Squashed 'third_party/allwpilib_2019/' changes from 99e4f7dd2..c36bbcc9a

936627bd9 wpilibc: Remove direct CameraServer dependency (#1989)
8e333c0aa Use FPGA Time instead of wall clock time for odometry (#1996)
d4430b765 Gearsbot example: Use standard argument order (#1995)
75438ab2c Add RamseteCommand (#1951)
989df1b46 Bump Native Utils and OpenCV dependencies (#1993)
dbc33b61e Fix Timer usage in TrapezoidProfileCommand (#1992)
79f8c5644 Add TrapezoidProfileCommand (#1962)
9440edf2b Refactor TrajectoryGenerator (#1972)
73a30182c Add frc2::Timer (#1968)
36ea865ed Add toString for geometry and trajectory classes (#1991)
cbe05e7e8 Update ProfiledPIDController API (#1967)
d04eb3546 Deprecate old PID classes (#1964)
02264db69 Add JNI dependencies to myRobotCpp (#1980)
2a76c996e Use VID/PID detection for PS3Eye (#1977)
a3820bbdf Remove HAL_BaseInitialize (#1981)
a83fb4793 Update to 2020v5 image (#1983)
4b0ed910e Make SwerveDriveKinematics.toChassisSpeeds() public (#1976)
103c1b121 Remove DS caching from the HAL level (#1971)
6635ea75e Fix NPE in SendableRegistry.foreachLiveWindow() (#1974)
cfe23c5cd Fix grammar error in comment for configureButtonBindings (#1969)
4bde2654e Fix mac azure build (#1973)
4f034e6c1 generateTrajectory: default reversed param to false (#1953)
acf960f72 Sim GUI: Add option to disable outputs on DS disable
2d3dac99f Sim GUI: Handle low resolutions and scale default window positions
07c86e0cd Sim GUI: Support High DPI monitors
46ad95512 SimDeviceData: Add missing null check
5bce489b9 Add ProggyDotted font to imgui (both cmake and gradle)
55af553ac Simulation GUI: Map gamepad the same way as DS
c59f9cea5 CameraServer: Add VID/PID support for Linux USB devices (#1960)
3fc89c84d Make splinePointsFromSplines public (#1963)
2c5093797 Fix implicitly deleted move constructors (#1954)
f3ad927f4 Update Java SmartDashboard and LiveWindow to match C++
05c25deb7 Fix move handling of C++ Sendable in SmartDashboard and LiveWindow
d726591ce Fix Gazebo sim plugin build (#1959)
2ff694fa4 Unbreak gradle build when other compilers installed (#1958)
53816155b Improve command decorator names (#1945)
a38f183a9 Fix GenResources.cmake so it's usable in a submodule (#1956)
b3398dca3 Set gradlebase correctly for all examples (#1950)
2c311013d Add Aarch64Bionic platform detection (#1922)
c10f2003c Add generateTrajectory overload (#1944)
63cfa64fb Add getters for pose in odometry classes (#1943)
2402c2bad Fix C++ command group recursive constructor bug (#1941)
f4eedf597 Fix ConcurrentModificationException in CommandScheduler (#1938)
bb0b207d2 Fix array out of bounds exception caused by parallel race group (#1935)
7bd69e591 Fix typo in temperature (#1940)
ec9738245 Bump to 2020 v4 image (#1931)
46303a822 Add messaging to extension loading in the HAL (#1926)
d169d6be9 Set extract_static for Doxygen config so that static members show up (#1930)
4e183eb10 Bump to 2020 v3 image (#1929)
84c185803 LiveWindow: catch errors in callback/builder functions (#1921)
0e3b0f3da Remove deprecated free() calls (#1925)
7f839b87c Remove timeouts from azure builds (#1924)
45b766a5d Fix main thread ID being potentially incorrect for simulation (#1923)
56d782b16 Add secondary camera name for PS3Eye (#1920)
2b4894038 Add simulation GUI plugin
f97d16073 Add imgui build to cmake
55a844a3e HAL sim: Add encoder channel B access
10deba854 Remove sendables from SendableRegistry when close() is called (#1917)
a9f0e4668 Implement sim devices for ADXL345, ADXL362, ADXRS450, Ultrasonic
aa9064586 Add ability to associate other devices with a SimDevice
81c2c8a7d Add simulation generic device/value support
e8d6f8a2c Move mockdata/HAL_Value.h to hal/Value.h
1b266717a Add simulation module support to cmake build (#1906)
fb8f3bd06 Add testbench yaml file (#1915)
846d8def0 Update to 2020 v2 image (#1913)
d6ac6e512 Fix PortForwarder package declaration (#1912)
227157086 Fix PS3Eye exposure setting (#1911)
885744d7e Add myRobot C++ version to cmake build (#1907)
366091fa8 Document that ConditionalCommand requires all subsystems (#1909)
c58b072c8 Fix Drive usage reporting order (#1908)
762c88adb Update compiler versions in readme (#1905)
af8ce568d Add Ramsete unicycle controller (#1790)
b2c2934d0 Fix javadoc warnings about invalid usage of ">" (#1904)
cce26ec78 Replace CRLF line endings with LF (#1902)
cb54602d4 Add support for writing RTR CAN Frames to the CAN API (#1900)
9f740e590 Use OS for serial port instead of NI VISA (#1875)
b23baf611 Add ability to run robot main loop in a separate thread (#1895)
457f94ba2 Add trajectory generation using hermite splines (#1843)
fd612052f Update native utils to use new frchome directory (#1884)
8858ec55c Remove periodic can read call (#1868)
41efb8015 Update CANAPITypes.h (#1860)
c93be1b2d Remove LabVIEW HAL support (#1901)
680f8919e Remove eigen, units and libuv from doxygen generation (#1898)
c5812524f Bump GradleJNI plugin version (#1899)
971303da8 Add PortForwarder class (#1890)
50db77bf2 Fix wpiutil cmake eigen install source directory (#1891)
85d42c199 C++ PIDCommand: Add GetMeasurement() and UseOutput() (#1892)
2dfbb855d wpilibj: Fix SwerveDriveKinematics ctor parameter name (#1889)
471f375a3 Simplify Sendable interface (#1864)
1d8c4d016 Replace ::value and ::type with _v and _t suffixes (#1885)
a5650b943 Add Units Utility class for Java (#1829)
904479ad4 Deprecate GearTooth class for removal (#1878)
86b666bba Add equality comparator to geometry classes (#1882)
62f07c182 Make one-arg Rotation2d constructor implicit (#1883)
f405582f8 Add kinematics suite (#1787)
561cbbd14 Deprecate Filter class for removal (#1876)
84e2973aa Remove unused include from Filesystem.h (#1877)
f49859ebf Remove NI VISA headers, as they are now included in NI Libraries (#1879)
bc59db5e6 Rename DEBUG macro to DEBUG0 (#1871)
dd928b4cb Remove JNI logging (#1872)
3e0f7d099 Use units for new NotifierCommand (#1869)
5ffe15d5f Remove ability to build all combined artifacts (#1867)
516cbef2c  Remove RoboRIO ifdef from simulation headers (#1859)
9b6ffc201 Replace SetOutputRange() with SetIntegratorRange()
ff8b8f0a8 Remove percent tolerance from PID controller
0ca8d667d Clean up AutoCloseable and other Java warnings (#1866)
7112add67 Watchdog: use units::second_t instead of double (#1863)
761bc3ef8 Change C++ WaitCommand to use units (#1865)
1fb301123 Add MathUtils.clamp() for Java (#1861)
eb3e0c9c9 Fix cmake Eigen include directory (#1862)
2250b7fbe Rename GearsBotNew example to GearsBot
c9f9feff1 Replace deprecated API usage in C++ examples
d6b9c7e14 CONTRIBUTING.md: Point to frc-docs instead of screensteps (#1858)
d10a1a797 Fix eigen build in vcpkg (#1856)
2bdb44325 Add frc2 includes to list of "other lib" regexes (#1855)
4b2b21d24 Replace outdated Java collections (#508)
8993ce5bf Move Eigen headers out of main include folder (#1854)
0f532a117 Add PWMSparkMax (#1751)
f7ad363d8 Add jni cross compile options for aarch64 (#1853)
9afea3340 Add support for aarch64 jetson bionic builds (#1844)
d787b5d60 Add more items to .gitignore (#1850)
5dd0d1b7d Use units in SPI
07ac711b3 Fix units deprecated warning in IterativeRobot
decfd858b Correctly report -1 for POV on disconnected joystick (#1852)
076ed7770 Add new C++ Command framework (#1785)
a0be07c37 Refactor HAL handle move construction/assignment (#1845)
558c38308 Add new Java Command framework (#1682)
1379735af Delete RobotState and SensorUtil constructors (#1847)
e3d86fee4 Move circular buffer class from wpilib to wpiutil (#1840)
4cd8a5667 TimedRobot.cpp: Fix deprecation warning (#1846)
b2861f894 Use 2020 artifacts and artifactory server (#1838)
98cc32703 Update to use artifactory to publish artifacts (#1833)
fa0640300 Move drive integration tests into wpilibj/src/test (#1836)
e716c36b8 Fix Nat.java generation to be incremental (#1831)
9fd2b5e3f Fix MSVC builds on cmake windows in vcpkg (#1835)
7e95010a2 Add compile-time EJML matrix wrapper to wpiutil (#1804)
3ebc5a6d3 Add ProfiledPIDController
fc98a79db Clean up PIDController interface in preparation for ProfiledPIDController
fdc098267 Fix compilation error in elevator trapezoid profile example (#1826)
a3dd84e85 Make XBoxController Button enum public (#1823)
a216b9e9e Add TrapezoidProfile example (#1814)
8f386f6bb wpilibc: Add unit-safety to C++ geometry classes (#1811)
c07ac2353 wpilibc: Add overloads for units (#1815)
f1d71da8a Move GetStackTrace and Demangle to wpiutil, add Windows support (#1819)
ef037457e Make LinearFilter copyable and moveable (#1789)
76930250c Remove objective-cpp support (#1816)
1c246418f Move TrapezoidProfileTest to trajectory folder (#1812)
95a54a0f2 Add java arcade drive example (#1810)
a4530243e HAL sim: Fix incorrectly setting dio port to initialized on cleanup (#1813)
09d00a622 Update Java examples to use new PIDController (#1809)
ba9b51742 Add missing Java examples (#841)
6411bd79c InterruptableSensorBase: Fix callback function deletion (#1807)
810e58ea8 I2C: Add tip about writeBulk() to transaction() (#1806)
607d6c148 Fix wpilibj integration tests jar name (#1808)
c9873e81b Remove PIDControllerRunner and mutex from new PIDController (#1795)
98d0706de Fix cscore build with OpenCV 4 (#1803)
fbe67c90c Make Sendable setters synchronous (#1799)
c67a488a0 Format SendableBuilderImpl javadocs (#1802)
8e93ce892 Fix PIDControllerRunner member destruction order (#1801)
c98ca7310 Add EJML dependency to wpiutil (#1769)
3b12276bc SendableBase: remove unnecessary synchronization (#1797)
e6d348f38 Fix missing default name in Java PIDController (#1792)
df12fc2a8 Java cleanups (#1776)
39561751f Update GradleVSCode version (#1786)
37d316aa0 Add C++20 std::math constants shim (#1788)
dd4310959 Deprecate frc/WPILib.h (#1779)
823174f30 Update native utils to 2020.0.4 (#1783)
37c695266 Squelch -Wdeprecated-copy for Eigen with GCC >= 9
04c9b000f Revert "Fix build of Eigen 3.3.7 with GCC 9"
ca3e71e21 wpiutil: Fix Process::Spawn() (#1778)
d946d5a2b Fix Eigen compilation errors and add tests (#1777)
8b1b9ac75 Fix build of Eigen 3.3.7 with GCC 9
2f680ba99 Add Eigen linear algebra library
a885db7d4 Make MotorEncoderTest use LinearFilter (#1775)
ee2410169 Add geometry classes (#1766)
48fe54271 Add HALSIM_SetSendError implementation (#1773)
dff58c87f Fix unused warning in release build (#1771)
dde61aad3 Remove TimerEventHandler typedef from Notifier class (#1767)
0f6ef80ab Add RobotState#IsEStopped and DriverStation#IsEStopped (#952)
e48886187 Move unit tests from integration test suite (#1170)
dffa1a5cb Make null checks more descriptive (#1688)
fe59d854d Notifier: add null check (#1684)
10731f3d6 Update uv Udp wrapper for latest features
89f7b72b6 Update libuv to 1.30.1 release
85f2f8740 wpiutil: Add unique_function (#1761)
73ec94078 Remove SampleRobot (#1658)
62be0392b Replace std::lock_guard and std::lock with std::scoped_lock (#1758)
24d31df55 Make sure move constructor is generated for TrapezoidProfile (#1757)
841ef5d73 Remove template types from lock RAII wrapper usages (#1756)
e582518ba Fix some move constructors (#1754)
8757bc471 Remove pre-C++17 shims (#1752)
ea9512977 Add replacement PIDController class (#1300)
9b798d228 Add TrapezoidProfile class (#1673)
804926fb5 Unconditionally skip athena builds for sim (#1748)
118e9d29d Add C++14 units library (#1749)
c705953d7 Add usage reporting to LinearFilter (#1750)
852d1b9ca Don't cross-build gazebo for raspbian (#1747)
eedb3a1ad Fix GCC 9 warnings (#1730)
60dce66a4 Remove wpi::ArrayRef std::initializer_list constructor (#1745)
9e19b29c3 Use base azure image for primary wpilib build (#1744)
299425071 Update jni library, fix cross builds of the jni symbol check (#1742)
a6b0e9b85 Only disable execution of cross compile google tests (#1741)
3c2093119 Use docker container to run wpiformat (#1740)
5fe2eebce Revert "Don't build halsim_gazebo on raspbian (#1737)" (#1743)
4b1b92bb7 Replace wpi::optional with C++17 std::optional (#1732)
0fbb0d989 Update to 2020 compilers (#1733)
2dc94e605 Disable google tests on cross compilers (#1738)
d9cb57a42 Don't build halsim_gazebo on raspbian (#1737)
f7cfdd7ce Replace crlf line endings with lf (#1731)
b6d5d90d9 Add JaCoCo Support (#1734)
c7ab2baa6 Add way to disable the jni check tasks from a property (#1736)
0c45c5b7e Fix skip athena and skip raspbian flags (#1735)
3dfb01d45 Update to new Native Utils (#1696)
30e936837 Clean up LinearDigitalFilter class (#782)
311e2de4c Remove deprecated Joystick constants (#1715)
c08fd6682 Update CAN manufacturer list (#1706)
258bba0c2 ErrorBase and WPIError improvements (#1727)
372ca4f45 cmake: Enable googletest unit tests (#1720)
223d47af0 HALSIM: support mocking of HAL_SendError() (#1728)
55cb683db Change compiler flags to C++17 (#1723)
ee8a33c56 wpiutil: SafeThread: Add thread id, support getting shared_ptr (#1722)
61426d08d wpiutil: Signal: make operator() const (#1721)
b630b63ef Remove functions in LiveWindow deprecated since 2018 (#1716)
1d0c05d4f Styleguide fixes for #1718 (#1719)
f07569df1 Fix newer GCC/clang compiler warnings (#1718)
0120f3124 C++ SPI: Fix SetClockRate to take int (#1717)
c2829ed98 Configure gradle to ignore unresolved headers (#1711)
221e66f46 Allow disabling static init of JNI libraries (#1672)
738852e11 cmake: Add cross toolchain files for Rio and Pi (#1710)
27b697b08 Remove frc directory include shims (#1714)
9e45373a7 Remove functions and classes deprecated for 2018 season (#1059)
eeb1025ac SPI: Report port as instance for usage reporting (#1704)
bc6f1e246 Windows compiler options improvements (#1709)
bb48ae391 cmake: Move example programs into folders (#1654)
221011494 Update for C++17 and fix MSVC warnings (#1694)
fb1239a2a Add raw sources and sinks to cscore (#1670)
7de947734 Add lambda overloads for interrupts (#1636)
90957aeea Move libuv to its own subfolder in build (#1661)
47aae502a Styleguide fixes (#1702)
0bff98b5e Correct DifferentialDrive::ArcadeDrive param docs (#1698)
b52e40b80 Allow widgets to be added by passing value suppliers (#1690)
4a00cd77b Add usage reporting for the Shuffleboard API (#1685)
e25e515f2  Publish artifacts on azure (#1678)
322ef9b96 Force Java 11, fix javadoc generation (#1695)
d42ef5df0 Fix Watchdog print formatting (#1693)
f432f65be Update copyright year in license to 2019 (#1524)
1726b77ac wpiutil: uv: Remove copy from SimpleBufferPool (#1680)
620bec9ca wpiutil: uv: Add LoopClosing status to Handle (#1647)
7cd6e2e7f UsbCamera: Solve race in windows initialization (#1638)
7732836bd Completely disable watchdog tests on mac (#1679)
698edfda9 Remove framework load, disable mac timeout test (#1676)
1c454b000 Add Shuffleboard calls to IterativeRobotBase in C++ (#1607)
f42905b32 Include missing headers in HAL.h (#1660)
bdc822fad Only generate passthrough URLs for RoboRIO (#1624)
d3affb16b Make failure of HAL_GetFPGATime() more descriptive (#1633)
2de3bf7f5 Update LLVM from stable upstream (#1653)
3cf4f38f5 Fix build on macos10.14.4 (#1648)
4e0c10f48 Fix CAN Clean using wrong ID (#1668)
3b0631324 Fix Gray to BGR conversion in CameraServer (#1665)
6cd1c73ef Fix GUID comparison creating weird symbol (#1659)
063bbab6f MavenArtifacts.md: update links to HTTPS (#1674)
aab4c494d Fix type in build.gradle (#1604)
bf46af260 Disable extraneous data warnings in libjpeg (#1630)
655763a9a Limit length of message sent to DS SendError call (#1618)
a095ec2d8 Fix linker errors with free functions in Threads.h (#1625)
12ab035aa Fix receive side of LabVIEW USB streams (#1621)

Change-Id: Ibd382e1a48925c200850cf90a8121e35c0fcffe3
git-subtree-dir: third_party/allwpilib_2019
git-subtree-split: c36bbcc9a9095489fc078229db4fba3ecd0f9b78
diff --git a/hal/src/main/native/athena/AnalogInput.cpp b/hal/src/main/native/athena/AnalogInput.cpp
index b11280d..859524e 100644
--- a/hal/src/main/native/athena/AnalogInput.cpp
+++ b/hal/src/main/native/athena/AnalogInput.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -75,6 +75,9 @@
   return channel < kNumAnalogInputs && channel >= 0;
 }
 
+void HAL_SetAnalogInputSimDevice(HAL_AnalogInputHandle handle,
+                                 HAL_SimDeviceHandle device) {}
+
 void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status) {
   // TODO: This will change when variable size scan lists are implemented.
   // TODO: Need double comparison with epsilon.
@@ -149,7 +152,7 @@
   readSelect.Channel = port->channel;
   readSelect.Averaged = false;
 
-  std::lock_guard<wpi::mutex> lock(analogRegisterWindowMutex);
+  std::scoped_lock lock(analogRegisterWindowMutex);
   analogInputSystem->writeReadSelect(readSelect, status);
   analogInputSystem->strobeLatchOutput(status);
   return static_cast<int16_t>(analogInputSystem->readOutput(status));
@@ -166,7 +169,7 @@
   readSelect.Channel = port->channel;
   readSelect.Averaged = true;
 
-  std::lock_guard<wpi::mutex> lock(analogRegisterWindowMutex);
+  std::scoped_lock lock(analogRegisterWindowMutex);
   analogInputSystem->writeReadSelect(readSelect, status);
   analogInputSystem->strobeLatchOutput(status);
   return static_cast<int32_t>(analogInputSystem->readOutput(status));
diff --git a/hal/src/main/native/athena/AnalogInternal.cpp b/hal/src/main/native/athena/AnalogInternal.cpp
index 6e02def..03a246d 100644
--- a/hal/src/main/native/athena/AnalogInternal.cpp
+++ b/hal/src/main/native/athena/AnalogInternal.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -44,7 +44,7 @@
 void initializeAnalog(int32_t* status) {
   hal::init::CheckInit();
   if (analogSystemInitialized) return;
-  std::lock_guard<wpi::mutex> lock(analogRegisterWindowMutex);
+  std::scoped_lock lock(analogRegisterWindowMutex);
   if (analogSystemInitialized) return;
   analogInputSystem.reset(tAI::create(status));
   analogOutputSystem.reset(tAO::create(status));
diff --git a/hal/src/main/native/athena/CANAPI.cpp b/hal/src/main/native/athena/CANAPI.cpp
index 01c06bd..44cdb58 100644
--- a/hal/src/main/native/athena/CANAPI.cpp
+++ b/hal/src/main/native/athena/CANAPI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -68,6 +68,8 @@
   return createdId;
 }
 
+extern "C" {
+
 HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
                                 int32_t deviceId, HAL_CANDeviceType deviceType,
                                 int32_t* status) {
@@ -91,12 +93,12 @@
 void HAL_CleanCAN(HAL_CANHandle handle) {
   auto data = canHandles->Free(handle);
 
-  std::lock_guard<wpi::mutex> lock(data->mapMutex);
+  std::scoped_lock lock(data->mapMutex);
 
   for (auto&& i : data->periodicSends) {
     int32_t s = 0;
-    HAL_CAN_SendMessage(i.first, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING,
-                        &s);
+    auto id = CreateCANId(data.get(), i.first);
+    HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING, &s);
     i.second = -1;
   }
 }
@@ -115,7 +117,7 @@
   if (*status != 0) {
     return;
   }
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   can->periodicSends[apiId] = -1;
 }
 
@@ -134,10 +136,31 @@
   if (*status != 0) {
     return;
   }
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   can->periodicSends[apiId] = repeatMs;
 }
 
+void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
+                          int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  auto id = CreateCANId(can.get(), apiId);
+  id |= HAL_CAN_IS_FRAME_REMOTE;
+  uint8_t data[8];
+  std::memset(data, 0, sizeof(data));
+
+  HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::scoped_lock lock(can->mapMutex);
+  can->periodicSends[apiId] = -1;
+}
+
 void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
                                 int32_t* status) {
   auto can = canHandles->Get(handle);
@@ -153,7 +176,7 @@
   if (*status != 0) {
     return;
   }
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   can->periodicSends[apiId] = -1;
 }
 
@@ -172,7 +195,7 @@
   HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
 
   if (*status == 0) {
-    std::lock_guard<wpi::mutex> lock(can->mapMutex);
+    std::scoped_lock lock(can->mapMutex);
     auto& msg = can->receives[messageId];
     msg.length = dataSize;
     msg.lastTimeStamp = ts;
@@ -197,7 +220,7 @@
   uint32_t ts = 0;
   HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
 
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   if (*status == 0) {
     // fresh update
     auto& msg = can->receives[messageId];
@@ -234,7 +257,7 @@
   uint32_t ts = 0;
   HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
 
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   if (*status == 0) {
     // fresh update
     auto& msg = can->receives[messageId];
@@ -262,65 +285,4 @@
     }
   }
 }
-
-void HAL_ReadCANPeriodicPacket(HAL_CANHandle handle, int32_t apiId,
-                               uint8_t* data, int32_t* length,
-                               uint64_t* receivedTimestamp, int32_t timeoutMs,
-                               int32_t periodMs, int32_t* status) {
-  auto can = canHandles->Get(handle);
-  if (!can) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  uint32_t messageId = CreateCANId(can.get(), apiId);
-
-  {
-    std::lock_guard<wpi::mutex> lock(can->mapMutex);
-    auto i = can->receives.find(messageId);
-    if (i != can->receives.end()) {
-      // Found, check if new enough
-      uint32_t now = GetPacketBaseTime();
-      if (now - i->second.lastTimeStamp < static_cast<uint32_t>(periodMs)) {
-        // Read the data from the stored message into the output
-        std::memcpy(data, i->second.data, i->second.length);
-        *length = i->second.length;
-        *receivedTimestamp = i->second.lastTimeStamp;
-        *status = 0;
-        return;
-      }
-    }
-  }
-
-  uint8_t dataSize = 0;
-  uint32_t ts = 0;
-  HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
-
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
-  if (*status == 0) {
-    // fresh update
-    auto& msg = can->receives[messageId];
-    msg.length = dataSize;
-    *length = dataSize;
-    msg.lastTimeStamp = ts;
-    *receivedTimestamp = ts;
-    // The NetComm call placed in data, copy into the msg
-    std::memcpy(msg.data, data, dataSize);
-  } else {
-    auto i = can->receives.find(messageId);
-    if (i != can->receives.end()) {
-      // Found, check if new enough
-      uint32_t now = GetPacketBaseTime();
-      if (now - i->second.lastTimeStamp > static_cast<uint32_t>(timeoutMs)) {
-        // Timeout, return bad status
-        *status = HAL_CAN_TIMEOUT;
-        return;
-      }
-      // Read the data from the stored message into the output
-      std::memcpy(data, i->second.data, i->second.length);
-      *length = i->second.length;
-      *receivedTimestamp = i->second.lastTimeStamp;
-      *status = 0;
-    }
-  }
-}
+}  // extern "C"
diff --git a/hal/src/main/native/athena/DIO.cpp b/hal/src/main/native/athena/DIO.cpp
index 96eab2b..dc4631e 100644
--- a/hal/src/main/native/athena/DIO.cpp
+++ b/hal/src/main/native/athena/DIO.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -69,7 +69,7 @@
 
   port->channel = static_cast<uint8_t>(channel);
 
-  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  std::scoped_lock lock(digitalDIOMutex);
 
   tDIO::tOutputEnable outputEnable = digitalSystem->readOutputEnable(status);
 
@@ -143,7 +143,7 @@
   }
 
   int32_t status = 0;
-  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  std::scoped_lock lock(digitalDIOMutex);
   if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
     // Unset the SPI flag
     int32_t bitToUnset = 1 << remapSPIChannel(port->channel);
@@ -160,6 +160,9 @@
   }
 }
 
+void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
+}
+
 HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
   auto handle = digitalPWMHandles->Allocate();
   if (handle == HAL_kInvalidHandle) {
@@ -205,7 +208,7 @@
   double rawDutyCycle = 256.0 * dutyCycle;
   if (rawDutyCycle > 255.5) rawDutyCycle = 255.5;
   {
-    std::lock_guard<wpi::mutex> lock(digitalPwmMutex);
+    std::scoped_lock lock(digitalPwmMutex);
     uint16_t pwmPeriodPower = digitalSystem->readPWMPeriodPower(status);
     if (pwmPeriodPower < 4) {
       // The resolution of the duty cycle drops close to the highest
@@ -251,7 +254,7 @@
     if (value != 0) value = 1;
   }
   {
-    std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+    std::scoped_lock lock(digitalDIOMutex);
     tDIO::tDO currentDIO = digitalSystem->readDO(status);
 
     if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
@@ -289,7 +292,7 @@
     return;
   }
   {
-    std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+    std::scoped_lock lock(digitalDIOMutex);
     tDIO::tOutputEnable currentDIO = digitalSystem->readOutputEnable(status);
 
     if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
@@ -382,8 +385,8 @@
   }
 
   digitalSystem->writePulseLength(
-      static_cast<uint8_t>(1.0e9 * pulseLength /
-                           (pwmSystem->readLoopTiming(status) * 25)),
+      static_cast<uint16_t>(1.0e9 * pulseLength /
+                            (pwmSystem->readLoopTiming(status) * 25)),
       status);
   digitalSystem->writePulse(pulse, status);
 }
@@ -421,7 +424,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  std::scoped_lock lock(digitalDIOMutex);
   if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
     // Channels 10-15 are SPI channels, so subtract our MXP channels
     digitalSystem->writeFilterSelectHdr(port->channel - kNumDigitalMXPChannels,
@@ -441,7 +444,7 @@
     return 0;
   }
 
-  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  std::scoped_lock lock(digitalDIOMutex);
   if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
     // Channels 10-15 are SPI channels, so subtract our MXP channels
     return digitalSystem->readFilterSelectHdr(
@@ -457,7 +460,7 @@
 void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
   initializeDigital(status);
   if (*status != 0) return;
-  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  std::scoped_lock lock(digitalDIOMutex);
   digitalSystem->writeFilterPeriodHdr(filterIndex, value, status);
   if (*status == 0) {
     digitalSystem->writeFilterPeriodMXP(filterIndex, value, status);
@@ -470,7 +473,7 @@
   uint32_t hdrPeriod = 0;
   uint32_t mxpPeriod = 0;
   {
-    std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+    std::scoped_lock lock(digitalDIOMutex);
     hdrPeriod = digitalSystem->readFilterPeriodHdr(filterIndex, status);
     if (*status == 0) {
       mxpPeriod = digitalSystem->readFilterPeriodMXP(filterIndex, status);
diff --git a/hal/src/main/native/athena/DigitalInternal.cpp b/hal/src/main/native/athena/DigitalInternal.cpp
index bdba75b..684d35a 100644
--- a/hal/src/main/native/athena/DigitalInternal.cpp
+++ b/hal/src/main/native/athena/DigitalInternal.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -74,7 +74,7 @@
   // Initial check, as if it's true initialization has finished
   if (initialized) return;
 
-  std::lock_guard<wpi::mutex> lock(initializeMutex);
+  std::scoped_lock lock(initializeMutex);
   // Second check in case another thread was waiting
   if (initialized) return;
 
diff --git a/hal/src/main/native/athena/Encoder.cpp b/hal/src/main/native/athena/Encoder.cpp
index adf70ed..bf3a273 100644
--- a/hal/src/main/native/athena/Encoder.cpp
+++ b/hal/src/main/native/athena/Encoder.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -261,6 +261,9 @@
   encoderHandles->Free(encoderHandle);
 }
 
+void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
+                             HAL_SimDeviceHandle device) {}
+
 int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
   auto encoder = encoderHandles->Get(encoderHandle);
   if (encoder == nullptr) {
diff --git a/hal/src/main/native/athena/FRCDriverStation.cpp b/hal/src/main/native/athena/FRCDriverStation.cpp
index 5409ad0..23c874f 100644
--- a/hal/src/main/native/athena/FRCDriverStation.cpp
+++ b/hal/src/main/native/athena/FRCDriverStation.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -30,64 +30,9 @@
 
 static constexpr int kJoystickPorts = 6;
 
-// Joystick User Data
-static std::unique_ptr<HAL_JoystickAxes[]> m_joystickAxes;
-static std::unique_ptr<HAL_JoystickPOVs[]> m_joystickPOVs;
-static std::unique_ptr<HAL_JoystickButtons[]> m_joystickButtons;
-static std::unique_ptr<HAL_JoystickDescriptor[]> m_joystickDescriptor;
-static std::unique_ptr<HAL_MatchInfo> m_matchInfo;
-
-// Joystick Cached Data
-static std::unique_ptr<HAL_JoystickAxes[]> m_joystickAxesCache;
-static std::unique_ptr<HAL_JoystickPOVs[]> m_joystickPOVsCache;
-static std::unique_ptr<HAL_JoystickButtons[]> m_joystickButtonsCache;
-static std::unique_ptr<HAL_JoystickDescriptor[]> m_joystickDescriptorCache;
-static std::unique_ptr<HAL_MatchInfo> m_matchInfoCache;
-
-static wpi::mutex m_cacheDataMutex;
-
-// Control word variables
-static HAL_ControlWord m_controlWordCache;
-static std::chrono::steady_clock::time_point m_lastControlWordUpdate;
-static wpi::mutex m_controlWordMutex;
-
 // Message and Data variables
 static wpi::mutex msgMutex;
 
-static void InitializeDriverStationCaches() {
-  m_joystickAxes = std::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
-  m_joystickPOVs = std::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
-  m_joystickButtons = std::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
-  m_joystickDescriptor =
-      std::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
-  m_matchInfo = std::make_unique<HAL_MatchInfo>();
-  m_joystickAxesCache = std::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
-  m_joystickPOVsCache = std::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
-  m_joystickButtonsCache =
-      std::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
-  m_joystickDescriptorCache =
-      std::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
-  m_matchInfoCache = std::make_unique<HAL_MatchInfo>();
-
-  // All joysticks should default to having zero axes, povs and buttons, so
-  // uninitialized memory doesn't get sent to speed controllers.
-  for (unsigned int i = 0; i < kJoystickPorts; i++) {
-    m_joystickAxes[i].count = 0;
-    m_joystickPOVs[i].count = 0;
-    m_joystickButtons[i].count = 0;
-    m_joystickDescriptor[i].isXbox = 0;
-    m_joystickDescriptor[i].type = -1;
-    m_joystickDescriptor[i].name[0] = '\0';
-
-    m_joystickAxesCache[i].count = 0;
-    m_joystickPOVsCache[i].count = 0;
-    m_joystickButtonsCache[i].count = 0;
-    m_joystickDescriptorCache[i].isXbox = 0;
-    m_joystickDescriptorCache[i].type = -1;
-    m_joystickDescriptorCache[i].name[0] = '\0';
-  }
-}
-
 static int32_t HAL_GetJoystickAxesInternal(int32_t joystickNum,
                                            HAL_JoystickAxes* axes) {
   HAL_JoystickAxesInt axesInt;
@@ -138,7 +83,7 @@
 static int32_t HAL_GetJoystickDescriptorInternal(int32_t joystickNum,
                                                  HAL_JoystickDescriptor* desc) {
   desc->isXbox = 0;
-  desc->type = std::numeric_limits<uint8_t>::max();
+  desc->type = (std::numeric_limits<uint8_t>::max)();
   desc->name[0] = '\0';
   desc->axisCount =
       HAL_kMaxJoystickAxes; /* set to the desc->axisTypes's capacity */
@@ -177,90 +122,18 @@
   return status;
 }
 
-static void UpdateDriverStationControlWord(bool force,
-                                           HAL_ControlWord& controlWord) {
-  auto now = std::chrono::steady_clock::now();
-  std::lock_guard<wpi::mutex> lock(m_controlWordMutex);
-  // Update every 50 ms or on force.
-  if ((now - m_lastControlWordUpdate > std::chrono::milliseconds(50)) ||
-      force) {
-    HAL_GetControlWordInternal(&m_controlWordCache);
-    m_lastControlWordUpdate = now;
-  }
-  controlWord = m_controlWordCache;
-}
-
-static void UpdateDriverStationDataCaches() {
-  // Get the status of all of the joysticks, and save to the cache
-  for (uint8_t stick = 0; stick < kJoystickPorts; stick++) {
-    HAL_GetJoystickAxesInternal(stick, &m_joystickAxesCache[stick]);
-    HAL_GetJoystickPOVsInternal(stick, &m_joystickPOVsCache[stick]);
-    HAL_GetJoystickButtonsInternal(stick, &m_joystickButtonsCache[stick]);
-    HAL_GetJoystickDescriptorInternal(stick, &m_joystickDescriptorCache[stick]);
-  }
-  // Grab match specific data
-  HAL_GetMatchInfoInternal(m_matchInfoCache.get());
-
-  // Force a control word update, to make sure the data is the newest.
-  HAL_ControlWord controlWord;
-  UpdateDriverStationControlWord(true, controlWord);
-
-  {
-    // Obtain a lock on the data, swap the cached data into the main data arrays
-    std::lock_guard<wpi::mutex> lock(m_cacheDataMutex);
-
-    m_joystickAxes.swap(m_joystickAxesCache);
-    m_joystickPOVs.swap(m_joystickPOVsCache);
-    m_joystickButtons.swap(m_joystickButtonsCache);
-    m_joystickDescriptor.swap(m_joystickDescriptorCache);
-    m_matchInfo.swap(m_matchInfoCache);
-  }
-}
-
-class DriverStationThread : public wpi::SafeThread {
- public:
-  void Main() {
-    std::unique_lock<wpi::mutex> lock(m_mutex);
-    while (m_active) {
-      m_cond.wait(lock, [&] { return !m_active || m_notify; });
-      if (!m_active) break;
-      m_notify = false;
-
-      lock.unlock();
-      UpdateDriverStationDataCaches();
-      lock.lock();
-
-      // Notify all threads
-      newDSDataAvailableCounter++;
-      newDSDataAvailableCond.notify_all();
-    }
-
-    // Notify waiters on thread exit
-    newDSDataAvailableCounter++;
-    newDSDataAvailableCond.notify_all();
-  }
-
-  bool m_notify = false;
-  wpi::condition_variable newDSDataAvailableCond;
-  int newDSDataAvailableCounter{0};
-};
-
-class DriverStationThreadOwner
-    : public wpi::SafeThreadOwner<DriverStationThread> {
- public:
-  void Notify() {
-    auto thr = GetThread();
-    if (!thr) return;
-    thr->m_notify = true;
-    thr->m_cond.notify_one();
-  }
-};
-
-static std::unique_ptr<DriverStationThreadOwner> dsThread = nullptr;
+static wpi::mutex* newDSDataAvailableMutex;
+static wpi::condition_variable* newDSDataAvailableCond;
+static int newDSDataAvailableCounter{0};
 
 namespace hal {
 namespace init {
-void InitializeFRCDriverStation() {}
+void InitializeFRCDriverStation() {
+  static wpi::mutex newMutex;
+  newDSDataAvailableMutex = &newMutex;
+  static wpi::condition_variable newCond;
+  newDSDataAvailableCond = &newCond;
+}
 }  // namespace init
 }  // namespace hal
 
@@ -272,7 +145,7 @@
   // Avoid flooding console by keeping track of previous 5 error
   // messages and only printing again if they're longer than 1 second old.
   static constexpr int KEEP_MSGS = 5;
-  std::lock_guard<wpi::mutex> lock(msgMutex);
+  std::scoped_lock lock(msgMutex);
   static std::string prevMsg[KEEP_MSGS];
   static std::chrono::time_point<std::chrono::steady_clock>
       prevMsgTime[KEEP_MSGS];
@@ -292,8 +165,43 @@
   }
   int retval = 0;
   if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
-    retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
-                                                details, location, callStack);
+    wpi::StringRef detailsRef{details};
+    wpi::StringRef locationRef{location};
+    wpi::StringRef callStackRef{callStack};
+
+    // 1 tag, 4 timestamp, 2 seqnum
+    // 2 numOccur, 4 error code, 1 flags, 6 strlen
+    // 1 extra needed for padding on Netcomm end.
+    size_t baseLength = 21;
+
+    if (baseLength + detailsRef.size() + locationRef.size() +
+            callStackRef.size() <=
+        65536) {
+      // Pass through
+      retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
+                                                  details, location, callStack);
+    } else if (baseLength + detailsRef.size() > 65536) {
+      // Details too long, cut both location and stack
+      auto newLen = 65536 - baseLength;
+      std::string newDetails{details, newLen};
+      char empty = '\0';
+      retval = FRC_NetworkCommunication_sendError(
+          isError, errorCode, isLVCode, newDetails.c_str(), &empty, &empty);
+    } else if (baseLength + detailsRef.size() + locationRef.size() > 65536) {
+      // Location too long, cut stack
+      auto newLen = 65536 - baseLength - detailsRef.size();
+      std::string newLocation{location, newLen};
+      char empty = '\0';
+      retval = FRC_NetworkCommunication_sendError(
+          isError, errorCode, isLVCode, details, newLocation.c_str(), &empty);
+    } else {
+      // Stack too long
+      auto newLen = 65536 - baseLength - detailsRef.size() - locationRef.size();
+      std::string newCallStack{callStack, newLen};
+      retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
+                                                  details, location,
+                                                  newCallStack.c_str());
+    }
     if (printMsg) {
       if (location && location[0] != '\0') {
         wpi::errs() << (isError ? "Error" : "Warning") << " at " << location
@@ -322,41 +230,29 @@
 }
 
 int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
-  std::memset(controlWord, 0, sizeof(HAL_ControlWord));
-  UpdateDriverStationControlWord(false, *controlWord);
-  return 0;
+  return HAL_GetControlWordInternal(controlWord);
 }
 
 int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
-  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
-  *axes = m_joystickAxes[joystickNum];
-  return 0;
+  return HAL_GetJoystickAxesInternal(joystickNum, axes);
 }
 
 int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
-  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
-  *povs = m_joystickPOVs[joystickNum];
-  return 0;
+  return HAL_GetJoystickPOVsInternal(joystickNum, povs);
 }
 
 int32_t HAL_GetJoystickButtons(int32_t joystickNum,
                                HAL_JoystickButtons* buttons) {
-  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
-  *buttons = m_joystickButtons[joystickNum];
-  return 0;
+  return HAL_GetJoystickButtonsInternal(joystickNum, buttons);
 }
 
 int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
                                   HAL_JoystickDescriptor* desc) {
-  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
-  *desc = m_joystickDescriptor[joystickNum];
-  return 0;
+  return HAL_GetJoystickDescriptorInternal(joystickNum, desc);
 }
 
 int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
-  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
-  *info = *m_matchInfo;
-  return 0;
+  return HAL_GetMatchInfoInternal(info);
 }
 
 HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
@@ -448,10 +344,8 @@
   // 20ms rate occurs once every 2.7 years of DS connected runtime, so not
   // worth the cycles to check.
   thread_local int lastCount{-1};
-  if (!dsThread) return false;
-  auto thr = dsThread->GetThread();
-  if (!thr) return false;
-  int currentCount = thr->newDSDataAvailableCounter;
+  std::lock_guard lock{*newDSDataAvailableMutex};
+  int currentCount = newDSDataAvailableCounter;
   if (lastCount == currentCount) return false;
   lastCount = currentCount;
   return true;
@@ -471,19 +365,16 @@
   auto timeoutTime =
       std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
 
-  if (!dsThread) return false;
-  auto thr = dsThread->GetThread();
-  if (!thr) return false;
-  int currentCount = thr->newDSDataAvailableCounter;
-  while (thr->newDSDataAvailableCounter == currentCount) {
+  std::unique_lock lock{*newDSDataAvailableMutex};
+  int currentCount = newDSDataAvailableCounter;
+  while (newDSDataAvailableCounter == currentCount) {
     if (timeout > 0) {
-      auto timedOut =
-          thr->newDSDataAvailableCond.wait_until(thr.GetLock(), timeoutTime);
+      auto timedOut = newDSDataAvailableCond->wait_until(lock, timeoutTime);
       if (timedOut == std::cv_status::timeout) {
         return false;
       }
     } else {
-      thr->newDSDataAvailableCond.wait(thr.GetLock());
+      newDSDataAvailableCond->wait(lock);
     }
   }
   return true;
@@ -496,7 +387,9 @@
   // Since we could get other values, require our specific handle
   // to signal our threads
   if (refNum != refNumber) return;
-  dsThread->Notify();
+  // Notify all threads
+  newDSDataAvailableCounter++;
+  newDSDataAvailableCond->notify_all();
 }
 
 /*
@@ -510,15 +403,10 @@
   // Initial check, as if it's true initialization has finished
   if (initialized) return;
 
-  std::lock_guard<wpi::mutex> lock(initializeMutex);
+  std::scoped_lock lock(initializeMutex);
   // Second check in case another thread was waiting
   if (initialized) return;
 
-  InitializeDriverStationCaches();
-
-  dsThread = std::make_unique<DriverStationThreadOwner>();
-  dsThread->Start();
-
   // Set up the occur function internally with NetComm
   NetCommRPCProxy_SetOccurFuncPointer(newDataOccur);
   // Set up our occur reference number
diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp
index dbdb826..a9abde6 100644
--- a/hal/src/main/native/athena/HAL.cpp
+++ b/hal/src/main/native/athena/HAL.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -61,6 +61,7 @@
   InitializeFRCDriverStation();
   InitializeI2C();
   InitialzeInterrupts();
+  InitializeMain();
   InitializeNotifier();
   InitializePCMInternal();
   InitializePDP();
@@ -276,24 +277,6 @@
   return !(watchdog->readStatus_PowerAlive(status));
 }
 
-void HAL_BaseInitialize(int32_t* status) {
-  static std::atomic_bool initialized{false};
-  static wpi::mutex initializeMutex;
-  // Initial check, as if it's true initialization has finished
-  if (initialized) return;
-
-  std::lock_guard<wpi::mutex> lock(initializeMutex);
-  // Second check in case another thread was waiting
-  if (initialized) return;
-  // image 4; Fixes errors caused by multiple processes. Talk to NI about this
-  nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
-      nLoadOut::kTargetClass_RoboRIO;
-
-  global.reset(tGlobal::create(status));
-  watchdog.reset(tSysWatchdog::create(status));
-  initialized = true;
-}
-
 static bool killExistingProgram(int timeout, int mode) {
   // Kill any previous robot programs
   std::fstream fs;
@@ -341,7 +324,7 @@
   // Initial check, as if it's true initialization has finished
   if (initialized) return true;
 
-  std::lock_guard<wpi::mutex> lock(initializeMutex);
+  std::scoped_lock lock(initializeMutex);
   // Second check in case another thread was waiting
   if (initialized) return true;
 
@@ -367,8 +350,14 @@
     setNewDataSem(nullptr);
   });
 
+  // image 4; Fixes errors caused by multiple processes. Talk to NI about this
+  nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
+      nLoadOut::kTargetClass_RoboRIO;
+
   int32_t status = 0;
-  HAL_BaseInitialize(&status);
+  global.reset(tGlobal::create(&status));
+  watchdog.reset(tSysWatchdog::create(&status));
+
   if (status != 0) return false;
 
   HAL_InitializeDriverStation();
@@ -379,8 +368,9 @@
     uint64_t rv = HAL_GetFPGATime(&status);
     if (status != 0) {
       wpi::errs()
-          << "Call to HAL_GetFPGATime failed."
-          << "Initialization might have failed. Time will not be correct\n";
+          << "Call to HAL_GetFPGATime failed in wpi::Now() with status "
+          << status
+          << ". Initialization might have failed. Time will not be correct\n";
       wpi::errs().flush();
       return 0u;
     }
diff --git a/hal/src/main/native/athena/HALInitializer.h b/hal/src/main/native/athena/HALInitializer.h
index 384fe58..fc38038 100644
--- a/hal/src/main/native/athena/HALInitializer.h
+++ b/hal/src/main/native/athena/HALInitializer.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -38,6 +38,7 @@
 extern void InitializeHAL();
 extern void InitializeI2C();
 extern void InitialzeInterrupts();
+extern void InitializeMain();
 extern void InitializeNotifier();
 extern void InitializePCMInternal();
 extern void InitializePDP();
diff --git a/hal/src/main/native/athena/I2C.cpp b/hal/src/main/native/athena/I2C.cpp
index 907906e..b72e25e 100644
--- a/hal/src/main/native/athena/I2C.cpp
+++ b/hal/src/main/native/athena/I2C.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -52,7 +52,7 @@
   }
 
   if (port == HAL_I2C_kOnboard) {
-    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    std::scoped_lock lock(digitalI2COnBoardMutex);
     i2COnboardObjCount++;
     if (i2COnboardObjCount > 1) return;
     int handle = open("/dev/i2c-2", O_RDWR);
@@ -62,7 +62,7 @@
     }
     i2COnBoardHandle = handle;
   } else {
-    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    std::scoped_lock lock(digitalI2CMXPMutex);
     i2CMXPObjCount++;
     if (i2CMXPObjCount > 1) return;
     if ((i2CMXPDigitalHandle1 = HAL_InitializeDIOPort(
@@ -108,10 +108,10 @@
   rdwr.nmsgs = 2;
 
   if (port == HAL_I2C_kOnboard) {
-    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    std::scoped_lock lock(digitalI2COnBoardMutex);
     return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr);
   } else {
-    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    std::scoped_lock lock(digitalI2CMXPMutex);
     return ioctl(i2CMXPHandle, I2C_RDWR, &rdwr);
   }
 }
@@ -134,10 +134,10 @@
   rdwr.nmsgs = 1;
 
   if (port == HAL_I2C_kOnboard) {
-    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    std::scoped_lock lock(digitalI2COnBoardMutex);
     return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr);
   } else {
-    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    std::scoped_lock lock(digitalI2CMXPMutex);
     return ioctl(i2CMXPHandle, I2C_RDWR, &rdwr);
   }
 }
@@ -160,10 +160,10 @@
   rdwr.nmsgs = 1;
 
   if (port == HAL_I2C_kOnboard) {
-    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    std::scoped_lock lock(digitalI2COnBoardMutex);
     return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr);
   } else {
-    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    std::scoped_lock lock(digitalI2CMXPMutex);
     return ioctl(i2CMXPHandle, I2C_RDWR, &rdwr);
   }
 }
@@ -175,12 +175,12 @@
   }
 
   if (port == HAL_I2C_kOnboard) {
-    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    std::scoped_lock lock(digitalI2COnBoardMutex);
     if (i2COnboardObjCount-- == 0) {
       close(i2COnBoardHandle);
     }
   } else {
-    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    std::scoped_lock lock(digitalI2CMXPMutex);
     if (i2CMXPObjCount-- == 0) {
       close(i2CMXPHandle);
     }
diff --git a/hal/src/main/native/athena/Interrupts.cpp b/hal/src/main/native/athena/Interrupts.cpp
index c661da4..b0b2071 100644
--- a/hal/src/main/native/athena/Interrupts.cpp
+++ b/hal/src/main/native/athena/Interrupts.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -26,7 +26,7 @@
 class InterruptThread : public wpi::SafeThread {
  public:
   void Main() {
-    std::unique_lock<wpi::mutex> lock(m_mutex);
+    std::unique_lock lock(m_mutex);
     while (m_active) {
       m_cond.wait(lock, [&] { return !m_active || m_notify; });
       if (!m_active) break;
@@ -118,7 +118,7 @@
   if (anInterrupt == nullptr) {
     return nullptr;
   }
-  anInterrupt->manager->enable(status);
+  anInterrupt->manager->disable(status);
   void* param = anInterrupt->param;
   return param;
 }
diff --git a/hal/src/main/native/athena/Notifier.cpp b/hal/src/main/native/athena/Notifier.cpp
index c457cd1..662b04e 100644
--- a/hal/src/main/native/athena/Notifier.cpp
+++ b/hal/src/main/native/athena/Notifier.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -53,7 +53,7 @@
   ~NotifierHandleContainer() {
     ForEach([](HAL_NotifierHandle handle, Notifier* notifier) {
       {
-        std::lock_guard<wpi::mutex> lock(notifier->mutex);
+        std::scoped_lock lock(notifier->mutex);
         notifier->triggerTime = UINT64_MAX;
         notifier->triggeredTime = 0;
         notifier->active = false;
@@ -66,7 +66,7 @@
 static NotifierHandleContainer* notifierHandles;
 
 static void alarmCallback(uint32_t, void*) {
-  std::lock_guard<wpi::mutex> lock(notifierMutex);
+  std::scoped_lock lock(notifierMutex);
   int32_t status = 0;
   uint64_t currentTime = 0;
 
@@ -77,7 +77,7 @@
   notifierHandles->ForEach([&](HAL_NotifierHandle handle, Notifier* notifier) {
     if (notifier->triggerTime == UINT64_MAX) return;
     if (currentTime == 0) currentTime = HAL_GetFPGATime(&status);
-    std::unique_lock<wpi::mutex> lock(notifier->mutex);
+    std::unique_lock lock(notifier->mutex);
     if (notifier->triggerTime < currentTime) {
       notifier->triggerTime = UINT64_MAX;
       notifier->triggeredTime = currentTime;
@@ -119,7 +119,7 @@
     std::atexit(cleanupNotifierAtExit);
 
   if (notifierRefCount.fetch_add(1) == 0) {
-    std::lock_guard<wpi::mutex> lock(notifierMutex);
+    std::scoped_lock lock(notifierMutex);
     // create manager and alarm if not already created
     if (!notifierManager) {
       notifierManager = std::make_unique<tInterruptManager>(
@@ -144,7 +144,7 @@
   if (!notifier) return;
 
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->triggerTime = UINT64_MAX;
     notifier->triggeredTime = 0;
     notifier->active = false;
@@ -158,7 +158,7 @@
 
   // Just in case HAL_StopNotifier() wasn't called...
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->triggerTime = UINT64_MAX;
     notifier->triggeredTime = 0;
     notifier->active = false;
@@ -177,7 +177,7 @@
     // if (notifierAlarm) notifierAlarm->writeEnable(false, status);
     // if (notifierManager) notifierManager->disable(status);
 
-    // std::lock_guard<wpi::mutex> lock(notifierMutex);
+    // std::scoped_lock lock(notifierMutex);
     // notifierAlarm = nullptr;
     // notifierManager = nullptr;
     // closestTrigger = UINT64_MAX;
@@ -190,12 +190,12 @@
   if (!notifier) return;
 
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->triggerTime = triggerTime;
     notifier->triggeredTime = UINT64_MAX;
   }
 
-  std::lock_guard<wpi::mutex> lock(notifierMutex);
+  std::scoped_lock lock(notifierMutex);
   // Update alarm time if closer than current.
   if (triggerTime < closestTrigger) {
     bool wasActive = (closestTrigger != UINT64_MAX);
@@ -214,7 +214,7 @@
   if (!notifier) return;
 
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->triggerTime = UINT64_MAX;
   }
 }
@@ -223,7 +223,7 @@
                                   int32_t* status) {
   auto notifier = notifierHandles->Get(notifierHandle);
   if (!notifier) return 0;
-  std::unique_lock<wpi::mutex> lock(notifier->mutex);
+  std::unique_lock lock(notifier->mutex);
   notifier->cond.wait(lock, [&] {
     return !notifier->active || notifier->triggeredTime != UINT64_MAX;
   });
diff --git a/hal/src/main/native/athena/PDP.cpp b/hal/src/main/native/athena/PDP.cpp
index 22ea8c1..f27f5da 100644
--- a/hal/src/main/native/athena/PDP.cpp
+++ b/hal/src/main/native/athena/PDP.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -34,7 +34,6 @@
 static constexpr int32_t Control1 = 0x70;
 
 static constexpr int32_t TimeoutMs = 100;
-static constexpr int32_t StatusPeriodMs = 25;
 
 /* encoder/decoders */
 union PdpStatus1 {
@@ -130,7 +129,7 @@
     return HAL_kInvalidHandle;
   }
 
-  std::lock_guard<wpi::mutex> lock(pdpHandleMutex);
+  std::scoped_lock lock(pdpHandleMutex);
 
   if (pdpHandles[module] != HAL_kInvalidHandle) {
     *status = 0;
@@ -173,9 +172,8 @@
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
-                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                            status);
+  HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
+                           &receivedTimestamp, TimeoutMs, status);
 
   return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
 }
@@ -185,9 +183,8 @@
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
-                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                            status);
+  HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
+                           &receivedTimestamp, TimeoutMs, status);
 
   return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
 }
@@ -206,9 +203,8 @@
 
   if (channel <= 5) {
     PdpStatus1 pdpStatus;
-    HAL_ReadCANPeriodicPacket(handle, Status1, pdpStatus.data, &length,
-                              &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                              status);
+    HAL_ReadCANPacketTimeout(handle, Status1, pdpStatus.data, &length,
+                             &receivedTimestamp, TimeoutMs, status);
     switch (channel) {
       case 0:
         raw = (static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
@@ -237,9 +233,8 @@
     }
   } else if (channel <= 11) {
     PdpStatus2 pdpStatus;
-    HAL_ReadCANPeriodicPacket(handle, Status2, pdpStatus.data, &length,
-                              &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                              status);
+    HAL_ReadCANPacketTimeout(handle, Status2, pdpStatus.data, &length,
+                             &receivedTimestamp, TimeoutMs, status);
     switch (channel) {
       case 6:
         raw = (static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
@@ -268,9 +263,8 @@
     }
   } else {
     PdpStatus3 pdpStatus;
-    HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
-                              &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                              status);
+    HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
+                             &receivedTimestamp, TimeoutMs, status);
     switch (channel) {
       case 12:
         raw = (static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |
@@ -300,9 +294,8 @@
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
-                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                            status);
+  HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
+                           &receivedTimestamp, TimeoutMs, status);
 
   uint32_t raw;
   raw = pdpStatus.bits.TotalCurrent_125mAperunit_h8;
@@ -316,9 +309,8 @@
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
-                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                            status);
+  HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
+                           &receivedTimestamp, TimeoutMs, status);
 
   uint32_t raw;
   raw = pdpStatus.bits.Power_125mWperunit_h4;
@@ -334,9 +326,8 @@
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
-                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
-                            status);
+  HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
+                           &receivedTimestamp, TimeoutMs, status);
 
   uint32_t raw;
   raw = pdpStatus.bits.Energy_125mWPerUnitXTmeas_h4;
diff --git a/hal/src/main/native/athena/PWM.cpp b/hal/src/main/native/athena/PWM.cpp
index 06b527c..a3b141c 100644
--- a/hal/src/main/native/athena/PWM.cpp
+++ b/hal/src/main/native/athena/PWM.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -266,11 +266,9 @@
 
   DigitalPort* dPort = port.get();
 
-  if (speed < -1.0) {
-    speed = -1.0;
-  } else if (speed > 1.0) {
-    speed = 1.0;
-  } else if (!std::isfinite(speed)) {
+  if (std::isfinite(speed)) {
+    speed = std::clamp(speed, -1.0, 1.0);
+  } else {
     speed = 0.0;
   }
 
diff --git a/hal/src/main/native/athena/Relay.cpp b/hal/src/main/native/athena/Relay.cpp
index 9f7d6c0..71880a8 100644
--- a/hal/src/main/native/athena/Relay.cpp
+++ b/hal/src/main/native/athena/Relay.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -100,7 +100,7 @@
     *status = HAL_HANDLE_ERROR;
     return;
   }
-  std::lock_guard<wpi::mutex> lock(digitalRelayMutex);
+  std::scoped_lock lock(digitalRelayMutex);
   uint8_t relays = 0;
   if (port->fwd) {
     relays = relaySystem->readValue_Forward(status);
diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp
index ddced41..bb0666a 100644
--- a/hal/src/main/native/athena/SPI.cpp
+++ b/hal/src/main/native/athena/SPI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -55,7 +55,7 @@
   // There are two SPI devices: one for ports 0-3 (onboard), the other for port
   // 4 (MXP).
   if (!spiAutoRunning) return false;
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   return (spiAutoPort >= 0 && spiAutoPort <= 3 && port >= 0 && port <= 3) ||
          (spiAutoPort == 4 && port == 4);
 }
@@ -253,7 +253,7 @@
   xfer.rx_buf = (__u64)dataReceived;
   xfer.len = size;
 
-  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  std::scoped_lock lock(spiApiMutexes[port]);
   return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
 }
 
@@ -270,7 +270,7 @@
   xfer.tx_buf = (__u64)dataToSend;
   xfer.len = sendSize;
 
-  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  std::scoped_lock lock(spiApiMutexes[port]);
   return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
 }
 
@@ -286,7 +286,7 @@
   xfer.rx_buf = (__u64)buffer;
   xfer.len = count;
 
-  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  std::scoped_lock lock(spiApiMutexes[port]);
   return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
 }
 
@@ -299,7 +299,7 @@
   HAL_FreeSPIAuto(port, &status);
 
   {
-    std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+    std::scoped_lock lock(spiApiMutexes[port]);
     close(HAL_GetSPIHandle(port));
   }
 
@@ -335,7 +335,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  std::scoped_lock lock(spiApiMutexes[port]);
   ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MAX_SPEED_HZ, &speed);
 }
 
@@ -350,7 +350,7 @@
   mode |= (clkIdleHigh ? 2 : 0);
   mode |= (sampleOnTrailing ? 1 : 0);
 
-  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  std::scoped_lock lock(spiApiMutexes[port]);
   ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MODE, &mode);
 }
 
@@ -360,7 +360,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  std::scoped_lock lock(spiApiMutexes[port]);
   if (port < 4) {
     spiSystem->writeChipSelectActiveHigh_Hdr(
         spiSystem->readChipSelectActiveHigh_Hdr(status) | (1 << port), status);
@@ -375,7 +375,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  std::scoped_lock lock(spiApiMutexes[port]);
   if (port < 4) {
     spiSystem->writeChipSelectActiveHigh_Hdr(
         spiSystem->readChipSelectActiveHigh_Hdr(status) & ~(1 << port), status);
@@ -389,7 +389,7 @@
     return 0;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiHandleMutexes[port]);
+  std::scoped_lock lock(spiHandleMutexes[port]);
   switch (port) {
     case 0:
       return m_spiCS0Handle;
@@ -411,7 +411,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiHandleMutexes[port]);
+  std::scoped_lock lock(spiHandleMutexes[port]);
   switch (port) {
     case 0:
       m_spiCS0Handle = handle;
@@ -439,7 +439,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (spiAutoPort != kSpiMaxHandles) {
     *status = RESOURCE_IS_ALLOCATED;
@@ -470,7 +470,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   if (spiAutoPort != port) return;
   spiAutoPort = kSpiMaxHandles;
 
@@ -487,7 +487,7 @@
 }
 
 void HAL_StartSPIAutoRate(HAL_SPIPort port, double period, int32_t* status) {
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (port != spiAutoPort) {
     *status = INCOMPATIBLE_STATE;
@@ -510,7 +510,7 @@
                              HAL_AnalogTriggerType analogTriggerType,
                              HAL_Bool triggerRising, HAL_Bool triggerFalling,
                              int32_t* status) {
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (port != spiAutoPort) {
     *status = INCOMPATIBLE_STATE;
@@ -545,7 +545,7 @@
 }
 
 void HAL_StopSPIAuto(HAL_SPIPort port, int32_t* status) {
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (port != spiAutoPort) {
     *status = INCOMPATIBLE_STATE;
@@ -575,7 +575,7 @@
     return;
   }
 
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (port != spiAutoPort) {
     *status = INCOMPATIBLE_STATE;
@@ -594,7 +594,7 @@
 }
 
 void HAL_ForceSPIAutoRead(HAL_SPIPort port, int32_t* status) {
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (port != spiAutoPort) {
     *status = INCOMPATIBLE_STATE;
@@ -607,7 +607,7 @@
 int32_t HAL_ReadSPIAutoReceivedData(HAL_SPIPort port, uint32_t* buffer,
                                     int32_t numToRead, double timeout,
                                     int32_t* status) {
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (port != spiAutoPort) {
     *status = INCOMPATIBLE_STATE;
@@ -621,7 +621,7 @@
 }
 
 int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status) {
-  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  std::scoped_lock lock(spiAutoMutex);
   // FPGA only has one auto SPI engine
   if (port != spiAutoPort) {
     *status = INCOMPATIBLE_STATE;
diff --git a/hal/src/main/native/athena/SerialPort.cpp b/hal/src/main/native/athena/SerialPort.cpp
index d2597a9..7ef9b70 100644
--- a/hal/src/main/native/athena/SerialPort.cpp
+++ b/hal/src/main/native/athena/SerialPort.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,168 +7,493 @@
 
 #include "hal/SerialPort.h"
 
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <stdexcept>
 #include <string>
+#include <thread>
 
-#include "HALInitializer.h"
 #include "hal/cpp/SerialHelper.h"
-#include "visa/visa.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/IndexedHandleResource.h"
 
-static int32_t resourceManagerHandle{0};
-static HAL_SerialPort portHandles[4];
+namespace {
+struct SerialPort {
+  int portId;
+  struct termios tty;
+  int baudRate;
+
+  double timeout = 0;
+
+  bool termination = false;
+  char terminationChar = '\n';
+};
+}  // namespace
+
+namespace hal {
+IndexedHandleResource<HAL_SerialPortHandle, SerialPort, 4,
+                      HAL_HandleEnum::SerialPort>* serialPortHandles;
+}  // namespace hal
 
 namespace hal {
 namespace init {
-void InitializeSerialPort() {}
+void InitializeSerialPort() {
+  static IndexedHandleResource<HAL_SerialPortHandle, SerialPort, 4,
+                               HAL_HandleEnum::SerialPort>
+      spH;
+  serialPortHandles = &spH;
+}
 }  // namespace init
 }  // namespace hal
 
+using namespace hal;
+
 extern "C" {
-
-void HAL_InitializeSerialPort(HAL_SerialPort port, int32_t* status) {
-  hal::init::CheckInit();
-  std::string portName;
-
-  if (resourceManagerHandle == 0)
-    viOpenDefaultRM(reinterpret_cast<ViSession*>(&resourceManagerHandle));
+HAL_SerialPortHandle HAL_InitializeSerialPort(HAL_SerialPort port,
+                                              int32_t* status) {
+  // hal::init::CheckInit();
 
   hal::SerialHelper serialHelper;
 
-  portName = serialHelper.GetVISASerialPortName(port, status);
+  std::string portName = serialHelper.GetOSSerialPortName(port, status);
 
   if (*status < 0) {
+    return HAL_kInvalidHandle;
+  }
+
+  return HAL_InitializeSerialPortDirect(port, portName.c_str(), status);
+}
+HAL_SerialPortHandle HAL_InitializeSerialPortDirect(HAL_SerialPort port,
+                                                    const char* portName,
+                                                    int32_t* status) {
+  auto handle = serialPortHandles->Allocate(static_cast<int16_t>(port), status);
+
+  if (*status != 0) {
+    return HAL_kInvalidHandle;
+  }
+
+  auto serialPort = serialPortHandles->Get(handle);
+
+  if (serialPort == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  serialPort->portId = open(portName, O_RDWR | O_NOCTTY);
+  if (serialPort->portId < 0) {
+    *status = errno;
+    serialPortHandles->Free(handle);
+    return HAL_kInvalidHandle;
+  }
+
+  std::memset(&serialPort->tty, 0, sizeof(serialPort->tty));
+
+  serialPort->baudRate = B9600;
+  cfsetospeed(&serialPort->tty, static_cast<speed_t>(serialPort->baudRate));
+  cfsetispeed(&serialPort->tty, static_cast<speed_t>(serialPort->baudRate));
+
+  serialPort->tty.c_cflag &= ~PARENB;
+  serialPort->tty.c_cflag &= ~CSTOPB;
+  serialPort->tty.c_cflag &= ~CSIZE;
+  serialPort->tty.c_cflag |= CS8;
+
+  serialPort->tty.c_cc[VMIN] = 0;
+  serialPort->tty.c_cc[VTIME] = 10;
+
+  serialPort->tty.c_cflag |= CREAD | CLOCAL;
+
+  serialPort->tty.c_lflag &= ~(ICANON | ECHO | ISIG);
+  serialPort->tty.c_iflag &= ~(IXON | IXOFF | IXANY);
+  /* Raw output mode, sends the raw and unprocessed data  (send as it is).
+   * If it is in canonical mode and sending new line char then CR
+   * will be added as prefix and send as CR LF
+   */
+  serialPort->tty.c_oflag = ~OPOST;
+
+  tcflush(serialPort->portId, TCIOFLUSH);
+  if (tcsetattr(serialPort->portId, TCSANOW, &serialPort->tty) != 0) {
+    *status = errno;
+    close(serialPort->portId);
+    serialPortHandles->Free(handle);
+    return HAL_kInvalidHandle;
+  }
+  return handle;
+}
+
+void HAL_CloseSerial(HAL_SerialPortHandle handle, int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  serialPortHandles->Free(handle);
+
+  if (port) {
+    close(port->portId);
+  }
+}
+
+int HAL_GetSerialFD(HAL_SerialPortHandle handle, int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
+  }
+  return port->portId;
+}
+
+#define BAUDCASE(BAUD)        \
+  case BAUD:                  \
+    port->baudRate = B##BAUD; \
+    break;
+
+void HAL_SetSerialBaudRate(HAL_SerialPortHandle handle, int32_t baud,
+                           int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
     return;
   }
 
-  *status = viOpen(resourceManagerHandle, const_cast<char*>(portName.c_str()),
-                   VI_NULL, VI_NULL,
-                   reinterpret_cast<ViSession*>(&portHandles[port]));
-  if (*status > 0) *status = 0;
+  switch (baud) {
+    BAUDCASE(50)
+    BAUDCASE(75)
+    BAUDCASE(110)
+    BAUDCASE(134)
+    BAUDCASE(150)
+    BAUDCASE(200)
+    BAUDCASE(300)
+    BAUDCASE(600)
+    BAUDCASE(1200)
+    BAUDCASE(1800)
+    BAUDCASE(2400)
+    BAUDCASE(4800)
+    BAUDCASE(9600)
+    BAUDCASE(19200)
+    BAUDCASE(38400)
+    BAUDCASE(57600)
+    BAUDCASE(115200)
+    BAUDCASE(230400)
+    BAUDCASE(460800)
+    BAUDCASE(500000)
+    BAUDCASE(576000)
+    BAUDCASE(921600)
+    BAUDCASE(1000000)
+    BAUDCASE(1152000)
+    BAUDCASE(1500000)
+    BAUDCASE(2000000)
+    BAUDCASE(2500000)
+    BAUDCASE(3000000)
+    BAUDCASE(3500000)
+    BAUDCASE(4000000)
+    default:
+      *status = PARAMETER_OUT_OF_RANGE;
+      return;
+  }
+  int err = cfsetospeed(&port->tty, static_cast<speed_t>(port->baudRate));
+  if (err < 0) {
+    *status = errno;
+    return;
+  }
+  err = cfsetispeed(&port->tty, static_cast<speed_t>(port->baudRate));
+  if (err < 0) {
+    *status = errno;
+    return;
+  }
+  err = tcsetattr(port->portId, TCSANOW, &port->tty);
+  if (err < 0) {
+    *status = errno;
+  }
 }
 
-void HAL_InitializeSerialPortDirect(HAL_SerialPort port, const char* portName,
-                                    int32_t* status) {
-  *status = viOpen(resourceManagerHandle, const_cast<char*>(portName), VI_NULL,
-                   VI_NULL, reinterpret_cast<ViSession*>(&portHandles[port]));
-  if (*status > 0) *status = 0;
-}
-
-void HAL_SetSerialBaudRate(HAL_SerialPort port, int32_t baud, int32_t* status) {
-  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_BAUD, baud);
-  if (*status > 0) *status = 0;
-}
-
-void HAL_SetSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status) {
-  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_DATA_BITS, bits);
-  if (*status > 0) *status = 0;
-}
-
-void HAL_SetSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status) {
-  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_PARITY, parity);
-  if (*status > 0) *status = 0;
-}
-
-void HAL_SetSerialStopBits(HAL_SerialPort port, int32_t stopBits,
+void HAL_SetSerialDataBits(HAL_SerialPortHandle handle, int32_t bits,
                            int32_t* status) {
-  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_STOP_BITS, stopBits);
-  if (*status > 0) *status = 0;
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  int bitFlag = -1;
+  switch (bits) {
+    case 5:
+      bitFlag = CS5;
+      break;
+    case 6:
+      bitFlag = CS6;
+      break;
+    case 7:
+      bitFlag = CS7;
+      break;
+    case 8:
+      bitFlag = CS8;
+      break;
+    default:
+      *status = PARAMETER_OUT_OF_RANGE;
+      return;
+  }
+
+  port->tty.c_cflag &= ~CSIZE;
+  port->tty.c_cflag |= bitFlag;
+
+  int err = tcsetattr(port->portId, TCSANOW, &port->tty);
+  if (err < 0) {
+    *status = errno;
+  }
 }
 
-void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode,
+void HAL_SetSerialParity(HAL_SerialPortHandle handle, int32_t parity,
+                         int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  switch (parity) {
+    case 0:  // None
+      port->tty.c_cflag &= ~PARENB;
+      port->tty.c_cflag &= ~CMSPAR;
+      break;
+    case 1:  // Odd
+      port->tty.c_cflag |= PARENB;
+      port->tty.c_cflag &= ~CMSPAR;
+      port->tty.c_cflag &= ~PARODD;
+      break;
+    case 2:  // Even
+      port->tty.c_cflag |= PARENB;
+      port->tty.c_cflag &= ~CMSPAR;
+      port->tty.c_cflag |= PARODD;
+      break;
+    case 3:  // Mark
+      port->tty.c_cflag |= PARENB;
+      port->tty.c_cflag |= CMSPAR;
+      port->tty.c_cflag |= PARODD;
+      break;
+    case 4:  // Space
+      port->tty.c_cflag |= PARENB;
+      port->tty.c_cflag |= CMSPAR;
+      port->tty.c_cflag &= ~PARODD;
+      break;
+    default:
+      *status = PARAMETER_OUT_OF_RANGE;
+      return;
+  }
+
+  int err = tcsetattr(port->portId, TCSANOW, &port->tty);
+  if (err < 0) {
+    *status = errno;
+  }
+}
+
+void HAL_SetSerialStopBits(HAL_SerialPortHandle handle, int32_t stopBits,
+                           int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  switch (stopBits) {
+    case 10:  // 1
+      port->tty.c_cflag &= ~CSTOPB;
+      break;
+    case 15:  // 1.5
+    case 20:  // 2
+      port->tty.c_cflag |= CSTOPB;
+      break;
+    default:
+      *status = PARAMETER_OUT_OF_RANGE;
+      return;
+  }
+
+  int err = tcsetattr(port->portId, TCSANOW, &port->tty);
+  if (err < 0) {
+    *status = errno;
+  }
+}
+
+void HAL_SetSerialWriteMode(HAL_SerialPortHandle handle, int32_t mode,
                             int32_t* status) {
-  *status = viSetAttribute(portHandles[port], VI_ATTR_WR_BUF_OPER_MODE, mode);
-  if (*status > 0) *status = 0;
+  // This seems to be a no op on the NI serial port driver
 }
 
-void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
+void HAL_SetSerialFlowControl(HAL_SerialPortHandle handle, int32_t flow,
                               int32_t* status) {
-  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_FLOW_CNTRL, flow);
-  if (*status > 0) *status = 0;
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  switch (flow) {
+    case 0:
+      port->tty.c_cflag &= ~CRTSCTS;
+      break;
+    case 1:
+      port->tty.c_cflag &= ~CRTSCTS;
+      port->tty.c_iflag &= IXON | IXOFF;
+      break;
+    case 2:
+      port->tty.c_cflag |= CRTSCTS;
+      break;
+    default:
+      *status = PARAMETER_OUT_OF_RANGE;
+      return;
+  }
+
+  int err = tcsetattr(port->portId, TCSANOW, &port->tty);
+  if (err < 0) {
+    *status = errno;
+  }
 }
 
-void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout,
+void HAL_SetSerialTimeout(HAL_SerialPortHandle handle, double timeout,
                           int32_t* status) {
-  *status = viSetAttribute(portHandles[port], VI_ATTR_TMO_VALUE,
-                           static_cast<uint32_t>(timeout * 1e3));
-  if (*status > 0) *status = 0;
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  port->timeout = timeout;
+  port->tty.c_cc[VTIME] = static_cast<int>(timeout * 10);
+  int err = tcsetattr(port->portId, TCSANOW, &port->tty);
+  if (err < 0) {
+    *status = errno;
+  }
 }
 
-void HAL_EnableSerialTermination(HAL_SerialPort port, char terminator,
+void HAL_EnableSerialTermination(HAL_SerialPortHandle handle, char terminator,
                                  int32_t* status) {
-  viSetAttribute(portHandles[port], VI_ATTR_TERMCHAR_EN, VI_TRUE);
-  viSetAttribute(portHandles[port], VI_ATTR_TERMCHAR, terminator);
-  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_END_IN,
-                           VI_ASRL_END_TERMCHAR);
-  if (*status > 0) *status = 0;
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  port->termination = true;
+  port->terminationChar = terminator;
 }
 
-void HAL_DisableSerialTermination(HAL_SerialPort port, int32_t* status) {
-  viSetAttribute(portHandles[port], VI_ATTR_TERMCHAR_EN, VI_FALSE);
-  *status =
-      viSetAttribute(portHandles[port], VI_ATTR_ASRL_END_IN, VI_ASRL_END_NONE);
-  if (*status > 0) *status = 0;
-}
-
-void HAL_SetSerialReadBufferSize(HAL_SerialPort port, int32_t size,
-                                 int32_t* status) {
-  *status = viSetBuf(portHandles[port], VI_READ_BUF, size);
-  if (*status > 0) *status = 0;
-}
-
-void HAL_SetSerialWriteBufferSize(HAL_SerialPort port, int32_t size,
+void HAL_DisableSerialTermination(HAL_SerialPortHandle handle,
                                   int32_t* status) {
-  *status = viSetBuf(portHandles[port], VI_WRITE_BUF, size);
-  if (*status > 0) *status = 0;
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  port->termination = false;
 }
 
-int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status) {
-  int32_t bytes = 0;
+void HAL_SetSerialReadBufferSize(HAL_SerialPortHandle handle, int32_t size,
+                                 int32_t* status) {
+  // NO OP currently
+}
 
-  *status = viGetAttribute(portHandles[port], VI_ATTR_ASRL_AVAIL_NUM, &bytes);
-  if (*status > 0) *status = 0;
+void HAL_SetSerialWriteBufferSize(HAL_SerialPortHandle handle, int32_t size,
+                                  int32_t* status) {
+  // NO OP currently
+}
+
+int32_t HAL_GetSerialBytesReceived(HAL_SerialPortHandle handle,
+                                   int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
+  }
+  int bytes = 0;
+  int err = ioctl(port->portId, FIONREAD, &bytes);
+  if (err < 0) {
+    *status = errno;
+  }
   return bytes;
 }
 
-int32_t HAL_ReadSerial(HAL_SerialPort port, char* buffer, int32_t count,
+int32_t HAL_ReadSerial(HAL_SerialPortHandle handle, char* buffer, int32_t count,
                        int32_t* status) {
-  uint32_t retCount = 0;
+  // Don't do anything if 0 bytes were requested
+  if (count == 0) return 0;
 
-  *status =
-      viRead(portHandles[port], (ViPBuf)buffer, count, (ViPUInt32)&retCount);
-
-  if (*status == VI_ERROR_IO || *status == VI_ERROR_ASRL_OVERRUN ||
-      *status == VI_ERROR_ASRL_FRAMING || *status == VI_ERROR_ASRL_PARITY) {
-    int32_t localStatus = 0;
-    HAL_ClearSerial(port, &localStatus);
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
   }
 
-  if (*status == VI_ERROR_TMO || *status > 0) *status = 0;
-  return static_cast<int32_t>(retCount);
+  int n = 0, loc = 0;
+  char buf = '\0';
+  std::memset(buffer, '\0', count);
+  *status = 0;
+
+  do {
+    n = read(port->portId, &buf, 1);
+    if (n == 1) {
+      buffer[loc] = buf;
+      loc++;
+      // If buffer is full, return
+      if (loc == count) {
+        return loc;
+      }
+      // If terminating, and termination was hit return;
+      if (port->termination && buf == port->terminationChar) {
+        return loc;
+      }
+    } else if (n == -1) {
+      // ERROR
+      *status = errno;
+      return loc;
+    } else {
+      // If nothing read, timeout
+      return loc;
+    }
+  } while (true);
 }
 
-int32_t HAL_WriteSerial(HAL_SerialPort port, const char* buffer, int32_t count,
-                        int32_t* status) {
-  uint32_t retCount = 0;
+int32_t HAL_WriteSerial(HAL_SerialPortHandle handle, const char* buffer,
+                        int32_t count, int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
+  }
 
-  *status =
-      viWrite(portHandles[port], (ViPBuf)buffer, count, (ViPUInt32)&retCount);
-
-  if (*status > 0) *status = 0;
-  return static_cast<int32_t>(retCount);
+  int written = 0, spot = 0;
+  do {
+    written = write(port->portId, buffer + spot, count - spot);
+    if (written < 0) {
+      *status = errno;
+      return spot;
+    }
+    spot += written;
+  } while (spot < count);
+  return spot;
 }
 
-void HAL_FlushSerial(HAL_SerialPort port, int32_t* status) {
-  *status = viFlush(portHandles[port], VI_WRITE_BUF);
-  if (*status > 0) *status = 0;
+void HAL_FlushSerial(HAL_SerialPortHandle handle, int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  int err = tcdrain(port->portId);
+  if (err < 0) {
+    *status = errno;
+  }
 }
-
-void HAL_ClearSerial(HAL_SerialPort port, int32_t* status) {
-  *status = viClear(portHandles[port]);
-  if (*status > 0) *status = 0;
+void HAL_ClearSerial(HAL_SerialPortHandle handle, int32_t* status) {
+  auto port = serialPortHandles->Get(handle);
+  if (!port) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  int err = tcflush(port->portId, TCIOFLUSH);
+  if (err < 0) {
+    *status = errno;
+  }
 }
-
-void HAL_CloseSerial(HAL_SerialPort port, int32_t* status) {
-  *status = viClose(portHandles[port]);
-  if (*status > 0) *status = 0;
-}
-
 }  // extern "C"
diff --git a/hal/src/main/native/athena/SimDevice.cpp b/hal/src/main/native/athena/SimDevice.cpp
new file mode 100644
index 0000000..94a65d4
--- /dev/null
+++ b/hal/src/main/native/athena/SimDevice.cpp
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/SimDevice.h"
+
+extern "C" {
+
+HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name) { return 0; }
+
+void HAL_FreeSimDevice(HAL_SimDeviceHandle handle) {}
+
+HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
+                                      const char* name, HAL_Bool readonly,
+                                      const struct HAL_Value* initialValue) {
+  return 0;
+}
+
+HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
+                                          const char* name, HAL_Bool readonly,
+                                          int32_t numOptions,
+                                          const char** options,
+                                          int32_t initialValue) {
+  return 0;
+}
+
+void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
+  value->type = HAL_UNASSIGNED;
+}
+
+void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value) {
+}
+
+hal::SimDevice::SimDevice(const char* name, int index) {}
+
+hal::SimDevice::SimDevice(const char* name, int index, int channel) {}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/cpp/SerialHelper.cpp b/hal/src/main/native/athena/cpp/SerialHelper.cpp
index 98b22db..e312e2a 100644
--- a/hal/src/main/native/athena/cpp/SerialHelper.cpp
+++ b/hal/src/main/native/athena/cpp/SerialHelper.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -14,8 +14,8 @@
 #include <wpi/FileSystem.h>
 #include <wpi/StringRef.h>
 
-#include "../visa/visa.h"
 #include "hal/Errors.h"
+#include "visa/visa.h"
 
 constexpr const char* OnboardResourceVISA = "ASRL1::INSTR";
 constexpr const char* MxpResourceVISA = "ASRL2::INSTR";
@@ -275,7 +275,7 @@
 
 int32_t SerialHelper::GetIndexForPort(HAL_SerialPort port, int32_t* status) {
   // Hold lock whenever we're using the names array
-  std::lock_guard<wpi::mutex> lock(m_nameMutex);
+  std::scoped_lock lock(m_nameMutex);
 
   std::string portString = m_usbNames[port - 2];
 
diff --git a/hal/src/main/native/athena/ctre/CtreCanNode.cpp b/hal/src/main/native/athena/ctre/CtreCanNode.cpp
index bd3c9e8..440bebd 100644
--- a/hal/src/main/native/athena/ctre/CtreCanNode.cpp
+++ b/hal/src/main/native/athena/ctre/CtreCanNode.cpp
@@ -86,7 +86,7 @@
 	if(timeoutMs > 999)
 		timeoutMs = 999;
 	FRC_NetworkCommunication_CANSessionMux_receiveMessage(&arbId,kFullMessageIDMask,dataBytes,&len,&timeStamp,&status);
-	std::lock_guard<wpi::mutex> lock(_lck);
+	std::scoped_lock lock(_lck);
 	if(status == 0){
 		/* fresh update */
 		rxEvent_t & r = _rxRxEvents[arbId]; /* lookup entry or make a default new one with all zeroes */
diff --git a/hal/src/main/native/athena/visa/visa.h b/hal/src/main/native/athena/visa/visa.h
deleted file mode 100644
index 3c6ad30..0000000
--- a/hal/src/main/native/athena/visa/visa.h
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*---------------------------------------------------------------------------*/
-/* Distributed by IVI Foundation Inc.                                        */
-/* Contains National Instruments extensions.                                 */
-/* Do not modify the contents of this file.                                  */
-/*---------------------------------------------------------------------------*/
-/*                                                                           */
-/* Title   : VISA.H                                                          */
-/* Date    : 10-09-2006                                                      */
-/* Purpose : Include file for the VISA Library 4.0 specification             */
-/*                                                                           */
-/*---------------------------------------------------------------------------*/
-/* When using NI-VISA extensions, you must link with the VISA library that   */
-/* comes with NI-VISA.  Currently, the extensions provided by NI-VISA are:   */
-/*                                                                           */
-/* PXI (Compact PCI eXtensions for Instrumentation) and PCI support.  To use */
-/* this, you must define the macro NIVISA_PXI before including this header.  */
-/* You must also create an INF file with the VISA Driver Development Wizard. */
-/*                                                                           */
-/* A fast set of macros for viPeekXX/viPokeXX that guarantees binary         */
-/* compatibility with other implementations of VISA.  To use this, you must  */
-/* define the macro NIVISA_PEEKPOKE before including this header.            */
-/*                                                                           */
-/* Support for USB devices that do not conform to a specific class.  To use  */
-/* this, you must define the macro NIVISA_USB before including this header.  */
-/* You must also create an INF file with the VISA Driver Development Wizard. */
-/*---------------------------------------------------------------------------*/
-
-#ifndef __VISA_HEADER__
-#define __VISA_HEADER__
-
-#include <stdarg.h>
-
-#if !defined(__VISATYPE_HEADER__)
-#include "visatype.h"
-#endif
-
-#define VI_SPEC_VERSION     (0x00400000UL)
-
-#if defined(__cplusplus) || defined(__cplusplus__)
-   extern "C" {
-#endif
-
-#if defined(_CVI_)
-#pragma EnableLibraryRuntimeChecking
-#endif
-
-/*- VISA Types --------------------------------------------------------------*/
-
-typedef ViObject             ViEvent;
-typedef ViEvent      _VI_PTR ViPEvent;
-typedef ViObject             ViFindList;
-typedef ViFindList   _VI_PTR ViPFindList;
-
-#if defined(_VI_INT64_UINT64_DEFINED) && defined(_VISA_ENV_IS_64_BIT)
-typedef ViUInt64             ViBusAddress;
-typedef ViUInt64             ViBusSize;
-typedef ViUInt64             ViAttrState;
-#else
-typedef ViUInt32             ViBusAddress;
-typedef ViUInt32             ViBusSize;
-typedef ViUInt32             ViAttrState;
-#endif
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-typedef ViUInt64             ViBusAddress64;
-typedef ViBusAddress64 _VI_PTR ViPBusAddress64;
-#endif
-
-typedef ViUInt32             ViEventType;
-typedef ViEventType  _VI_PTR ViPEventType;
-typedef ViEventType  _VI_PTR ViAEventType;
-typedef void         _VI_PTR ViPAttrState;
-typedef ViAttr       _VI_PTR ViPAttr;
-typedef ViAttr       _VI_PTR ViAAttr;
-
-typedef ViString             ViKeyId;
-typedef ViPString            ViPKeyId;
-typedef ViUInt32             ViJobId;
-typedef ViJobId      _VI_PTR ViPJobId;
-typedef ViUInt32             ViAccessMode;
-typedef ViAccessMode _VI_PTR ViPAccessMode;
-typedef ViBusAddress _VI_PTR ViPBusAddress;
-typedef ViUInt32             ViEventFilter;
-
-typedef va_list              ViVAList;
-
-typedef ViStatus (_VI_FUNCH _VI_PTR ViHndlr)
-   (ViSession vi, ViEventType eventType, ViEvent event, ViAddr userHandle);
-
-/*- Resource Manager Functions and Operations -------------------------------*/
-
-ViStatus _VI_FUNC  viOpenDefaultRM (ViPSession vi);
-ViStatus _VI_FUNC  viFindRsrc      (ViSession sesn, ViString expr, ViPFindList vi,
-                                    ViPUInt32 retCnt, ViChar _VI_FAR desc[]);
-ViStatus _VI_FUNC  viFindNext      (ViFindList vi, ViChar _VI_FAR desc[]);
-ViStatus _VI_FUNC  viParseRsrc     (ViSession rmSesn, ViRsrc rsrcName,
-                                    ViPUInt16 intfType, ViPUInt16 intfNum);
-ViStatus _VI_FUNC  viParseRsrcEx   (ViSession rmSesn, ViRsrc rsrcName, ViPUInt16 intfType,
-                                    ViPUInt16 intfNum, ViChar _VI_FAR rsrcClass[],
-                                    ViChar _VI_FAR expandedUnaliasedName[],
-                                    ViChar _VI_FAR aliasIfExists[]);
-ViStatus _VI_FUNC  viOpen          (ViSession sesn, ViRsrc name, ViAccessMode mode,
-                                    ViUInt32 timeout, ViPSession vi);
-
-/*- Resource Template Operations --------------------------------------------*/
-
-ViStatus _VI_FUNC  viClose         (ViObject vi);
-ViStatus _VI_FUNC  viSetAttribute  (ViObject vi, ViAttr attrName, ViAttrState attrValue);
-ViStatus _VI_FUNC  viGetAttribute  (ViObject vi, ViAttr attrName, void _VI_PTR attrValue);
-ViStatus _VI_FUNC  viStatusDesc    (ViObject vi, ViStatus status, ViChar _VI_FAR desc[]);
-ViStatus _VI_FUNC  viTerminate     (ViObject vi, ViUInt16 degree, ViJobId jobId);
-
-ViStatus _VI_FUNC  viLock          (ViSession vi, ViAccessMode lockType, ViUInt32 timeout,
-                                    ViKeyId requestedKey, ViChar _VI_FAR accessKey[]);
-ViStatus _VI_FUNC  viUnlock        (ViSession vi);
-ViStatus _VI_FUNC  viEnableEvent   (ViSession vi, ViEventType eventType, ViUInt16 mechanism,
-                                    ViEventFilter context);
-ViStatus _VI_FUNC  viDisableEvent  (ViSession vi, ViEventType eventType, ViUInt16 mechanism);
-ViStatus _VI_FUNC  viDiscardEvents (ViSession vi, ViEventType eventType, ViUInt16 mechanism);
-ViStatus _VI_FUNC  viWaitOnEvent   (ViSession vi, ViEventType inEventType, ViUInt32 timeout,
-                                    ViPEventType outEventType, ViPEvent outContext);
-ViStatus _VI_FUNC  viInstallHandler(ViSession vi, ViEventType eventType, ViHndlr handler,
-                                    ViAddr userHandle);
-ViStatus _VI_FUNC  viUninstallHandler(ViSession vi, ViEventType eventType, ViHndlr handler,
-                                      ViAddr userHandle);
-
-/*- Basic I/O Operations ----------------------------------------------------*/
-
-ViStatus _VI_FUNC  viRead          (ViSession vi, ViPBuf buf, ViUInt32 cnt, ViPUInt32 retCnt);
-ViStatus _VI_FUNC  viReadAsync     (ViSession vi, ViPBuf buf, ViUInt32 cnt, ViPJobId  jobId);
-ViStatus _VI_FUNC  viReadToFile    (ViSession vi, ViConstString filename, ViUInt32 cnt,
-                                    ViPUInt32 retCnt);
-ViStatus _VI_FUNC  viWrite         (ViSession vi, ViBuf  buf, ViUInt32 cnt, ViPUInt32 retCnt);
-ViStatus _VI_FUNC  viWriteAsync    (ViSession vi, ViBuf  buf, ViUInt32 cnt, ViPJobId  jobId);
-ViStatus _VI_FUNC  viWriteFromFile (ViSession vi, ViConstString filename, ViUInt32 cnt,
-                                    ViPUInt32 retCnt);
-ViStatus _VI_FUNC  viAssertTrigger (ViSession vi, ViUInt16 protocol);
-ViStatus _VI_FUNC  viReadSTB       (ViSession vi, ViPUInt16 status);
-ViStatus _VI_FUNC  viClear         (ViSession vi);
-
-/*- Formatted and Buffered I/O Operations -----------------------------------*/
-
-ViStatus _VI_FUNC  viSetBuf        (ViSession vi, ViUInt16 mask, ViUInt32 size);
-ViStatus _VI_FUNC  viFlush         (ViSession vi, ViUInt16 mask);
-
-ViStatus _VI_FUNC  viBufWrite      (ViSession vi, ViBuf  buf, ViUInt32 cnt, ViPUInt32 retCnt);
-ViStatus _VI_FUNC  viBufRead       (ViSession vi, ViPBuf buf, ViUInt32 cnt, ViPUInt32 retCnt);
-
-ViStatus _VI_FUNCC viPrintf        (ViSession vi, ViString writeFmt, ...);
-ViStatus _VI_FUNC  viVPrintf       (ViSession vi, ViString writeFmt, ViVAList params);
-ViStatus _VI_FUNCC viSPrintf       (ViSession vi, ViPBuf buf, ViString writeFmt, ...);
-ViStatus _VI_FUNC  viVSPrintf      (ViSession vi, ViPBuf buf, ViString writeFmt,
-                                    ViVAList parms);
-
-ViStatus _VI_FUNCC viScanf         (ViSession vi, ViString readFmt, ...);
-ViStatus _VI_FUNC  viVScanf        (ViSession vi, ViString readFmt, ViVAList params);
-ViStatus _VI_FUNCC viSScanf        (ViSession vi, ViBuf buf, ViString readFmt, ...);
-ViStatus _VI_FUNC  viVSScanf       (ViSession vi, ViBuf buf, ViString readFmt,
-                                    ViVAList parms);
-
-ViStatus _VI_FUNCC viQueryf        (ViSession vi, ViString writeFmt, ViString readFmt, ...);
-ViStatus _VI_FUNC  viVQueryf       (ViSession vi, ViString writeFmt, ViString readFmt, 
-                                    ViVAList params);
-
-/*- Memory I/O Operations ---------------------------------------------------*/
-
-ViStatus _VI_FUNC  viIn8           (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViPUInt8  val8);
-ViStatus _VI_FUNC  viOut8          (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViUInt8   val8);
-ViStatus _VI_FUNC  viIn16          (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViPUInt16 val16);
-ViStatus _VI_FUNC  viOut16         (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViUInt16  val16);
-ViStatus _VI_FUNC  viIn32          (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViPUInt32 val32);
-ViStatus _VI_FUNC  viOut32         (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViUInt32  val32);
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-ViStatus _VI_FUNC  viIn64          (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViPUInt64 val64);
-ViStatus _VI_FUNC  viOut64         (ViSession vi, ViUInt16 space,
-                                    ViBusAddress offset, ViUInt64  val64);
-
-ViStatus _VI_FUNC  viIn8Ex         (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViPUInt8  val8);
-ViStatus _VI_FUNC  viOut8Ex        (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViUInt8   val8);
-ViStatus _VI_FUNC  viIn16Ex        (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViPUInt16 val16);
-ViStatus _VI_FUNC  viOut16Ex       (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViUInt16  val16);
-ViStatus _VI_FUNC  viIn32Ex        (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViPUInt32 val32);
-ViStatus _VI_FUNC  viOut32Ex       (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViUInt32  val32);
-ViStatus _VI_FUNC  viIn64Ex        (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViPUInt64 val64);
-ViStatus _VI_FUNC  viOut64Ex       (ViSession vi, ViUInt16 space,
-                                    ViBusAddress64 offset, ViUInt64  val64);
-#endif
-
-ViStatus _VI_FUNC  viMoveIn8       (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt8  buf8);
-ViStatus _VI_FUNC  viMoveOut8      (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt8  buf8);
-ViStatus _VI_FUNC  viMoveIn16      (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt16 buf16);
-ViStatus _VI_FUNC  viMoveOut16     (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt16 buf16);
-ViStatus _VI_FUNC  viMoveIn32      (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt32 buf32);
-ViStatus _VI_FUNC  viMoveOut32     (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt32 buf32);
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-ViStatus _VI_FUNC  viMoveIn64      (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt64 buf64);
-ViStatus _VI_FUNC  viMoveOut64     (ViSession vi, ViUInt16 space, ViBusAddress offset,
-                                    ViBusSize length, ViAUInt64 buf64);
-
-ViStatus _VI_FUNC  viMoveIn8Ex     (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt8  buf8);
-ViStatus _VI_FUNC  viMoveOut8Ex    (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt8  buf8);
-ViStatus _VI_FUNC  viMoveIn16Ex    (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt16 buf16);
-ViStatus _VI_FUNC  viMoveOut16Ex   (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt16 buf16);
-ViStatus _VI_FUNC  viMoveIn32Ex    (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt32 buf32);
-ViStatus _VI_FUNC  viMoveOut32Ex   (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt32 buf32);
-ViStatus _VI_FUNC  viMoveIn64Ex    (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt64 buf64);
-ViStatus _VI_FUNC  viMoveOut64Ex   (ViSession vi, ViUInt16 space, ViBusAddress64 offset,
-                                    ViBusSize length, ViAUInt64 buf64);
-#endif
-
-ViStatus _VI_FUNC  viMove          (ViSession vi, ViUInt16 srcSpace, ViBusAddress srcOffset,
-                                    ViUInt16 srcWidth, ViUInt16 destSpace, 
-                                    ViBusAddress destOffset, ViUInt16 destWidth, 
-                                    ViBusSize srcLength); 
-ViStatus _VI_FUNC  viMoveAsync     (ViSession vi, ViUInt16 srcSpace, ViBusAddress srcOffset,
-                                    ViUInt16 srcWidth, ViUInt16 destSpace, 
-                                    ViBusAddress destOffset, ViUInt16 destWidth, 
-                                    ViBusSize srcLength, ViPJobId jobId);
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-ViStatus _VI_FUNC  viMoveEx        (ViSession vi, ViUInt16 srcSpace, ViBusAddress64 srcOffset,
-                                    ViUInt16 srcWidth, ViUInt16 destSpace, 
-                                    ViBusAddress64 destOffset, ViUInt16 destWidth, 
-                                    ViBusSize srcLength); 
-ViStatus _VI_FUNC  viMoveAsyncEx   (ViSession vi, ViUInt16 srcSpace, ViBusAddress64 srcOffset,
-                                    ViUInt16 srcWidth, ViUInt16 destSpace, 
-                                    ViBusAddress64 destOffset, ViUInt16 destWidth, 
-                                    ViBusSize srcLength, ViPJobId jobId);
-#endif
-
-ViStatus _VI_FUNC  viMapAddress    (ViSession vi, ViUInt16 mapSpace, ViBusAddress mapOffset,
-                                    ViBusSize mapSize, ViBoolean access,
-                                    ViAddr suggested, ViPAddr address);
-ViStatus _VI_FUNC  viUnmapAddress  (ViSession vi);
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-ViStatus _VI_FUNC  viMapAddressEx  (ViSession vi, ViUInt16 mapSpace, ViBusAddress64 mapOffset,
-                                    ViBusSize mapSize, ViBoolean access,
-                                    ViAddr suggested, ViPAddr address);
-#endif
-
-void     _VI_FUNC  viPeek8         (ViSession vi, ViAddr address, ViPUInt8  val8);
-void     _VI_FUNC  viPoke8         (ViSession vi, ViAddr address, ViUInt8   val8);
-void     _VI_FUNC  viPeek16        (ViSession vi, ViAddr address, ViPUInt16 val16);
-void     _VI_FUNC  viPoke16        (ViSession vi, ViAddr address, ViUInt16  val16);
-void     _VI_FUNC  viPeek32        (ViSession vi, ViAddr address, ViPUInt32 val32);
-void     _VI_FUNC  viPoke32        (ViSession vi, ViAddr address, ViUInt32  val32);
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-void     _VI_FUNC  viPeek64        (ViSession vi, ViAddr address, ViPUInt64 val64);
-void     _VI_FUNC  viPoke64        (ViSession vi, ViAddr address, ViUInt64  val64);
-#endif
-
-/*- Shared Memory Operations ------------------------------------------------*/
-
-ViStatus _VI_FUNC  viMemAlloc      (ViSession vi, ViBusSize size, ViPBusAddress offset);
-ViStatus _VI_FUNC  viMemFree       (ViSession vi, ViBusAddress offset);
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-ViStatus _VI_FUNC  viMemAllocEx    (ViSession vi, ViBusSize size, ViPBusAddress64 offset);
-ViStatus _VI_FUNC  viMemFreeEx     (ViSession vi, ViBusAddress64 offset);
-#endif
-
-/*- Interface Specific Operations -------------------------------------------*/
-
-ViStatus _VI_FUNC  viGpibControlREN(ViSession vi, ViUInt16 mode);
-ViStatus _VI_FUNC  viGpibControlATN(ViSession vi, ViUInt16 mode);
-ViStatus _VI_FUNC  viGpibSendIFC   (ViSession vi);
-ViStatus _VI_FUNC  viGpibCommand   (ViSession vi, ViBuf cmd, ViUInt32 cnt, ViPUInt32 retCnt);
-ViStatus _VI_FUNC  viGpibPassControl(ViSession vi, ViUInt16 primAddr, ViUInt16 secAddr);
-
-ViStatus _VI_FUNC  viVxiCommandQuery(ViSession vi, ViUInt16 mode, ViUInt32 cmd,
-                                     ViPUInt32 response);
-ViStatus _VI_FUNC  viAssertUtilSignal(ViSession vi, ViUInt16 line);
-ViStatus _VI_FUNC  viAssertIntrSignal(ViSession vi, ViInt16 mode, ViUInt32 statusID);
-ViStatus _VI_FUNC  viMapTrigger    (ViSession vi, ViInt16 trigSrc, ViInt16 trigDest, 
-                                    ViUInt16 mode);
-ViStatus _VI_FUNC  viUnmapTrigger  (ViSession vi, ViInt16 trigSrc, ViInt16 trigDest);
-ViStatus _VI_FUNC  viUsbControlOut (ViSession vi, ViInt16 bmRequestType, ViInt16 bRequest,
-                                    ViUInt16 wValue, ViUInt16 wIndex, ViUInt16 wLength,
-                                    ViBuf buf);
-ViStatus _VI_FUNC  viUsbControlIn  (ViSession vi, ViInt16 bmRequestType, ViInt16 bRequest,
-                                    ViUInt16 wValue, ViUInt16 wIndex, ViUInt16 wLength,
-                                    ViPBuf buf, ViPUInt16 retCnt);
-
-/*- Attributes (platform independent size) ----------------------------------*/
-
-#define VI_ATTR_RSRC_CLASS          (0xBFFF0001UL)
-#define VI_ATTR_RSRC_NAME           (0xBFFF0002UL)
-#define VI_ATTR_RSRC_IMPL_VERSION   (0x3FFF0003UL)
-#define VI_ATTR_RSRC_LOCK_STATE     (0x3FFF0004UL)
-#define VI_ATTR_MAX_QUEUE_LENGTH    (0x3FFF0005UL)
-#define VI_ATTR_USER_DATA_32        (0x3FFF0007UL)
-#define VI_ATTR_FDC_CHNL            (0x3FFF000DUL)
-#define VI_ATTR_FDC_MODE            (0x3FFF000FUL)
-#define VI_ATTR_FDC_GEN_SIGNAL_EN   (0x3FFF0011UL)
-#define VI_ATTR_FDC_USE_PAIR        (0x3FFF0013UL)
-#define VI_ATTR_SEND_END_EN         (0x3FFF0016UL)
-#define VI_ATTR_TERMCHAR            (0x3FFF0018UL)
-#define VI_ATTR_TMO_VALUE           (0x3FFF001AUL)
-#define VI_ATTR_GPIB_READDR_EN      (0x3FFF001BUL)
-#define VI_ATTR_IO_PROT             (0x3FFF001CUL)
-#define VI_ATTR_DMA_ALLOW_EN        (0x3FFF001EUL)
-#define VI_ATTR_ASRL_BAUD           (0x3FFF0021UL)
-#define VI_ATTR_ASRL_DATA_BITS      (0x3FFF0022UL)
-#define VI_ATTR_ASRL_PARITY         (0x3FFF0023UL)
-#define VI_ATTR_ASRL_STOP_BITS      (0x3FFF0024UL)
-#define VI_ATTR_ASRL_FLOW_CNTRL     (0x3FFF0025UL)
-#define VI_ATTR_RD_BUF_OPER_MODE    (0x3FFF002AUL)
-#define VI_ATTR_RD_BUF_SIZE         (0x3FFF002BUL)
-#define VI_ATTR_WR_BUF_OPER_MODE    (0x3FFF002DUL)
-#define VI_ATTR_WR_BUF_SIZE         (0x3FFF002EUL)
-#define VI_ATTR_SUPPRESS_END_EN     (0x3FFF0036UL)
-#define VI_ATTR_TERMCHAR_EN         (0x3FFF0038UL)
-#define VI_ATTR_DEST_ACCESS_PRIV    (0x3FFF0039UL)
-#define VI_ATTR_DEST_BYTE_ORDER     (0x3FFF003AUL)
-#define VI_ATTR_SRC_ACCESS_PRIV     (0x3FFF003CUL)
-#define VI_ATTR_SRC_BYTE_ORDER      (0x3FFF003DUL)
-#define VI_ATTR_SRC_INCREMENT       (0x3FFF0040UL)
-#define VI_ATTR_DEST_INCREMENT      (0x3FFF0041UL)
-#define VI_ATTR_WIN_ACCESS_PRIV     (0x3FFF0045UL)
-#define VI_ATTR_WIN_BYTE_ORDER      (0x3FFF0047UL)
-#define VI_ATTR_GPIB_ATN_STATE      (0x3FFF0057UL)
-#define VI_ATTR_GPIB_ADDR_STATE     (0x3FFF005CUL)
-#define VI_ATTR_GPIB_CIC_STATE      (0x3FFF005EUL)
-#define VI_ATTR_GPIB_NDAC_STATE     (0x3FFF0062UL)
-#define VI_ATTR_GPIB_SRQ_STATE      (0x3FFF0067UL)
-#define VI_ATTR_GPIB_SYS_CNTRL_STATE (0x3FFF0068UL)
-#define VI_ATTR_GPIB_HS488_CBL_LEN  (0x3FFF0069UL)
-#define VI_ATTR_CMDR_LA             (0x3FFF006BUL)
-#define VI_ATTR_VXI_DEV_CLASS       (0x3FFF006CUL)
-#define VI_ATTR_MAINFRAME_LA        (0x3FFF0070UL)
-#define VI_ATTR_MANF_NAME           (0xBFFF0072UL)
-#define VI_ATTR_MODEL_NAME          (0xBFFF0077UL)
-#define VI_ATTR_VXI_VME_INTR_STATUS (0x3FFF008BUL)
-#define VI_ATTR_VXI_TRIG_STATUS     (0x3FFF008DUL)
-#define VI_ATTR_VXI_VME_SYSFAIL_STATE (0x3FFF0094UL)
-#define VI_ATTR_WIN_BASE_ADDR_32    (0x3FFF0098UL)
-#define VI_ATTR_WIN_SIZE_32         (0x3FFF009AUL)
-#define VI_ATTR_ASRL_AVAIL_NUM      (0x3FFF00ACUL)
-#define VI_ATTR_MEM_BASE_32         (0x3FFF00ADUL)
-#define VI_ATTR_ASRL_CTS_STATE      (0x3FFF00AEUL)
-#define VI_ATTR_ASRL_DCD_STATE      (0x3FFF00AFUL)
-#define VI_ATTR_ASRL_DSR_STATE      (0x3FFF00B1UL)
-#define VI_ATTR_ASRL_DTR_STATE      (0x3FFF00B2UL)
-#define VI_ATTR_ASRL_END_IN         (0x3FFF00B3UL)
-#define VI_ATTR_ASRL_END_OUT        (0x3FFF00B4UL)
-#define VI_ATTR_ASRL_REPLACE_CHAR   (0x3FFF00BEUL)
-#define VI_ATTR_ASRL_RI_STATE       (0x3FFF00BFUL)
-#define VI_ATTR_ASRL_RTS_STATE      (0x3FFF00C0UL)
-#define VI_ATTR_ASRL_XON_CHAR       (0x3FFF00C1UL)
-#define VI_ATTR_ASRL_XOFF_CHAR      (0x3FFF00C2UL)
-#define VI_ATTR_WIN_ACCESS          (0x3FFF00C3UL)
-#define VI_ATTR_RM_SESSION          (0x3FFF00C4UL)
-#define VI_ATTR_VXI_LA              (0x3FFF00D5UL)
-#define VI_ATTR_MANF_ID             (0x3FFF00D9UL)
-#define VI_ATTR_MEM_SIZE_32         (0x3FFF00DDUL)
-#define VI_ATTR_MEM_SPACE           (0x3FFF00DEUL)
-#define VI_ATTR_MODEL_CODE          (0x3FFF00DFUL)
-#define VI_ATTR_SLOT                (0x3FFF00E8UL)
-#define VI_ATTR_INTF_INST_NAME      (0xBFFF00E9UL)
-#define VI_ATTR_IMMEDIATE_SERV      (0x3FFF0100UL)
-#define VI_ATTR_INTF_PARENT_NUM     (0x3FFF0101UL)
-#define VI_ATTR_RSRC_SPEC_VERSION   (0x3FFF0170UL)
-#define VI_ATTR_INTF_TYPE           (0x3FFF0171UL)
-#define VI_ATTR_GPIB_PRIMARY_ADDR   (0x3FFF0172UL)
-#define VI_ATTR_GPIB_SECONDARY_ADDR (0x3FFF0173UL)
-#define VI_ATTR_RSRC_MANF_NAME      (0xBFFF0174UL)
-#define VI_ATTR_RSRC_MANF_ID        (0x3FFF0175UL)
-#define VI_ATTR_INTF_NUM            (0x3FFF0176UL)
-#define VI_ATTR_TRIG_ID             (0x3FFF0177UL)
-#define VI_ATTR_GPIB_REN_STATE      (0x3FFF0181UL)
-#define VI_ATTR_GPIB_UNADDR_EN      (0x3FFF0184UL)
-#define VI_ATTR_DEV_STATUS_BYTE     (0x3FFF0189UL)
-#define VI_ATTR_FILE_APPEND_EN      (0x3FFF0192UL)
-#define VI_ATTR_VXI_TRIG_SUPPORT    (0x3FFF0194UL)
-#define VI_ATTR_TCPIP_ADDR          (0xBFFF0195UL)
-#define VI_ATTR_TCPIP_HOSTNAME      (0xBFFF0196UL)
-#define VI_ATTR_TCPIP_PORT          (0x3FFF0197UL)
-#define VI_ATTR_TCPIP_DEVICE_NAME   (0xBFFF0199UL)
-#define VI_ATTR_TCPIP_NODELAY       (0x3FFF019AUL)
-#define VI_ATTR_TCPIP_KEEPALIVE     (0x3FFF019BUL)
-#define VI_ATTR_4882_COMPLIANT      (0x3FFF019FUL)
-#define VI_ATTR_USB_SERIAL_NUM      (0xBFFF01A0UL)
-#define VI_ATTR_USB_INTFC_NUM       (0x3FFF01A1UL)
-#define VI_ATTR_USB_PROTOCOL        (0x3FFF01A7UL)
-#define VI_ATTR_USB_MAX_INTR_SIZE   (0x3FFF01AFUL)
-#define VI_ATTR_PXI_DEV_NUM         (0x3FFF0201UL)
-#define VI_ATTR_PXI_FUNC_NUM        (0x3FFF0202UL)
-#define VI_ATTR_PXI_BUS_NUM         (0x3FFF0205UL)
-#define VI_ATTR_PXI_CHASSIS         (0x3FFF0206UL)
-#define VI_ATTR_PXI_SLOTPATH        (0xBFFF0207UL)
-#define VI_ATTR_PXI_SLOT_LBUS_LEFT  (0x3FFF0208UL)
-#define VI_ATTR_PXI_SLOT_LBUS_RIGHT (0x3FFF0209UL)
-#define VI_ATTR_PXI_TRIG_BUS        (0x3FFF020AUL)
-#define VI_ATTR_PXI_STAR_TRIG_BUS   (0x3FFF020BUL)
-#define VI_ATTR_PXI_STAR_TRIG_LINE  (0x3FFF020CUL)
-#define VI_ATTR_PXI_MEM_TYPE_BAR0   (0x3FFF0211UL)
-#define VI_ATTR_PXI_MEM_TYPE_BAR1   (0x3FFF0212UL)
-#define VI_ATTR_PXI_MEM_TYPE_BAR2   (0x3FFF0213UL)
-#define VI_ATTR_PXI_MEM_TYPE_BAR3   (0x3FFF0214UL)
-#define VI_ATTR_PXI_MEM_TYPE_BAR4   (0x3FFF0215UL)
-#define VI_ATTR_PXI_MEM_TYPE_BAR5   (0x3FFF0216UL)
-#define VI_ATTR_PXI_MEM_BASE_BAR0   (0x3FFF0221UL)
-#define VI_ATTR_PXI_MEM_BASE_BAR1   (0x3FFF0222UL)
-#define VI_ATTR_PXI_MEM_BASE_BAR2   (0x3FFF0223UL)
-#define VI_ATTR_PXI_MEM_BASE_BAR3   (0x3FFF0224UL)
-#define VI_ATTR_PXI_MEM_BASE_BAR4   (0x3FFF0225UL)
-#define VI_ATTR_PXI_MEM_BASE_BAR5   (0x3FFF0226UL)
-#define VI_ATTR_PXI_MEM_SIZE_BAR0   (0x3FFF0231UL)
-#define VI_ATTR_PXI_MEM_SIZE_BAR1   (0x3FFF0232UL)
-#define VI_ATTR_PXI_MEM_SIZE_BAR2   (0x3FFF0233UL)
-#define VI_ATTR_PXI_MEM_SIZE_BAR3   (0x3FFF0234UL)
-#define VI_ATTR_PXI_MEM_SIZE_BAR4   (0x3FFF0235UL)
-#define VI_ATTR_PXI_MEM_SIZE_BAR5   (0x3FFF0236UL)
-#define VI_ATTR_PXI_IS_EXPRESS      (0x3FFF0240UL)
-#define VI_ATTR_PXI_SLOT_LWIDTH     (0x3FFF0241UL)
-#define VI_ATTR_PXI_MAX_LWIDTH      (0x3FFF0242UL)
-#define VI_ATTR_PXI_ACTUAL_LWIDTH   (0x3FFF0243UL)
-#define VI_ATTR_PXI_DSTAR_BUS       (0x3FFF0244UL)
-#define VI_ATTR_PXI_DSTAR_SET       (0x3FFF0245UL)
-
-#define VI_ATTR_JOB_ID              (0x3FFF4006UL)
-#define VI_ATTR_EVENT_TYPE          (0x3FFF4010UL)
-#define VI_ATTR_SIGP_STATUS_ID      (0x3FFF4011UL)
-#define VI_ATTR_RECV_TRIG_ID        (0x3FFF4012UL)
-#define VI_ATTR_INTR_STATUS_ID      (0x3FFF4023UL)
-#define VI_ATTR_STATUS              (0x3FFF4025UL)
-#define VI_ATTR_RET_COUNT_32        (0x3FFF4026UL)
-#define VI_ATTR_BUFFER              (0x3FFF4027UL)
-#define VI_ATTR_RECV_INTR_LEVEL     (0x3FFF4041UL)
-#define VI_ATTR_OPER_NAME           (0xBFFF4042UL)
-#define VI_ATTR_GPIB_RECV_CIC_STATE (0x3FFF4193UL)
-#define VI_ATTR_RECV_TCPIP_ADDR     (0xBFFF4198UL)
-#define VI_ATTR_USB_RECV_INTR_SIZE  (0x3FFF41B0UL)
-#define VI_ATTR_USB_RECV_INTR_DATA  (0xBFFF41B1UL)
-
-/*- Attributes (platform dependent size) ------------------------------------*/
-
-#if defined(_VI_INT64_UINT64_DEFINED) && defined(_VISA_ENV_IS_64_BIT)
-#define VI_ATTR_USER_DATA_64        (0x3FFF000AUL)
-#define VI_ATTR_RET_COUNT_64        (0x3FFF4028UL)
-#define VI_ATTR_USER_DATA           (VI_ATTR_USER_DATA_64)
-#define VI_ATTR_RET_COUNT           (VI_ATTR_RET_COUNT_64)
-#else
-#define VI_ATTR_USER_DATA           (VI_ATTR_USER_DATA_32)
-#define VI_ATTR_RET_COUNT           (VI_ATTR_RET_COUNT_32)
-#endif
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-#define VI_ATTR_WIN_BASE_ADDR_64    (0x3FFF009BUL)
-#define VI_ATTR_WIN_SIZE_64         (0x3FFF009CUL)
-#define VI_ATTR_MEM_BASE_64         (0x3FFF00D0UL)
-#define VI_ATTR_MEM_SIZE_64         (0x3FFF00D1UL)
-#endif
-#if defined(_VI_INT64_UINT64_DEFINED) && defined(_VISA_ENV_IS_64_BIT)
-#define VI_ATTR_WIN_BASE_ADDR       (VI_ATTR_WIN_BASE_ADDR_64)
-#define VI_ATTR_WIN_SIZE            (VI_ATTR_WIN_SIZE_64)
-#define VI_ATTR_MEM_BASE            (VI_ATTR_MEM_BASE_64)
-#define VI_ATTR_MEM_SIZE            (VI_ATTR_MEM_SIZE_64)
-#else
-#define VI_ATTR_WIN_BASE_ADDR       (VI_ATTR_WIN_BASE_ADDR_32)
-#define VI_ATTR_WIN_SIZE            (VI_ATTR_WIN_SIZE_32)
-#define VI_ATTR_MEM_BASE            (VI_ATTR_MEM_BASE_32)
-#define VI_ATTR_MEM_SIZE            (VI_ATTR_MEM_SIZE_32)
-#endif
-
-/*- Event Types -------------------------------------------------------------*/
-
-#define VI_EVENT_IO_COMPLETION      (0x3FFF2009UL)
-#define VI_EVENT_TRIG               (0xBFFF200AUL)
-#define VI_EVENT_SERVICE_REQ        (0x3FFF200BUL)
-#define VI_EVENT_CLEAR              (0x3FFF200DUL)
-#define VI_EVENT_EXCEPTION          (0xBFFF200EUL)
-#define VI_EVENT_GPIB_CIC           (0x3FFF2012UL)
-#define VI_EVENT_GPIB_TALK          (0x3FFF2013UL)
-#define VI_EVENT_GPIB_LISTEN        (0x3FFF2014UL)
-#define VI_EVENT_VXI_VME_SYSFAIL    (0x3FFF201DUL)
-#define VI_EVENT_VXI_VME_SYSRESET   (0x3FFF201EUL)
-#define VI_EVENT_VXI_SIGP           (0x3FFF2020UL)
-#define VI_EVENT_VXI_VME_INTR       (0xBFFF2021UL)
-#define VI_EVENT_PXI_INTR           (0x3FFF2022UL)
-#define VI_EVENT_TCPIP_CONNECT      (0x3FFF2036UL)
-#define VI_EVENT_USB_INTR           (0x3FFF2037UL)
-
-#define VI_ALL_ENABLED_EVENTS       (0x3FFF7FFFUL)
-
-/*- Completion and Error Codes ----------------------------------------------*/
-
-#define VI_SUCCESS_EVENT_EN                   (0x3FFF0002L) /* 3FFF0002,  1073676290 */
-#define VI_SUCCESS_EVENT_DIS                  (0x3FFF0003L) /* 3FFF0003,  1073676291 */
-#define VI_SUCCESS_QUEUE_EMPTY                (0x3FFF0004L) /* 3FFF0004,  1073676292 */
-#define VI_SUCCESS_TERM_CHAR                  (0x3FFF0005L) /* 3FFF0005,  1073676293 */
-#define VI_SUCCESS_MAX_CNT                    (0x3FFF0006L) /* 3FFF0006,  1073676294 */
-#define VI_SUCCESS_DEV_NPRESENT               (0x3FFF007DL) /* 3FFF007D,  1073676413 */
-#define VI_SUCCESS_TRIG_MAPPED                (0x3FFF007EL) /* 3FFF007E,  1073676414 */
-#define VI_SUCCESS_QUEUE_NEMPTY               (0x3FFF0080L) /* 3FFF0080,  1073676416 */
-#define VI_SUCCESS_NCHAIN                     (0x3FFF0098L) /* 3FFF0098,  1073676440 */
-#define VI_SUCCESS_NESTED_SHARED              (0x3FFF0099L) /* 3FFF0099,  1073676441 */
-#define VI_SUCCESS_NESTED_EXCLUSIVE           (0x3FFF009AL) /* 3FFF009A,  1073676442 */
-#define VI_SUCCESS_SYNC                       (0x3FFF009BL) /* 3FFF009B,  1073676443 */
-
-#define VI_WARN_QUEUE_OVERFLOW                (0x3FFF000CL) /* 3FFF000C,  1073676300 */
-#define VI_WARN_CONFIG_NLOADED                (0x3FFF0077L) /* 3FFF0077,  1073676407 */
-#define VI_WARN_NULL_OBJECT                   (0x3FFF0082L) /* 3FFF0082,  1073676418 */
-#define VI_WARN_NSUP_ATTR_STATE               (0x3FFF0084L) /* 3FFF0084,  1073676420 */
-#define VI_WARN_UNKNOWN_STATUS                (0x3FFF0085L) /* 3FFF0085,  1073676421 */
-#define VI_WARN_NSUP_BUF                      (0x3FFF0088L) /* 3FFF0088,  1073676424 */
-#define VI_WARN_EXT_FUNC_NIMPL                (0x3FFF00A9L) /* 3FFF00A9,  1073676457 */
-
-#define VI_ERROR_SYSTEM_ERROR       (_VI_ERROR+0x3FFF0000L) /* BFFF0000, -1073807360 */
-#define VI_ERROR_INV_OBJECT         (_VI_ERROR+0x3FFF000EL) /* BFFF000E, -1073807346 */
-#define VI_ERROR_RSRC_LOCKED        (_VI_ERROR+0x3FFF000FL) /* BFFF000F, -1073807345 */
-#define VI_ERROR_INV_EXPR           (_VI_ERROR+0x3FFF0010L) /* BFFF0010, -1073807344 */
-#define VI_ERROR_RSRC_NFOUND        (_VI_ERROR+0x3FFF0011L) /* BFFF0011, -1073807343 */
-#define VI_ERROR_INV_RSRC_NAME      (_VI_ERROR+0x3FFF0012L) /* BFFF0012, -1073807342 */
-#define VI_ERROR_INV_ACC_MODE       (_VI_ERROR+0x3FFF0013L) /* BFFF0013, -1073807341 */
-#define VI_ERROR_TMO                (_VI_ERROR+0x3FFF0015L) /* BFFF0015, -1073807339 */
-#define VI_ERROR_CLOSING_FAILED     (_VI_ERROR+0x3FFF0016L) /* BFFF0016, -1073807338 */
-#define VI_ERROR_INV_DEGREE         (_VI_ERROR+0x3FFF001BL) /* BFFF001B, -1073807333 */
-#define VI_ERROR_INV_JOB_ID         (_VI_ERROR+0x3FFF001CL) /* BFFF001C, -1073807332 */
-#define VI_ERROR_NSUP_ATTR          (_VI_ERROR+0x3FFF001DL) /* BFFF001D, -1073807331 */
-#define VI_ERROR_NSUP_ATTR_STATE    (_VI_ERROR+0x3FFF001EL) /* BFFF001E, -1073807330 */
-#define VI_ERROR_ATTR_READONLY      (_VI_ERROR+0x3FFF001FL) /* BFFF001F, -1073807329 */
-#define VI_ERROR_INV_LOCK_TYPE      (_VI_ERROR+0x3FFF0020L) /* BFFF0020, -1073807328 */
-#define VI_ERROR_INV_ACCESS_KEY     (_VI_ERROR+0x3FFF0021L) /* BFFF0021, -1073807327 */
-#define VI_ERROR_INV_EVENT          (_VI_ERROR+0x3FFF0026L) /* BFFF0026, -1073807322 */
-#define VI_ERROR_INV_MECH           (_VI_ERROR+0x3FFF0027L) /* BFFF0027, -1073807321 */
-#define VI_ERROR_HNDLR_NINSTALLED   (_VI_ERROR+0x3FFF0028L) /* BFFF0028, -1073807320 */
-#define VI_ERROR_INV_HNDLR_REF      (_VI_ERROR+0x3FFF0029L) /* BFFF0029, -1073807319 */
-#define VI_ERROR_INV_CONTEXT        (_VI_ERROR+0x3FFF002AL) /* BFFF002A, -1073807318 */
-#define VI_ERROR_QUEUE_OVERFLOW     (_VI_ERROR+0x3FFF002DL) /* BFFF002D, -1073807315 */
-#define VI_ERROR_NENABLED           (_VI_ERROR+0x3FFF002FL) /* BFFF002F, -1073807313 */
-#define VI_ERROR_ABORT              (_VI_ERROR+0x3FFF0030L) /* BFFF0030, -1073807312 */
-#define VI_ERROR_RAW_WR_PROT_VIOL   (_VI_ERROR+0x3FFF0034L) /* BFFF0034, -1073807308 */
-#define VI_ERROR_RAW_RD_PROT_VIOL   (_VI_ERROR+0x3FFF0035L) /* BFFF0035, -1073807307 */
-#define VI_ERROR_OUTP_PROT_VIOL     (_VI_ERROR+0x3FFF0036L) /* BFFF0036, -1073807306 */
-#define VI_ERROR_INP_PROT_VIOL      (_VI_ERROR+0x3FFF0037L) /* BFFF0037, -1073807305 */
-#define VI_ERROR_BERR               (_VI_ERROR+0x3FFF0038L) /* BFFF0038, -1073807304 */
-#define VI_ERROR_IN_PROGRESS        (_VI_ERROR+0x3FFF0039L) /* BFFF0039, -1073807303 */
-#define VI_ERROR_INV_SETUP          (_VI_ERROR+0x3FFF003AL) /* BFFF003A, -1073807302 */
-#define VI_ERROR_QUEUE_ERROR        (_VI_ERROR+0x3FFF003BL) /* BFFF003B, -1073807301 */
-#define VI_ERROR_ALLOC              (_VI_ERROR+0x3FFF003CL) /* BFFF003C, -1073807300 */
-#define VI_ERROR_INV_MASK           (_VI_ERROR+0x3FFF003DL) /* BFFF003D, -1073807299 */
-#define VI_ERROR_IO                 (_VI_ERROR+0x3FFF003EL) /* BFFF003E, -1073807298 */
-#define VI_ERROR_INV_FMT            (_VI_ERROR+0x3FFF003FL) /* BFFF003F, -1073807297 */
-#define VI_ERROR_NSUP_FMT           (_VI_ERROR+0x3FFF0041L) /* BFFF0041, -1073807295 */
-#define VI_ERROR_LINE_IN_USE        (_VI_ERROR+0x3FFF0042L) /* BFFF0042, -1073807294 */
-#define VI_ERROR_NSUP_MODE          (_VI_ERROR+0x3FFF0046L) /* BFFF0046, -1073807290 */
-#define VI_ERROR_SRQ_NOCCURRED      (_VI_ERROR+0x3FFF004AL) /* BFFF004A, -1073807286 */
-#define VI_ERROR_INV_SPACE          (_VI_ERROR+0x3FFF004EL) /* BFFF004E, -1073807282 */
-#define VI_ERROR_INV_OFFSET         (_VI_ERROR+0x3FFF0051L) /* BFFF0051, -1073807279 */
-#define VI_ERROR_INV_WIDTH          (_VI_ERROR+0x3FFF0052L) /* BFFF0052, -1073807278 */
-#define VI_ERROR_NSUP_OFFSET        (_VI_ERROR+0x3FFF0054L) /* BFFF0054, -1073807276 */
-#define VI_ERROR_NSUP_VAR_WIDTH     (_VI_ERROR+0x3FFF0055L) /* BFFF0055, -1073807275 */
-#define VI_ERROR_WINDOW_NMAPPED     (_VI_ERROR+0x3FFF0057L) /* BFFF0057, -1073807273 */
-#define VI_ERROR_RESP_PENDING       (_VI_ERROR+0x3FFF0059L) /* BFFF0059, -1073807271 */
-#define VI_ERROR_NLISTENERS         (_VI_ERROR+0x3FFF005FL) /* BFFF005F, -1073807265 */
-#define VI_ERROR_NCIC               (_VI_ERROR+0x3FFF0060L) /* BFFF0060, -1073807264 */
-#define VI_ERROR_NSYS_CNTLR         (_VI_ERROR+0x3FFF0061L) /* BFFF0061, -1073807263 */
-#define VI_ERROR_NSUP_OPER          (_VI_ERROR+0x3FFF0067L) /* BFFF0067, -1073807257 */
-#define VI_ERROR_INTR_PENDING       (_VI_ERROR+0x3FFF0068L) /* BFFF0068, -1073807256 */
-#define VI_ERROR_ASRL_PARITY        (_VI_ERROR+0x3FFF006AL) /* BFFF006A, -1073807254 */
-#define VI_ERROR_ASRL_FRAMING       (_VI_ERROR+0x3FFF006BL) /* BFFF006B, -1073807253 */
-#define VI_ERROR_ASRL_OVERRUN       (_VI_ERROR+0x3FFF006CL) /* BFFF006C, -1073807252 */
-#define VI_ERROR_TRIG_NMAPPED       (_VI_ERROR+0x3FFF006EL) /* BFFF006E, -1073807250 */
-#define VI_ERROR_NSUP_ALIGN_OFFSET  (_VI_ERROR+0x3FFF0070L) /* BFFF0070, -1073807248 */
-#define VI_ERROR_USER_BUF           (_VI_ERROR+0x3FFF0071L) /* BFFF0071, -1073807247 */
-#define VI_ERROR_RSRC_BUSY          (_VI_ERROR+0x3FFF0072L) /* BFFF0072, -1073807246 */
-#define VI_ERROR_NSUP_WIDTH         (_VI_ERROR+0x3FFF0076L) /* BFFF0076, -1073807242 */
-#define VI_ERROR_INV_PARAMETER      (_VI_ERROR+0x3FFF0078L) /* BFFF0078, -1073807240 */
-#define VI_ERROR_INV_PROT           (_VI_ERROR+0x3FFF0079L) /* BFFF0079, -1073807239 */
-#define VI_ERROR_INV_SIZE           (_VI_ERROR+0x3FFF007BL) /* BFFF007B, -1073807237 */
-#define VI_ERROR_WINDOW_MAPPED      (_VI_ERROR+0x3FFF0080L) /* BFFF0080, -1073807232 */
-#define VI_ERROR_NIMPL_OPER         (_VI_ERROR+0x3FFF0081L) /* BFFF0081, -1073807231 */
-#define VI_ERROR_INV_LENGTH         (_VI_ERROR+0x3FFF0083L) /* BFFF0083, -1073807229 */
-#define VI_ERROR_INV_MODE           (_VI_ERROR+0x3FFF0091L) /* BFFF0091, -1073807215 */
-#define VI_ERROR_SESN_NLOCKED       (_VI_ERROR+0x3FFF009CL) /* BFFF009C, -1073807204 */
-#define VI_ERROR_MEM_NSHARED        (_VI_ERROR+0x3FFF009DL) /* BFFF009D, -1073807203 */
-#define VI_ERROR_LIBRARY_NFOUND     (_VI_ERROR+0x3FFF009EL) /* BFFF009E, -1073807202 */
-#define VI_ERROR_NSUP_INTR          (_VI_ERROR+0x3FFF009FL) /* BFFF009F, -1073807201 */
-#define VI_ERROR_INV_LINE           (_VI_ERROR+0x3FFF00A0L) /* BFFF00A0, -1073807200 */
-#define VI_ERROR_FILE_ACCESS        (_VI_ERROR+0x3FFF00A1L) /* BFFF00A1, -1073807199 */
-#define VI_ERROR_FILE_IO            (_VI_ERROR+0x3FFF00A2L) /* BFFF00A2, -1073807198 */
-#define VI_ERROR_NSUP_LINE          (_VI_ERROR+0x3FFF00A3L) /* BFFF00A3, -1073807197 */
-#define VI_ERROR_NSUP_MECH          (_VI_ERROR+0x3FFF00A4L) /* BFFF00A4, -1073807196 */
-#define VI_ERROR_INTF_NUM_NCONFIG   (_VI_ERROR+0x3FFF00A5L) /* BFFF00A5, -1073807195 */
-#define VI_ERROR_CONN_LOST          (_VI_ERROR+0x3FFF00A6L) /* BFFF00A6, -1073807194 */
-#define VI_ERROR_MACHINE_NAVAIL     (_VI_ERROR+0x3FFF00A7L) /* BFFF00A7, -1073807193 */
-#define VI_ERROR_NPERMISSION        (_VI_ERROR+0x3FFF00A8L) /* BFFF00A8, -1073807192 */
-
-/*- Other VISA Definitions --------------------------------------------------*/
-
-#define VI_VERSION_MAJOR(ver)       ((((ViVersion)ver) & 0xFFF00000UL) >> 20)
-#define VI_VERSION_MINOR(ver)       ((((ViVersion)ver) & 0x000FFF00UL) >>  8)
-#define VI_VERSION_SUBMINOR(ver)    ((((ViVersion)ver) & 0x000000FFUL)      )
-
-#define VI_FIND_BUFLEN              (256)
-
-#define VI_INTF_GPIB                (1)
-#define VI_INTF_VXI                 (2)
-#define VI_INTF_GPIB_VXI            (3)
-#define VI_INTF_ASRL                (4)
-#define VI_INTF_PXI                 (5)
-#define VI_INTF_TCPIP               (6)
-#define VI_INTF_USB                 (7)
-
-#define VI_PROT_NORMAL              (1)
-#define VI_PROT_FDC                 (2)
-#define VI_PROT_HS488               (3)
-#define VI_PROT_4882_STRS           (4)
-#define VI_PROT_USBTMC_VENDOR       (5)
-
-#define VI_FDC_NORMAL               (1)
-#define VI_FDC_STREAM               (2)
-
-#define VI_LOCAL_SPACE              (0)
-#define VI_A16_SPACE                (1)
-#define VI_A24_SPACE                (2)
-#define VI_A32_SPACE                (3)
-#define VI_A64_SPACE                (4)
-#define VI_PXI_ALLOC_SPACE          (9)
-#define VI_PXI_CFG_SPACE            (10)
-#define VI_PXI_BAR0_SPACE           (11)
-#define VI_PXI_BAR1_SPACE           (12)
-#define VI_PXI_BAR2_SPACE           (13)
-#define VI_PXI_BAR3_SPACE           (14)
-#define VI_PXI_BAR4_SPACE           (15)
-#define VI_PXI_BAR5_SPACE           (16)
-#define VI_OPAQUE_SPACE             (0xFFFF)
-
-#define VI_UNKNOWN_LA               (-1)
-#define VI_UNKNOWN_SLOT             (-1)
-#define VI_UNKNOWN_LEVEL            (-1)
-#define VI_UNKNOWN_CHASSIS          (-1)
-
-#define VI_QUEUE                    (1)
-#define VI_HNDLR                    (2)
-#define VI_SUSPEND_HNDLR            (4)
-#define VI_ALL_MECH                 (0xFFFF)
-
-#define VI_ANY_HNDLR                (0)
-
-#define VI_TRIG_ALL                 (-2)
-#define VI_TRIG_SW                  (-1)
-#define VI_TRIG_TTL0                (0)
-#define VI_TRIG_TTL1                (1)
-#define VI_TRIG_TTL2                (2)
-#define VI_TRIG_TTL3                (3)
-#define VI_TRIG_TTL4                (4)
-#define VI_TRIG_TTL5                (5)
-#define VI_TRIG_TTL6                (6)
-#define VI_TRIG_TTL7                (7)
-#define VI_TRIG_ECL0                (8)
-#define VI_TRIG_ECL1                (9)
-#define VI_TRIG_PANEL_IN            (27)
-#define VI_TRIG_PANEL_OUT           (28)
-
-#define VI_TRIG_PROT_DEFAULT        (0)
-#define VI_TRIG_PROT_ON             (1)
-#define VI_TRIG_PROT_OFF            (2)
-#define VI_TRIG_PROT_SYNC           (5)
-#define VI_TRIG_PROT_RESERVE        (6)
-#define VI_TRIG_PROT_UNRESERVE      (7)
-
-#define VI_READ_BUF                 (1)
-#define VI_WRITE_BUF                (2)
-#define VI_READ_BUF_DISCARD         (4)
-#define VI_WRITE_BUF_DISCARD        (8)
-#define VI_IO_IN_BUF                (16)
-#define VI_IO_OUT_BUF               (32)
-#define VI_IO_IN_BUF_DISCARD        (64)
-#define VI_IO_OUT_BUF_DISCARD       (128)
-
-#define VI_FLUSH_ON_ACCESS          (1)
-#define VI_FLUSH_WHEN_FULL          (2)
-#define VI_FLUSH_DISABLE            (3)
-
-#define VI_NMAPPED                  (1)
-#define VI_USE_OPERS                (2)
-#define VI_DEREF_ADDR               (3)
-#define VI_DEREF_ADDR_BYTE_SWAP     (4)
-
-#define VI_TMO_IMMEDIATE            (0L)
-#define VI_TMO_INFINITE             (0xFFFFFFFFUL)
-
-#define VI_NO_LOCK                  (0)
-#define VI_EXCLUSIVE_LOCK           (1)
-#define VI_SHARED_LOCK              (2)
-#define VI_LOAD_CONFIG              (4)
-
-#define VI_NO_SEC_ADDR              (0xFFFF)
-
-#define VI_ASRL_PAR_NONE            (0)
-#define VI_ASRL_PAR_ODD             (1)
-#define VI_ASRL_PAR_EVEN            (2)
-#define VI_ASRL_PAR_MARK            (3)
-#define VI_ASRL_PAR_SPACE           (4)
-
-#define VI_ASRL_STOP_ONE            (10)
-#define VI_ASRL_STOP_ONE5           (15)
-#define VI_ASRL_STOP_TWO            (20)
-
-#define VI_ASRL_FLOW_NONE           (0)
-#define VI_ASRL_FLOW_XON_XOFF       (1)
-#define VI_ASRL_FLOW_RTS_CTS        (2)
-#define VI_ASRL_FLOW_DTR_DSR        (4)
-
-#define VI_ASRL_END_NONE            (0)
-#define VI_ASRL_END_LAST_BIT        (1)
-#define VI_ASRL_END_TERMCHAR        (2)
-#define VI_ASRL_END_BREAK           (3)
-
-#define VI_STATE_ASSERTED           (1)
-#define VI_STATE_UNASSERTED         (0)
-#define VI_STATE_UNKNOWN            (-1)
-
-#define VI_BIG_ENDIAN               (0)
-#define VI_LITTLE_ENDIAN            (1)
-
-#define VI_DATA_PRIV                (0)
-#define VI_DATA_NPRIV               (1)
-#define VI_PROG_PRIV                (2)
-#define VI_PROG_NPRIV               (3)
-#define VI_BLCK_PRIV                (4)
-#define VI_BLCK_NPRIV               (5)
-#define VI_D64_PRIV                 (6)
-#define VI_D64_NPRIV                (7)
-
-#define VI_WIDTH_8                  (1)
-#define VI_WIDTH_16                 (2)
-#define VI_WIDTH_32                 (4)
-#define VI_WIDTH_64                 (8)
-
-#define VI_GPIB_REN_DEASSERT        (0)
-#define VI_GPIB_REN_ASSERT          (1)
-#define VI_GPIB_REN_DEASSERT_GTL    (2)
-#define VI_GPIB_REN_ASSERT_ADDRESS  (3)
-#define VI_GPIB_REN_ASSERT_LLO      (4)
-#define VI_GPIB_REN_ASSERT_ADDRESS_LLO (5)
-#define VI_GPIB_REN_ADDRESS_GTL     (6)
-
-#define VI_GPIB_ATN_DEASSERT        (0)
-#define VI_GPIB_ATN_ASSERT          (1)
-#define VI_GPIB_ATN_DEASSERT_HANDSHAKE (2)
-#define VI_GPIB_ATN_ASSERT_IMMEDIATE (3)
-
-#define VI_GPIB_HS488_DISABLED      (0)
-#define VI_GPIB_HS488_NIMPL         (-1)
-
-#define VI_GPIB_UNADDRESSED         (0)
-#define VI_GPIB_TALKER              (1)
-#define VI_GPIB_LISTENER            (2)
-
-#define VI_VXI_CMD16                (0x0200)
-#define VI_VXI_CMD16_RESP16         (0x0202)
-#define VI_VXI_RESP16               (0x0002)
-#define VI_VXI_CMD32                (0x0400)
-#define VI_VXI_CMD32_RESP16         (0x0402)
-#define VI_VXI_CMD32_RESP32         (0x0404)
-#define VI_VXI_RESP32               (0x0004)
-
-#define VI_ASSERT_SIGNAL            (-1)
-#define VI_ASSERT_USE_ASSIGNED      (0)
-#define VI_ASSERT_IRQ1              (1)
-#define VI_ASSERT_IRQ2              (2)
-#define VI_ASSERT_IRQ3              (3)
-#define VI_ASSERT_IRQ4              (4)
-#define VI_ASSERT_IRQ5              (5)
-#define VI_ASSERT_IRQ6              (6)
-#define VI_ASSERT_IRQ7              (7)
-
-#define VI_UTIL_ASSERT_SYSRESET     (1)
-#define VI_UTIL_ASSERT_SYSFAIL      (2)
-#define VI_UTIL_DEASSERT_SYSFAIL    (3)
-
-#define VI_VXI_CLASS_MEMORY         (0)
-#define VI_VXI_CLASS_EXTENDED       (1)
-#define VI_VXI_CLASS_MESSAGE        (2)
-#define VI_VXI_CLASS_REGISTER       (3)
-#define VI_VXI_CLASS_OTHER          (4)
-
-#define VI_PXI_ADDR_NONE            (0)
-#define VI_PXI_ADDR_MEM             (1)
-#define VI_PXI_ADDR_IO              (2)
-#define VI_PXI_ADDR_CFG             (3)
-
-#define VI_TRIG_UNKNOWN             (-1)
-
-#define VI_PXI_LBUS_UNKNOWN         (-1)
-#define VI_PXI_LBUS_NONE            (0)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_0 (1000)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_1 (1001)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_2 (1002)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_3 (1003)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_4 (1004)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_5 (1005)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_6 (1006)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_7 (1007)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_8 (1008)
-#define VI_PXI_LBUS_STAR_TRIG_BUS_9 (1009)
-#define VI_PXI_STAR_TRIG_CONTROLLER (1413)
-
-/*- Backward Compatibility Macros -------------------------------------------*/
-
-#define viGetDefaultRM(vi)          viOpenDefaultRM(vi)
-#define VI_ERROR_INV_SESSION        (VI_ERROR_INV_OBJECT)
-#define VI_INFINITE                 (VI_TMO_INFINITE)
-#define VI_NORMAL                   (VI_PROT_NORMAL)
-#define VI_FDC                      (VI_PROT_FDC)
-#define VI_HS488                    (VI_PROT_HS488)
-#define VI_ASRL488                  (VI_PROT_4882_STRS)
-#define VI_ASRL_IN_BUF              (VI_IO_IN_BUF)
-#define VI_ASRL_OUT_BUF             (VI_IO_OUT_BUF)
-#define VI_ASRL_IN_BUF_DISCARD      (VI_IO_IN_BUF_DISCARD)
-#define VI_ASRL_OUT_BUF_DISCARD     (VI_IO_OUT_BUF_DISCARD)
-
-/*- National Instruments ----------------------------------------------------*/
-
-#define VI_INTF_RIO                 (8)
-#define VI_INTF_FIREWIRE            (9) 
-
-#define VI_ATTR_SYNC_MXI_ALLOW_EN   (0x3FFF0161UL) /* ViBoolean, read/write */
-
-/* This is for VXI SERVANT resources */
-
-#define VI_EVENT_VXI_DEV_CMD        (0xBFFF200FUL)
-#define VI_ATTR_VXI_DEV_CMD_TYPE    (0x3FFF4037UL) /* ViInt16, read-only */
-#define VI_ATTR_VXI_DEV_CMD_VALUE   (0x3FFF4038UL) /* ViUInt32, read-only */
-
-#define VI_VXI_DEV_CMD_TYPE_16      (16)
-#define VI_VXI_DEV_CMD_TYPE_32      (32)
-
-ViStatus _VI_FUNC viVxiServantResponse(ViSession vi, ViInt16 mode, ViUInt32 resp);
-/* mode values include VI_VXI_RESP16, VI_VXI_RESP32, and the next 2 values */
-#define VI_VXI_RESP_NONE            (0)
-#define VI_VXI_RESP_PROT_ERROR      (-1)
-
-/* This allows extended Serial support on Win32 and on NI ENET Serial products */
-
-#define VI_ATTR_ASRL_DISCARD_NULL   (0x3FFF00B0UL)
-#define VI_ATTR_ASRL_CONNECTED      (0x3FFF01BBUL)
-#define VI_ATTR_ASRL_BREAK_STATE    (0x3FFF01BCUL)
-#define VI_ATTR_ASRL_BREAK_LEN      (0x3FFF01BDUL)
-#define VI_ATTR_ASRL_ALLOW_TRANSMIT (0x3FFF01BEUL)
-#define VI_ATTR_ASRL_WIRE_MODE      (0x3FFF01BFUL)
-
-#define VI_ASRL_WIRE_485_4          (0)
-#define VI_ASRL_WIRE_485_2_DTR_ECHO (1)
-#define VI_ASRL_WIRE_485_2_DTR_CTRL (2)
-#define VI_ASRL_WIRE_485_2_AUTO     (3)
-#define VI_ASRL_WIRE_232_DTE        (128)
-#define VI_ASRL_WIRE_232_DCE        (129)
-#define VI_ASRL_WIRE_232_AUTO       (130)
-
-#define VI_EVENT_ASRL_BREAK         (0x3FFF2023UL)
-#define VI_EVENT_ASRL_CTS           (0x3FFF2029UL)
-#define VI_EVENT_ASRL_DSR           (0x3FFF202AUL)
-#define VI_EVENT_ASRL_DCD           (0x3FFF202CUL)
-#define VI_EVENT_ASRL_RI            (0x3FFF202EUL)
-#define VI_EVENT_ASRL_CHAR          (0x3FFF2035UL)
-#define VI_EVENT_ASRL_TERMCHAR      (0x3FFF2024UL)
-
-/* This is for fast viPeek/viPoke macros */
-
-#if defined(NIVISA_PEEKPOKE)
-
-#if defined(NIVISA_PEEKPOKE_SUPP)
-#undef NIVISA_PEEKPOKE_SUPP
-#endif
-
-#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(_NI_mswin16_)
-/* This macro is supported for all Win32 compilers, including CVI. */
-#define NIVISA_PEEKPOKE_SUPP
-#elif (defined(_WINDOWS) || defined(_Windows)) && !defined(_CVI_) && !defined(_NI_mswin16_)
-/* This macro is supported for Borland and Microsoft compilers on Win16, but not CVI. */
-#define NIVISA_PEEKPOKE_SUPP
-#elif defined(_CVI_) && defined(_NI_sparc_)
-/* This macro is supported for Solaris 1 and 2, from CVI only. */
-#define NIVISA_PEEKPOKE_SUPP
-#else
-/* This macro is not supported on other platforms. */
-#endif
-
-#if defined(NIVISA_PEEKPOKE_SUPP)
-
-extern ViBoolean NI_viImplVISA1;
-ViStatus _VI_FUNC NI_viOpenDefaultRM (ViPSession vi);
-#define viOpenDefaultRM(vi) NI_viOpenDefaultRM(vi)
-
-#define viPeek8(vi,addr,val)                                                \
-   {                                                                        \
-      if ((NI_viImplVISA1) && (*((ViPUInt32)(vi))))                         \
-      {                                                                     \
-         do (*((ViPUInt8)(val)) = *((volatile ViUInt8 _VI_PTR)(addr)));     \
-         while (**((volatile ViUInt8 _VI_PTR _VI_PTR)(vi)) & 0x10);         \
-      }                                                                     \
-      else                                                                  \
-      {                                                                     \
-         (viPeek8)((vi),(addr),(val));                                      \
-      }                                                                     \
-   }
-
-#define viPoke8(vi,addr,val)                                                \
-   {                                                                        \
-      if ((NI_viImplVISA1) && (*((ViPUInt32)(vi))))                         \
-      {                                                                     \
-         do (*((volatile ViUInt8 _VI_PTR)(addr)) = ((ViUInt8)(val)));       \
-         while (**((volatile ViUInt8 _VI_PTR _VI_PTR)(vi)) & 0x10);         \
-      }                                                                     \
-      else                                                                  \
-      {                                                                     \
-         (viPoke8)((vi),(addr),(val));                                      \
-      }                                                                     \
-   }
-
-#define viPeek16(vi,addr,val)                                               \
-   {                                                                        \
-      if ((NI_viImplVISA1) && (*((ViPUInt32)(vi))))                         \
-      {                                                                     \
-         do (*((ViPUInt16)(val)) = *((volatile ViUInt16 _VI_PTR)(addr)));   \
-         while (**((volatile ViUInt8 _VI_PTR _VI_PTR)(vi)) & 0x10);         \
-      }                                                                     \
-      else                                                                  \
-      {                                                                     \
-         (viPeek16)((vi),(addr),(val));                                     \
-      }                                                                     \
-   }
-
-#define viPoke16(vi,addr,val)                                               \
-   {                                                                        \
-      if ((NI_viImplVISA1) && (*((ViPUInt32)(vi))))                         \
-      {                                                                     \
-         do (*((volatile ViUInt16 _VI_PTR)(addr)) = ((ViUInt16)(val)));     \
-         while (**((volatile ViUInt8 _VI_PTR _VI_PTR)(vi)) & 0x10);         \
-      }                                                                     \
-      else                                                                  \
-      {                                                                     \
-         (viPoke16)((vi),(addr),(val));                                     \
-      }                                                                     \
-   }
-
-#define viPeek32(vi,addr,val)                                               \
-   {                                                                        \
-      if ((NI_viImplVISA1) && (*((ViPUInt32)(vi))))                         \
-      {                                                                     \
-         do (*((ViPUInt32)(val)) = *((volatile ViUInt32 _VI_PTR)(addr)));   \
-         while (**((volatile ViUInt8 _VI_PTR _VI_PTR)(vi)) & 0x10);         \
-      }                                                                     \
-      else                                                                  \
-      {                                                                     \
-         (viPeek32)((vi),(addr),(val));                                     \
-      }                                                                     \
-   }
-
-#define viPoke32(vi,addr,val)                                               \
-   {                                                                        \
-      if ((NI_viImplVISA1) && (*((ViPUInt32)(vi))))                         \
-      {                                                                     \
-         do (*((volatile ViUInt32 _VI_PTR)(addr)) = ((ViUInt32)(val)));     \
-         while (**((volatile ViUInt8 _VI_PTR _VI_PTR)(vi)) & 0x10);         \
-      }                                                                     \
-      else                                                                  \
-      {                                                                     \
-         (viPoke32)((vi),(addr),(val));                                     \
-      }                                                                     \
-   }
-
-#endif
-
-#endif
-
-#if defined(NIVISA_PXI) || defined(PXISAVISA_PXI)
-
-#if 0
-/* The following 2 attributes were incorrectly implemented in earlier
-   versions of NI-VISA.  You should now query VI_ATTR_MANF_ID or
-   VI_ATTR_MODEL_CODE.  Those attributes contain sub-vendor information
-   when it exists.  To get both the actual primary and subvendor codes
-   from the device, you should call viIn16 using VI_PXI_CFG_SPACE. */
-#define VI_ATTR_PXI_SUB_MANF_ID     (0x3FFF0203UL)
-#define VI_ATTR_PXI_SUB_MODEL_CODE  (0x3FFF0204UL)
-#endif
-
-#define VI_ATTR_PXI_SRC_TRIG_BUS    (0x3FFF020DUL)
-#define VI_ATTR_PXI_DEST_TRIG_BUS   (0x3FFF020EUL)
-
-#define VI_ATTR_PXI_RECV_INTR_SEQ   (0x3FFF4240UL)
-#define VI_ATTR_PXI_RECV_INTR_DATA  (0x3FFF4241UL)
-
-#endif
-
-#if defined(NIVISA_USB)
-
-#define VI_ATTR_USB_BULK_OUT_PIPE   (0x3FFF01A2UL)
-#define VI_ATTR_USB_BULK_IN_PIPE    (0x3FFF01A3UL)
-#define VI_ATTR_USB_INTR_IN_PIPE    (0x3FFF01A4UL)
-#define VI_ATTR_USB_CLASS           (0x3FFF01A5UL)
-#define VI_ATTR_USB_SUBCLASS        (0x3FFF01A6UL)
-#define VI_ATTR_USB_ALT_SETTING     (0x3FFF01A8UL)
-#define VI_ATTR_USB_END_IN          (0x3FFF01A9UL)
-#define VI_ATTR_USB_NUM_INTFCS      (0x3FFF01AAUL)
-#define VI_ATTR_USB_NUM_PIPES       (0x3FFF01ABUL)
-#define VI_ATTR_USB_BULK_OUT_STATUS (0x3FFF01ACUL)
-#define VI_ATTR_USB_BULK_IN_STATUS  (0x3FFF01ADUL)
-#define VI_ATTR_USB_INTR_IN_STATUS  (0x3FFF01AEUL)
-#define VI_ATTR_USB_CTRL_PIPE       (0x3FFF01B0UL)
-
-#define VI_USB_PIPE_STATE_UNKNOWN   (-1)
-#define VI_USB_PIPE_READY           (0)
-#define VI_USB_PIPE_STALLED         (1)
-
-#define VI_USB_END_NONE             (0)
-#define VI_USB_END_SHORT            (4)
-#define VI_USB_END_SHORT_OR_COUNT   (5)
-
-#endif
-
-#define VI_ATTR_FIREWIRE_DEST_UPPER_OFFSET (0x3FFF01F0UL)
-#define VI_ATTR_FIREWIRE_SRC_UPPER_OFFSET  (0x3FFF01F1UL)
-#define VI_ATTR_FIREWIRE_WIN_UPPER_OFFSET  (0x3FFF01F2UL)
-#define VI_ATTR_FIREWIRE_VENDOR_ID         (0x3FFF01F3UL)
-#define VI_ATTR_FIREWIRE_LOWER_CHIP_ID     (0x3FFF01F4UL)
-#define VI_ATTR_FIREWIRE_UPPER_CHIP_ID     (0x3FFF01F5UL)
-
-#define VI_FIREWIRE_DFLT_SPACE           (5)
-
-#if defined(__cplusplus) || defined(__cplusplus__)
-   }
-#endif
-
-#endif
-
-/*- The End -----------------------------------------------------------------*/
diff --git a/hal/src/main/native/athena/visa/visatype.h b/hal/src/main/native/athena/visa/visatype.h
deleted file mode 100644
index ef089dd..0000000
--- a/hal/src/main/native/athena/visa/visatype.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*---------------------------------------------------------------------------*/
-/* Distributed by IVI Foundation Inc.                                        */
-/*                                                                           */
-/* Do not modify the contents of this file.                                  */
-/*---------------------------------------------------------------------------*/
-/*                                                                           */
-/* Title   : VISATYPE.H                                                      */
-/* Date    : 04-14-2006                                                      */
-/* Purpose : Fundamental VISA data types and macro definitions               */
-/*                                                                           */
-/*---------------------------------------------------------------------------*/
-
-#ifndef __VISATYPE_HEADER__
-#define __VISATYPE_HEADER__
-
-#if defined(_WIN64)
-#define _VI_FAR
-#define _VI_FUNC            __fastcall
-#define _VI_FUNCC           __fastcall
-#define _VI_FUNCH           __fastcall
-#define _VI_SIGNED          signed
-#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(_NI_mswin16_)
-#define _VI_FAR
-#define _VI_FUNC            __stdcall
-#define _VI_FUNCC           __cdecl
-#define _VI_FUNCH           __stdcall
-#define _VI_SIGNED          signed
-#elif defined(_CVI_) && defined(_NI_i386_)
-#define _VI_FAR
-#define _VI_FUNC            _pascal
-#define _VI_FUNCC
-#define _VI_FUNCH           _pascal
-#define _VI_SIGNED          signed
-#elif (defined(_WINDOWS) || defined(_Windows)) && !defined(_NI_mswin16_)
-#define _VI_FAR             _far
-#define _VI_FUNC            _far _pascal _export
-#define _VI_FUNCC           _far _cdecl  _export
-#define _VI_FUNCH           _far _pascal
-#define _VI_SIGNED          signed
-#elif (defined(hpux) || defined(__hpux)) && (defined(__cplusplus) || defined(__cplusplus__))
-#define _VI_FAR
-#define _VI_FUNC
-#define _VI_FUNCC
-#define _VI_FUNCH
-#define _VI_SIGNED
-#else
-#define _VI_FAR
-#define _VI_FUNC
-#define _VI_FUNCC
-#define _VI_FUNCH
-#define _VI_SIGNED          signed
-#endif
-
-#define _VI_ERROR           (-2147483647L-1)  /* 0x80000000 */
-#define _VI_PTR             _VI_FAR *
-
-/*- VISA Types --------------------------------------------------------------*/
-
-#ifndef _VI_INT64_UINT64_DEFINED
-#if defined(_WIN64) || ((defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(_NI_mswin16_))
-#if (defined(_MSC_VER) && (_MSC_VER >= 1200)) || (defined(_CVI_) && (_CVI_ >= 700)) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0520))
-typedef unsigned   __int64  ViUInt64;
-typedef _VI_SIGNED __int64  ViInt64;
-#define _VI_INT64_UINT64_DEFINED
-#if defined(_WIN64)
-#define _VISA_ENV_IS_64_BIT
-#else
-/* This is a 32-bit OS, not a 64-bit OS */
-#endif
-#endif
-#elif defined(__GNUC__) && (__GNUC__ >= 3)
-#include <limits.h>
-#include <sys/types.h>
-typedef u_int64_t           ViUInt64;
-typedef int64_t             ViInt64;
-#define _VI_INT64_UINT64_DEFINED
-#if defined(LONG_MAX) && (LONG_MAX > 0x7FFFFFFFL)
-#define _VISA_ENV_IS_64_BIT
-#else
-/* This is a 32-bit OS, not a 64-bit OS */
-#endif
-#else
-/* This platform does not support 64-bit types */
-#endif
-#endif
-
-#if defined(_VI_INT64_UINT64_DEFINED)
-typedef ViUInt64    _VI_PTR ViPUInt64;
-typedef ViUInt64    _VI_PTR ViAUInt64;
-typedef ViInt64     _VI_PTR ViPInt64;
-typedef ViInt64     _VI_PTR ViAInt64;
-#endif
-
-#if defined(LONG_MAX) && (LONG_MAX > 0x7FFFFFFFL)
-typedef unsigned int        ViUInt32;
-typedef _VI_SIGNED int      ViInt32;
-#else
-typedef unsigned long       ViUInt32;
-typedef _VI_SIGNED long     ViInt32;
-#endif
-
-typedef ViUInt32    _VI_PTR ViPUInt32;
-typedef ViUInt32    _VI_PTR ViAUInt32;
-typedef ViInt32     _VI_PTR ViPInt32;
-typedef ViInt32     _VI_PTR ViAInt32;
-
-typedef unsigned short      ViUInt16;
-typedef ViUInt16    _VI_PTR ViPUInt16;
-typedef ViUInt16    _VI_PTR ViAUInt16;
-
-typedef _VI_SIGNED short    ViInt16;
-typedef ViInt16     _VI_PTR ViPInt16;
-typedef ViInt16     _VI_PTR ViAInt16;
-
-typedef unsigned char       ViUInt8;
-typedef ViUInt8     _VI_PTR ViPUInt8;
-typedef ViUInt8     _VI_PTR ViAUInt8;
-
-typedef _VI_SIGNED char     ViInt8;
-typedef ViInt8      _VI_PTR ViPInt8;
-typedef ViInt8      _VI_PTR ViAInt8;
-
-typedef char                ViChar;
-typedef ViChar      _VI_PTR ViPChar;
-typedef ViChar      _VI_PTR ViAChar;
-
-typedef unsigned char       ViByte;
-typedef ViByte      _VI_PTR ViPByte;
-typedef ViByte      _VI_PTR ViAByte;
-
-typedef void        _VI_PTR ViAddr;
-typedef ViAddr      _VI_PTR ViPAddr;
-typedef ViAddr      _VI_PTR ViAAddr;
-
-typedef float               ViReal32;
-typedef ViReal32    _VI_PTR ViPReal32;
-typedef ViReal32    _VI_PTR ViAReal32;
-
-typedef double              ViReal64;
-typedef ViReal64    _VI_PTR ViPReal64;
-typedef ViReal64    _VI_PTR ViAReal64;
-
-typedef ViPByte             ViBuf;
-typedef ViPByte             ViPBuf;
-typedef ViPByte     _VI_PTR ViABuf;
-
-typedef ViPChar             ViString;
-typedef ViPChar             ViPString;
-typedef ViPChar     _VI_PTR ViAString;
-
-typedef ViString            ViRsrc;
-typedef ViString            ViPRsrc;
-typedef ViString    _VI_PTR ViARsrc;
-
-typedef ViUInt16            ViBoolean;
-typedef ViBoolean   _VI_PTR ViPBoolean;
-typedef ViBoolean   _VI_PTR ViABoolean;
-
-typedef ViInt32             ViStatus;
-typedef ViStatus    _VI_PTR ViPStatus;
-typedef ViStatus    _VI_PTR ViAStatus;
-
-typedef ViUInt32            ViVersion;
-typedef ViVersion   _VI_PTR ViPVersion;
-typedef ViVersion   _VI_PTR ViAVersion;
-
-typedef ViUInt32            ViObject;
-typedef ViObject    _VI_PTR ViPObject;
-typedef ViObject    _VI_PTR ViAObject;
-
-typedef ViObject            ViSession;
-typedef ViSession   _VI_PTR ViPSession;
-typedef ViSession   _VI_PTR ViASession;
-
-typedef ViUInt32             ViAttr;
-
-#ifndef _VI_CONST_STRING_DEFINED
-typedef const ViChar * ViConstString;
-#define _VI_CONST_STRING_DEFINED
-#endif  
-
-/*- Completion and Error Codes ----------------------------------------------*/
-
-#define VI_SUCCESS          (0L)
-
-/*- Other VISA Definitions --------------------------------------------------*/
-
-#define VI_NULL             (0)
-
-#define VI_TRUE             (1)
-#define VI_FALSE            (0)
-
-/*- Backward Compatibility Macros -------------------------------------------*/
-
-#define VISAFN              _VI_FUNC
-#define ViPtr               _VI_PTR
-
-#endif
-
-/*- The End -----------------------------------------------------------------*/
-
diff --git a/hal/src/main/native/cpp/Main.cpp b/hal/src/main/native/cpp/Main.cpp
new file mode 100644
index 0000000..a37c2b0
--- /dev/null
+++ b/hal/src/main/native/cpp/Main.cpp
@@ -0,0 +1,64 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Main.h"
+
+#include <wpi/condition_variable.h>
+#include <wpi/mutex.h>
+
+static void DefaultMain(void*);
+static void DefaultExit(void*);
+
+static bool gHasMain = false;
+static void* gMainParam = nullptr;
+static void (*gMainFunc)(void*) = DefaultMain;
+static void (*gExitFunc)(void*) = DefaultExit;
+static bool gExited = false;
+struct MainObj {
+  wpi::mutex gExitMutex;
+  wpi::condition_variable gExitCv;
+};
+
+static MainObj* mainObj;
+
+static void DefaultMain(void*) {
+  std::unique_lock lock{mainObj->gExitMutex};
+  mainObj->gExitCv.wait(lock, [] { return gExited; });
+}
+
+static void DefaultExit(void*) {
+  std::lock_guard lock{mainObj->gExitMutex};
+  gExited = true;
+  mainObj->gExitCv.notify_all();
+}
+
+namespace hal {
+namespace init {
+void InitializeMain() {
+  static MainObj mO;
+  mainObj = &mO;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+void HAL_SetMain(void* param, void (*mainFunc)(void*),
+                 void (*exitFunc)(void*)) {
+  gHasMain = true;
+  gMainParam = param;
+  gMainFunc = mainFunc;
+  gExitFunc = exitFunc;
+}
+
+HAL_Bool HAL_HasMain(void) { return gHasMain; }
+
+void HAL_RunMain(void) { gMainFunc(gMainParam); }
+
+void HAL_ExitMain(void) { gExitFunc(gMainParam); }
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/cpp/fpga_clock.cpp b/hal/src/main/native/cpp/cpp/fpga_clock.cpp
index 751eae1..bcec155 100644
--- a/hal/src/main/native/cpp/cpp/fpga_clock.cpp
+++ b/hal/src/main/native/cpp/cpp/fpga_clock.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -21,8 +21,9 @@
   uint64_t currentTime = HAL_GetFPGATime(&status);
   if (status != 0) {
     wpi::errs()
-        << "Call to HAL_GetFPGATime failed."
-        << "Initialization might have failed. Time will not be correct\n";
+        << "Call to HAL_GetFPGATime failed in fpga_clock::now() with status "
+        << status
+        << ". Initialization might have failed. Time will not be correct\n";
     wpi::errs().flush();
     return epoch();
   }
diff --git a/hal/src/main/native/cpp/handles/HandlesInternal.cpp b/hal/src/main/native/cpp/handles/HandlesInternal.cpp
index 45ffb31..5e66ce1 100644
--- a/hal/src/main/native/cpp/handles/HandlesInternal.cpp
+++ b/hal/src/main/native/cpp/handles/HandlesInternal.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -17,7 +17,7 @@
 static wpi::mutex globalHandleMutex;
 HandleBase::HandleBase() {
   static wpi::SmallVector<HandleBase*, 32> gH;
-  std::lock_guard<wpi::mutex> lock(globalHandleMutex);
+  std::scoped_lock lock(globalHandleMutex);
   if (!globalHandles) {
     globalHandles = &gH;
   }
@@ -30,7 +30,7 @@
   }
 }
 HandleBase::~HandleBase() {
-  std::lock_guard<wpi::mutex> lock(globalHandleMutex);
+  std::scoped_lock lock(globalHandleMutex);
   auto index = std::find(globalHandles->begin(), globalHandles->end(), this);
   if (index != globalHandles->end()) {
     *index = nullptr;
@@ -43,7 +43,7 @@
   }
 }
 void HandleBase::ResetGlobalHandles() {
-  std::unique_lock<wpi::mutex> lock(globalHandleMutex);
+  std::unique_lock lock(globalHandleMutex);
   for (auto&& i : *globalHandles) {
     if (i != nullptr) {
       lock.unlock();
diff --git a/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
index 74c1b49..35b7414 100644
--- a/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
+++ b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -12,20 +12,10 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_AnalogGyroJNI.h"
 #include "hal/AnalogGyro.h"
-#include "hal/cpp/Log.h"
 #include "hal/handles/HandlesInternal.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel analogGyroJNILogLevel = logWARNING;
-
-#define ANALOGGYROJNI_LOG(level)     \
-  if (level > analogGyroJNILogLevel) \
-    ;                                \
-  else                               \
-    Log().Get(level)
-
 extern "C" {
 /*
  * Class:     edu_wpi_first_hal_AnalogGyroJNI
@@ -36,14 +26,9 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_initializeAnalogGyro
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI initializeAnalogGyro";
-  ANALOGGYROJNI_LOG(logDEBUG)
-      << "Analog Input Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   HAL_GyroHandle handle =
       HAL_InitializeAnalogGyro((HAL_AnalogInputHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << handle;
   // Analog input does range checking, so we don't need to do so.
   CheckStatusForceThrow(env, status);
   return (jint)handle;
@@ -58,11 +43,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_setupAnalogGyro
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI setupAnalogGyro";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   HAL_SetupAnalogGyro((HAL_GyroHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -75,8 +57,6 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_freeAnalogGyro
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI freeAnalogGyro";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   HAL_FreeAnalogGyro((HAL_GyroHandle)id);
 }
 
@@ -89,13 +69,9 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_setAnalogGyroParameters
   (JNIEnv* env, jclass, jint id, jdouble vPDPS, jdouble offset, jint center)
 {
-  ANALOGGYROJNI_LOG(logDEBUG)
-      << "Calling ANALOGGYROJNI setAnalogGyroParameters";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   HAL_SetAnalogGyroParameters((HAL_GyroHandle)id, vPDPS, offset, center,
                               &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -108,13 +84,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_setAnalogGyroVoltsPerDegreePerSecond
   (JNIEnv* env, jclass, jint id, jdouble vPDPS)
 {
-  ANALOGGYROJNI_LOG(logDEBUG)
-      << "Calling ANALOGGYROJNI setAnalogGyroVoltsPerDegreePerSecond";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
-  ANALOGGYROJNI_LOG(logDEBUG) << "vPDPS = " << vPDPS;
   int32_t status = 0;
   HAL_SetAnalogGyroVoltsPerDegreePerSecond((HAL_GyroHandle)id, vPDPS, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -127,11 +98,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_resetAnalogGyro
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI resetAnalogGyro";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   HAL_ResetAnalogGyro((HAL_GyroHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -144,11 +112,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_calibrateAnalogGyro
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI calibrateAnalogGyro";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   HAL_CalibrateAnalogGyro((HAL_GyroHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -161,11 +126,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_setAnalogGyroDeadband
   (JNIEnv* env, jclass, jint id, jdouble deadband)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI setAnalogGyroDeadband";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   HAL_SetAnalogGyroDeadband((HAL_GyroHandle)id, deadband, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -178,12 +140,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_getAnalogGyroAngle
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI getAnalogGyroAngle";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   jdouble value = HAL_GetAnalogGyroAngle((HAL_GyroHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGGYROJNI_LOG(logDEBUG) << "Result = " << value;
   CheckStatus(env, status);
   return value;
 }
@@ -197,12 +155,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_getAnalogGyroRate
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI getAnalogGyroRate";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   jdouble value = HAL_GetAnalogGyroRate((HAL_GyroHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGGYROJNI_LOG(logDEBUG) << "Result = " << value;
   CheckStatus(env, status);
   return value;
 }
@@ -216,12 +170,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_getAnalogGyroOffset
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI getAnalogGyroOffset";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   jdouble value = HAL_GetAnalogGyroOffset((HAL_GyroHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGGYROJNI_LOG(logDEBUG) << "Result = " << value;
   CheckStatus(env, status);
   return value;
 }
@@ -235,12 +185,8 @@
 Java_edu_wpi_first_hal_AnalogGyroJNI_getAnalogGyroCenter
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGGYROJNI_LOG(logDEBUG) << "Calling ANALOGGYROJNI getAnalogGyroCenter";
-  ANALOGGYROJNI_LOG(logDEBUG) << "Gyro Handle = " << (HAL_GyroHandle)id;
   int32_t status = 0;
   jint value = HAL_GetAnalogGyroCenter((HAL_GyroHandle)id, &status);
-  ANALOGGYROJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGGYROJNI_LOG(logDEBUG) << "Result = " << value;
   CheckStatus(env, status);
   return value;
 }
diff --git a/hal/src/main/native/cpp/jni/AnalogJNI.cpp b/hal/src/main/native/cpp/jni/AnalogJNI.cpp
index 3b2aa2d..abd614f 100644
--- a/hal/src/main/native/cpp/jni/AnalogJNI.cpp
+++ b/hal/src/main/native/cpp/jni/AnalogJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -16,20 +16,10 @@
 #include "hal/AnalogOutput.h"
 #include "hal/AnalogTrigger.h"
 #include "hal/Ports.h"
-#include "hal/cpp/Log.h"
 #include "hal/handles/HandlesInternal.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel analogJNILogLevel = logWARNING;
-
-#define ANALOGJNI_LOG(level)     \
-  if (level > analogJNILogLevel) \
-    ;                            \
-  else                           \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -41,11 +31,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_initializeAnalogInputPort
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_PortHandle)id;
   int32_t status = 0;
   auto analog = HAL_InitializeAnalogInputPort((HAL_PortHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << analog;
   CheckStatusRange(env, status, 0, HAL_GetNumAnalogInputs(),
                    hal::getPortHandleChannel((HAL_PortHandle)id));
   return (jint)analog;
@@ -60,7 +47,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_freeAnalogInputPort
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_AnalogInputHandle)id;
   HAL_FreeAnalogInputPort((HAL_AnalogInputHandle)id);
 }
 
@@ -73,12 +59,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_initializeAnalogOutputPort
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_PortHandle)id;
   int32_t status = 0;
   HAL_AnalogOutputHandle analog =
       HAL_InitializeAnalogOutputPort((HAL_PortHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << analog;
   CheckStatusRange(env, status, 0, HAL_GetNumAnalogOutputs(),
                    hal::getPortHandleChannel((HAL_PortHandle)id));
   return (jlong)analog;
@@ -93,7 +76,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_freeAnalogOutputPort
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << id;
   HAL_FreeAnalogOutputPort((HAL_AnalogOutputHandle)id);
 }
 
@@ -106,10 +88,7 @@
 Java_edu_wpi_first_hal_AnalogJNI_checkAnalogModule
   (JNIEnv*, jclass, jbyte value)
 {
-  // ANALOGJNI_LOG(logDEBUG) << "Module = " << (jint)value;
   jboolean returnValue = HAL_CheckAnalogModule(value);
-  // ANALOGJNI_LOG(logDEBUG) << "checkAnalogModuleResult = " <<
-  // (jint)returnValue;
   return returnValue;
 }
 
@@ -122,10 +101,7 @@
 Java_edu_wpi_first_hal_AnalogJNI_checkAnalogInputChannel
   (JNIEnv*, jclass, jint value)
 {
-  // ANALOGJNI_LOG(logDEBUG) << "Channel = " << value;
   jboolean returnValue = HAL_CheckAnalogInputChannel(value);
-  // ANALOGJNI_LOG(logDEBUG) << "checkAnalogChannelResult = " <<
-  // (jint)returnValue;
   return returnValue;
 }
 
@@ -138,15 +114,25 @@
 Java_edu_wpi_first_hal_AnalogJNI_checkAnalogOutputChannel
   (JNIEnv*, jclass, jint value)
 {
-  // ANALOGJNI_LOG(logDEBUG) << "Channel = " << value;
   jboolean returnValue = HAL_CheckAnalogOutputChannel(value);
-  // ANALOGJNI_LOG(logDEBUG) << "checkAnalogChannelResult = " <<
-  // (jint)returnValue;
   return returnValue;
 }
 
 /*
  * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogInputSimDevice
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_AnalogJNI_setAnalogInputSimDevice
+  (JNIEnv* env, jclass, jint handle, jint device)
+{
+  HAL_SetAnalogInputSimDevice((HAL_AnalogInputHandle)handle,
+                              (HAL_SimDeviceHandle)device);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
  * Method:    setAnalogOutput
  * Signature: (ID)V
  */
@@ -154,9 +140,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogOutput
   (JNIEnv* env, jclass, jint id, jdouble voltage)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Calling setAnalogOutput";
-  ANALOGJNI_LOG(logDEBUG) << "Voltage = " << voltage;
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << id;
   int32_t status = 0;
   HAL_SetAnalogOutput((HAL_AnalogOutputHandle)id, voltage, &status);
   CheckStatus(env, status);
@@ -186,10 +169,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogSampleRate
   (JNIEnv* env, jclass, jdouble value)
 {
-  ANALOGJNI_LOG(logDEBUG) << "SampleRate = " << value;
   int32_t status = 0;
   HAL_SetAnalogSampleRate(value, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -204,8 +185,6 @@
 {
   int32_t status = 0;
   double returnValue = HAL_GetAnalogSampleRate(&status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "SampleRate = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -219,11 +198,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogAverageBits
   (JNIEnv* env, jclass, jint id, jint value)
 {
-  ANALOGJNI_LOG(logDEBUG) << "AverageBits = " << value;
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   HAL_SetAnalogAverageBits((HAL_AnalogInputHandle)id, value, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -236,12 +212,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogAverageBits
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetAnalogAverageBits((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AverageBits = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -255,11 +228,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogOversampleBits
   (JNIEnv* env, jclass, jint id, jint value)
 {
-  ANALOGJNI_LOG(logDEBUG) << "OversampleBits = " << value;
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   HAL_SetAnalogOversampleBits((HAL_AnalogInputHandle)id, value, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -272,12 +242,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogOversampleBits
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetAnalogOversampleBits((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "OversampleBits = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -291,11 +258,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogValue
   (JNIEnv* env, jclass, jint id)
 {
-  // ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (void*)id;
   int32_t status = 0;
   jshort returnValue = HAL_GetAnalogValue((HAL_AnalogInputHandle)id, &status);
-  // ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  // ANALOGJNI_LOG(logDEBUG) << "Value = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -309,12 +273,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogAverageValue
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetAnalogAverageValue((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AverageValue = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -328,13 +289,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogVoltsToValue
   (JNIEnv* env, jclass, jint id, jdouble voltageValue)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
-  ANALOGJNI_LOG(logDEBUG) << "VoltageValue = " << voltageValue;
   int32_t status = 0;
   jint returnValue = HAL_GetAnalogVoltsToValue((HAL_AnalogInputHandle)id,
                                                voltageValue, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "Value = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -348,12 +305,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogVoltage
   (JNIEnv* env, jclass, jint id)
 {
-  // ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (void*)id;
   int32_t status = 0;
   jdouble returnValue =
       HAL_GetAnalogVoltage((HAL_AnalogInputHandle)id, &status);
-  // ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  // ANALOGJNI_LOG(logDEBUG) << "Voltage = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -367,12 +321,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogAverageVoltage
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   jdouble returnValue =
       HAL_GetAnalogAverageVoltage((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AverageVoltage = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -386,12 +337,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogLSBWeight
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
 
   jint returnValue = HAL_GetAnalogLSBWeight((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AnalogLSBWeight = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -405,12 +353,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogOffset
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
 
   jint returnValue = HAL_GetAnalogOffset((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AnalogOffset = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -424,14 +369,10 @@
 Java_edu_wpi_first_hal_AnalogJNI_isAccumulatorChannel
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "isAccumulatorChannel";
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
 
   jboolean returnValue =
       HAL_IsAccumulatorChannel((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AnalogOffset = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -445,10 +386,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_initAccumulator
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   HAL_InitAccumulator((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -461,10 +400,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_resetAccumulator
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   HAL_ResetAccumulator((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -477,10 +414,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAccumulatorCenter
   (JNIEnv* env, jclass, jint id, jint center)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   HAL_SetAccumulatorCenter((HAL_AnalogInputHandle)id, center, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -493,10 +428,8 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAccumulatorDeadband
   (JNIEnv* env, jclass, jint id, jint deadband)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   HAL_SetAccumulatorDeadband((HAL_AnalogInputHandle)id, deadband, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -509,12 +442,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAccumulatorValue
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   jlong returnValue =
       HAL_GetAccumulatorValue((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AccumulatorValue = " << returnValue;
   CheckStatus(env, status);
 
   return returnValue;
@@ -529,12 +459,9 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAccumulatorCount
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetAccumulatorCount((HAL_AnalogInputHandle)id, &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AccumulatorCount = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -548,15 +475,11 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAccumulatorOutput
   (JNIEnv* env, jclass, jint id, jobject accumulatorResult)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Handle = " << (HAL_AnalogInputHandle)id;
   int32_t status = 0;
   int64_t value = 0;
   int64_t count = 0;
   HAL_GetAccumulatorOutput((HAL_AnalogInputHandle)id, &value, &count, &status);
   SetAccumulatorResultObject(env, accumulatorResult, value, count);
-  ANALOGJNI_LOG(logDEBUG) << "Value = " << value;
-  ANALOGJNI_LOG(logDEBUG) << "Count = " << count;
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -569,16 +492,12 @@
 Java_edu_wpi_first_hal_AnalogJNI_initializeAnalogTrigger
   (JNIEnv* env, jclass, jint id, jobject index)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_AnalogInputHandle)id;
   jint* indexHandle =
       reinterpret_cast<jint*>(env->GetDirectBufferAddress(index));
-  ANALOGJNI_LOG(logDEBUG) << "Index Ptr = " << indexHandle;
   int32_t status = 0;
   HAL_AnalogTriggerHandle analogTrigger = HAL_InitializeAnalogTrigger(
       (HAL_AnalogInputHandle)id, reinterpret_cast<int32_t*>(indexHandle),
       &status);
-  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
-  ANALOGJNI_LOG(logDEBUG) << "AnalogTrigger Handle = " << analogTrigger;
   CheckStatus(env, status);
   return (jint)analogTrigger;
 }
@@ -592,8 +511,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_cleanAnalogTrigger
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   HAL_CleanAnalogTrigger((HAL_AnalogTriggerHandle)id, &status);
   CheckStatus(env, status);
@@ -608,8 +525,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogTriggerLimitsRaw
   (JNIEnv* env, jclass, jint id, jint lower, jint upper)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   HAL_SetAnalogTriggerLimitsRaw((HAL_AnalogTriggerHandle)id, lower, upper,
                                 &status);
@@ -625,8 +540,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogTriggerLimitsVoltage
   (JNIEnv* env, jclass, jint id, jdouble lower, jdouble upper)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   HAL_SetAnalogTriggerLimitsVoltage((HAL_AnalogTriggerHandle)id, lower, upper,
                                     &status);
@@ -642,8 +555,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogTriggerAveraged
   (JNIEnv* env, jclass, jint id, jboolean averaged)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   HAL_SetAnalogTriggerAveraged((HAL_AnalogTriggerHandle)id, averaged, &status);
   CheckStatus(env, status);
@@ -658,8 +569,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_setAnalogTriggerFiltered
   (JNIEnv* env, jclass, jint id, jboolean filtered)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   HAL_SetAnalogTriggerFiltered((HAL_AnalogTriggerHandle)id, filtered, &status);
   CheckStatus(env, status);
@@ -674,8 +583,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogTriggerInWindow
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   jboolean val =
       HAL_GetAnalogTriggerInWindow((HAL_AnalogTriggerHandle)id, &status);
@@ -692,8 +599,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogTriggerTriggerState
   (JNIEnv* env, jclass, jint id)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   jboolean val =
       HAL_GetAnalogTriggerTriggerState((HAL_AnalogTriggerHandle)id, &status);
@@ -710,8 +615,6 @@
 Java_edu_wpi_first_hal_AnalogJNI_getAnalogTriggerOutput
   (JNIEnv* env, jclass, jint id, jint type)
 {
-  ANALOGJNI_LOG(logDEBUG) << "Analog Trigger Handle = "
-                          << (HAL_AnalogTriggerHandle)id;
   int32_t status = 0;
   jboolean val = HAL_GetAnalogTriggerOutput(
       (HAL_AnalogTriggerHandle)id, (HAL_AnalogTriggerType)type, &status);
diff --git a/hal/src/main/native/cpp/jni/CANAPIJNI.cpp b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
index bcb285c..7ac7cf6 100644
--- a/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
+++ b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -18,7 +18,6 @@
 #include "hal/CAN.h"
 #include "hal/CANAPI.h"
 #include "hal/Errors.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 using namespace wpi::java;
@@ -95,6 +94,21 @@
 
 /*
  * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    writeCANRTRFrame
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_writeCANRTRFrame
+  (JNIEnv* env, jclass, jint handle, jint length, jint apiId)
+{
+  auto halHandle = static_cast<HAL_CANHandle>(handle);
+  int32_t status = 0;
+  HAL_WriteCANRTRFrame(halHandle, static_cast<int32_t>(length), apiId, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
  * Method:    stopCANPacketRepeating
  * Signature: (II)V
  */
@@ -204,38 +218,4 @@
                           reinterpret_cast<jbyte*>(dataTemp));
   return true;
 }
-
-/*
- * Class:     edu_wpi_first_hal_CANAPIJNI
- * Method:    readCANPeriodicPacket
- * Signature: (IIIILjava/lang/Object;)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CANAPIJNI_readCANPeriodicPacket
-  (JNIEnv* env, jclass, jint handle, jint apiId, jint timeoutMs, jint periodMs,
-   jobject data)
-{
-  auto halHandle = static_cast<HAL_CANHandle>(handle);
-  uint8_t dataTemp[8];
-  int32_t dataLength = 0;
-  uint64_t timestamp = 0;
-  int32_t status = 0;
-  HAL_ReadCANPeriodicPacket(halHandle, apiId, dataTemp, &dataLength, &timestamp,
-                            timeoutMs, periodMs, &status);
-  if (status == HAL_CAN_TIMEOUT ||
-      status == HAL_ERR_CANSessionMux_MessageNotFound) {
-    return false;
-  }
-  if (!CheckStatus(env, status)) {
-    return false;
-  }
-  if (dataLength > 8) dataLength = 8;
-
-  jbyteArray toSetArray = SetCANDataObject(env, data, dataLength, timestamp);
-  auto javaLen = env->GetArrayLength(toSetArray);
-  if (javaLen < dataLength) dataLength = javaLen;
-  env->SetByteArrayRegion(toSetArray, 0, dataLength,
-                          reinterpret_cast<jbyte*>(dataTemp));
-  return true;
-}
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/CANJNI.cpp b/hal/src/main/native/cpp/jni/CANJNI.cpp
index 0f46d15..9278c24 100644
--- a/hal/src/main/native/cpp/jni/CANJNI.cpp
+++ b/hal/src/main/native/cpp/jni/CANJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -16,21 +16,10 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_can_CANJNI.h"
 #include "hal/CAN.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 using namespace wpi::java;
 
-// set the logging level
-// TLogLevel canJNILogLevel = logDEBUG;
-TLogLevel canJNILogLevel = logERROR;
-
-#define CANJNI_LOG(level)     \
-  if (level > canJNILogLevel) \
-    ;                         \
-  else                        \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -42,37 +31,14 @@
 Java_edu_wpi_first_hal_can_CANJNI_FRCNetCommCANSessionMuxSendMessage
   (JNIEnv* env, jclass, jint messageID, jbyteArray data, jint periodMs)
 {
-  CANJNI_LOG(logDEBUG) << "Calling CANJNI FRCNetCommCANSessionMuxSendMessage";
-
   JByteArrayRef dataArray{env, data};
 
   const uint8_t* dataBuffer =
       reinterpret_cast<const uint8_t*>(dataArray.array().data());
   uint8_t dataSize = dataArray.array().size();
 
-  CANJNI_LOG(logDEBUG) << "Message ID ";
-  CANJNI_LOG(logDEBUG).write_hex(messageID);
-
-  if (logDEBUG <= canJNILogLevel) {
-    if (dataBuffer) {
-      wpi::SmallString<128> buf;
-      wpi::raw_svector_ostream str(buf);
-      for (int32_t i = 0; i < dataSize; i++) {
-        str.write_hex(dataBuffer[i]) << ' ';
-      }
-
-      Log().Get(logDEBUG) << "Data: " << str.str();
-    } else {
-      CANJNI_LOG(logDEBUG) << "Data: null";
-    }
-  }
-
-  CANJNI_LOG(logDEBUG) << "Period: " << periodMs;
-
   int32_t status = 0;
   HAL_CAN_SendMessage(messageID, dataBuffer, dataSize, periodMs, &status);
-
-  CANJNI_LOG(logDEBUG) << "Status: " << status;
   CheckCANStatus(env, status, messageID);
 }
 
@@ -86,9 +52,6 @@
   (JNIEnv* env, jclass, jobject messageID, jint messageIDMask,
    jobject timeStamp)
 {
-  CANJNI_LOG(logDEBUG)
-      << "Calling CANJNI FRCNetCommCANSessionMuxReceiveMessage";
-
   uint32_t* messageIDPtr =
       reinterpret_cast<uint32_t*>(env->GetDirectBufferAddress(messageID));
   uint32_t* timeStampPtr =
@@ -101,28 +64,6 @@
   HAL_CAN_ReceiveMessage(messageIDPtr, messageIDMask, buffer, &dataSize,
                          timeStampPtr, &status);
 
-  CANJNI_LOG(logDEBUG) << "Message ID ";
-  CANJNI_LOG(logDEBUG).write_hex(*messageIDPtr);
-
-  if (logDEBUG <= canJNILogLevel) {
-    wpi::SmallString<128> buf;
-    wpi::raw_svector_ostream str(buf);
-
-    for (int32_t i = 0; i < dataSize; i++) {
-      // Pad one-digit data with a zero
-      if (buffer[i] <= 16) {
-        str << '0';
-      }
-
-      str.write_hex(buffer[i]) << ' ';
-    }
-
-    Log().Get(logDEBUG) << "Data: " << str.str();
-  }
-
-  CANJNI_LOG(logDEBUG) << "Timestamp: " << *timeStampPtr;
-  CANJNI_LOG(logDEBUG) << "Status: " << status;
-
   if (!CheckCANStatus(env, status, *messageIDPtr)) return nullptr;
   return MakeJByteArray(env,
                         wpi::StringRef{reinterpret_cast<const char*>(buffer),
@@ -138,8 +79,6 @@
 Java_edu_wpi_first_hal_can_CANJNI_GetCANStatus
   (JNIEnv* env, jclass, jobject canStatus)
 {
-  CANJNI_LOG(logDEBUG) << "Calling CANJNI HAL_CAN_GetCANStatus";
-
   float percentBusUtilization = 0;
   uint32_t busOffCount = 0;
   uint32_t txFullCount = 0;
diff --git a/hal/src/main/native/cpp/jni/CompressorJNI.cpp b/hal/src/main/native/cpp/jni/CompressorJNI.cpp
index e38abb5..75a5e0a 100644
--- a/hal/src/main/native/cpp/jni/CompressorJNI.cpp
+++ b/hal/src/main/native/cpp/jni/CompressorJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -10,7 +10,6 @@
 #include "hal/Compressor.h"
 #include "hal/Ports.h"
 #include "hal/Solenoid.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
diff --git a/hal/src/main/native/cpp/jni/ConstantsJNI.cpp b/hal/src/main/native/cpp/jni/ConstantsJNI.cpp
index 3db8f5a..fb1ae0b 100644
--- a/hal/src/main/native/cpp/jni/ConstantsJNI.cpp
+++ b/hal/src/main/native/cpp/jni/ConstantsJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -12,19 +12,9 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_ConstantsJNI.h"
 #include "hal/Constants.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel constantsJNILogLevel = logWARNING;
-
-#define CONSTANTSJNI_LOG(level)     \
-  if (level > constantsJNILogLevel) \
-    ;                               \
-  else                              \
-    Log().Get(level)
-
 extern "C" {
 /*
  * Class:     edu_wpi_first_hal_ConstantsJNI
@@ -35,10 +25,7 @@
 Java_edu_wpi_first_hal_ConstantsJNI_getSystemClockTicksPerMicrosecond
   (JNIEnv* env, jclass)
 {
-  CONSTANTSJNI_LOG(logDEBUG)
-      << "Calling ConstantsJNI getSystemClockTicksPerMicrosecond";
   jint value = HAL_GetSystemClockTicksPerMicrosecond();
-  CONSTANTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/CounterJNI.cpp b/hal/src/main/native/cpp/jni/CounterJNI.cpp
index 70ec5be..41dedab 100644
--- a/hal/src/main/native/cpp/jni/CounterJNI.cpp
+++ b/hal/src/main/native/cpp/jni/CounterJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,19 +13,9 @@
 #include "edu_wpi_first_hal_CounterJNI.h"
 #include "hal/Counter.h"
 #include "hal/Errors.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel counterJNILogLevel = logWARNING;
-
-#define COUNTERJNI_LOG(level)     \
-  if (level > counterJNILogLevel) \
-    ;                             \
-  else                            \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -37,17 +27,10 @@
 Java_edu_wpi_first_hal_CounterJNI_initializeCounter
   (JNIEnv* env, jclass, jint mode, jobject index)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI initializeCounter";
-  COUNTERJNI_LOG(logDEBUG) << "Mode = " << mode;
   jint* indexPtr = reinterpret_cast<jint*>(env->GetDirectBufferAddress(index));
-  COUNTERJNI_LOG(logDEBUG) << "Index Ptr = "
-                           << reinterpret_cast<int32_t*>(indexPtr);
   int32_t status = 0;
   auto counter = HAL_InitializeCounter(
       (HAL_Counter_Mode)mode, reinterpret_cast<int32_t*>(indexPtr), &status);
-  COUNTERJNI_LOG(logDEBUG) << "Index = " << *indexPtr;
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
-  COUNTERJNI_LOG(logDEBUG) << "COUNTER Handle = " << counter;
   CheckStatusForceThrow(env, status);
   return (jint)counter;
 }
@@ -61,11 +44,8 @@
 Java_edu_wpi_first_hal_CounterJNI_freeCounter
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI freeCounter";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   HAL_FreeCounter((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -78,12 +58,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterAverageSize
   (JNIEnv* env, jclass, jint id, jint value)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterAverageSize";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "AverageSize = " << value;
   int32_t status = 0;
   HAL_SetCounterAverageSize((HAL_CounterHandle)id, value, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -97,14 +73,9 @@
   (JNIEnv* env, jclass, jint id, jint digitalSourceHandle,
    jint analogTriggerType)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterUpSource";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "digitalSourceHandle = " << digitalSourceHandle;
-  COUNTERJNI_LOG(logDEBUG) << "analogTriggerType = " << analogTriggerType;
   int32_t status = 0;
   HAL_SetCounterUpSource((HAL_CounterHandle)id, (HAL_Handle)digitalSourceHandle,
                          (HAL_AnalogTriggerType)analogTriggerType, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -117,14 +88,9 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterUpSourceEdge
   (JNIEnv* env, jclass, jint id, jboolean valueRise, jboolean valueFall)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterUpSourceEdge";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "Rise = " << (jint)valueRise;
-  COUNTERJNI_LOG(logDEBUG) << "Fall = " << (jint)valueFall;
   int32_t status = 0;
   HAL_SetCounterUpSourceEdge((HAL_CounterHandle)id, valueRise, valueFall,
                              &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -137,11 +103,8 @@
 Java_edu_wpi_first_hal_CounterJNI_clearCounterUpSource
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI clearCounterUpSource";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   HAL_ClearCounterUpSource((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -155,15 +118,10 @@
   (JNIEnv* env, jclass, jint id, jint digitalSourceHandle,
    jint analogTriggerType)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterDownSource";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "digitalSourceHandle = " << digitalSourceHandle;
-  COUNTERJNI_LOG(logDEBUG) << "analogTriggerType = " << analogTriggerType;
   int32_t status = 0;
   HAL_SetCounterDownSource((HAL_CounterHandle)id,
                            (HAL_Handle)digitalSourceHandle,
                            (HAL_AnalogTriggerType)analogTriggerType, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   if (status == PARAMETER_OUT_OF_RANGE) {
     ThrowIllegalArgumentException(env,
                                   "Counter only supports DownSource in "
@@ -182,14 +140,9 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterDownSourceEdge
   (JNIEnv* env, jclass, jint id, jboolean valueRise, jboolean valueFall)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterDownSourceEdge";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "Rise = " << (jint)valueRise;
-  COUNTERJNI_LOG(logDEBUG) << "Fall = " << (jint)valueFall;
   int32_t status = 0;
   HAL_SetCounterDownSourceEdge((HAL_CounterHandle)id, valueRise, valueFall,
                                &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -202,11 +155,8 @@
 Java_edu_wpi_first_hal_CounterJNI_clearCounterDownSource
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI clearCounterDownSource";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   HAL_ClearCounterDownSource((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -219,11 +169,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterUpDownMode
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterUpDownMode";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   HAL_SetCounterUpDownMode((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -236,12 +183,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterExternalDirectionMode
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG)
-      << "Calling COUNTERJNI setCounterExternalDirectionMode";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   HAL_SetCounterExternalDirectionMode((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -254,12 +197,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterSemiPeriodMode
   (JNIEnv* env, jclass, jint id, jboolean value)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterSemiPeriodMode";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "SemiPeriodMode = " << (jint)value;
   int32_t status = 0;
   HAL_SetCounterSemiPeriodMode((HAL_CounterHandle)id, value, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -272,12 +211,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterPulseLengthMode
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterPulseLengthMode";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "PulseLengthMode = " << value;
   int32_t status = 0;
   HAL_SetCounterPulseLengthMode((HAL_CounterHandle)id, value, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -290,14 +225,9 @@
 Java_edu_wpi_first_hal_CounterJNI_getCounterSamplesToAverage
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI getCounterSamplesToAverage";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetCounterSamplesToAverage((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
-  COUNTERJNI_LOG(logDEBUG) << "getCounterSamplesToAverageResult = "
-                           << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -311,12 +241,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterSamplesToAverage
   (JNIEnv* env, jclass, jint id, jint value)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterSamplesToAverage";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "SamplesToAverage = " << value;
   int32_t status = 0;
   HAL_SetCounterSamplesToAverage((HAL_CounterHandle)id, value, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   if (status == PARAMETER_OUT_OF_RANGE) {
     ThrowBoundaryException(env, value, 1, 127);
     return;
@@ -333,11 +259,8 @@
 Java_edu_wpi_first_hal_CounterJNI_resetCounter
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI resetCounter";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   HAL_ResetCounter((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -350,12 +273,8 @@
 Java_edu_wpi_first_hal_CounterJNI_getCounter
   (JNIEnv* env, jclass, jint id)
 {
-  // COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI getCounter";
-  // COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   jint returnValue = HAL_GetCounter((HAL_CounterHandle)id, &status);
-  // COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
-  // COUNTERJNI_LOG(logDEBUG) << "getCounterResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -369,12 +288,8 @@
 Java_edu_wpi_first_hal_CounterJNI_getCounterPeriod
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI getCounterPeriod";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   jdouble returnValue = HAL_GetCounterPeriod((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
-  COUNTERJNI_LOG(logDEBUG) << "getCounterPeriodResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -388,12 +303,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterMaxPeriod
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterMaxPeriod";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "MaxPeriod = " << value;
   int32_t status = 0;
   HAL_SetCounterMaxPeriod((HAL_CounterHandle)id, value, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -406,12 +317,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterUpdateWhenEmpty
   (JNIEnv* env, jclass, jint id, jboolean value)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterMaxPeriod";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "UpdateWhenEmpty = " << (jint)value;
   int32_t status = 0;
   HAL_SetCounterUpdateWhenEmpty((HAL_CounterHandle)id, value, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -424,12 +331,8 @@
 Java_edu_wpi_first_hal_CounterJNI_getCounterStopped
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI getCounterStopped";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   jboolean returnValue = HAL_GetCounterStopped((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
-  COUNTERJNI_LOG(logDEBUG) << "getCounterStoppedResult = " << (jint)returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -443,14 +346,9 @@
 Java_edu_wpi_first_hal_CounterJNI_getCounterDirection
   (JNIEnv* env, jclass, jint id)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI getCounterDirection";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
   int32_t status = 0;
   jboolean returnValue =
       HAL_GetCounterDirection((HAL_CounterHandle)id, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
-  COUNTERJNI_LOG(logDEBUG) << "getCounterDirectionResult = "
-                           << (jint)returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -464,12 +362,8 @@
 Java_edu_wpi_first_hal_CounterJNI_setCounterReverseDirection
   (JNIEnv* env, jclass, jint id, jboolean value)
 {
-  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI setCounterReverseDirection";
-  COUNTERJNI_LOG(logDEBUG) << "Counter Handle = " << (HAL_CounterHandle)id;
-  COUNTERJNI_LOG(logDEBUG) << "ReverseDirection = " << (jint)value;
   int32_t status = 0;
   HAL_SetCounterReverseDirection((HAL_CounterHandle)id, value, &status);
-  COUNTERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
diff --git a/hal/src/main/native/cpp/jni/DIOJNI.cpp b/hal/src/main/native/cpp/jni/DIOJNI.cpp
index e21edcf..9c44b4c 100644
--- a/hal/src/main/native/cpp/jni/DIOJNI.cpp
+++ b/hal/src/main/native/cpp/jni/DIOJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -14,20 +14,10 @@
 #include "hal/DIO.h"
 #include "hal/PWM.h"
 #include "hal/Ports.h"
-#include "hal/cpp/Log.h"
 #include "hal/handles/HandlesInternal.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel dioJNILogLevel = logWARNING;
-
-#define DIOJNI_LOG(level)     \
-  if (level > dioJNILogLevel) \
-    ;                         \
-  else                        \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -39,14 +29,9 @@
 Java_edu_wpi_first_hal_DIOJNI_initializeDIOPort
   (JNIEnv* env, jclass, jint id, jboolean input)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI initializeDIOPort";
-  DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_PortHandle)id;
-  DIOJNI_LOG(logDEBUG) << "Input = " << (jint)input;
   int32_t status = 0;
   auto dio = HAL_InitializeDIOPort((HAL_PortHandle)id,
                                    static_cast<uint8_t>(input), &status);
-  DIOJNI_LOG(logDEBUG) << "Status = " << status;
-  DIOJNI_LOG(logDEBUG) << "DIO Handle = " << dio;
   CheckStatusRange(env, status, 0, HAL_GetNumDigitalChannels(),
                    hal::getPortHandleChannel((HAL_PortHandle)id));
   return (jint)dio;
@@ -61,8 +46,6 @@
 Java_edu_wpi_first_hal_DIOJNI_checkDIOChannel
   (JNIEnv* env, jclass, jint channel)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI checkDIOChannel";
-  DIOJNI_LOG(logDEBUG) << "Channel = " << channel;
   return HAL_CheckDIOChannel(channel);
 }
 
@@ -75,13 +58,23 @@
 Java_edu_wpi_first_hal_DIOJNI_freeDIOPort
   (JNIEnv* env, jclass, jint id)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI freeDIOPort";
-  DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   HAL_FreeDIOPort((HAL_DigitalHandle)id);
 }
 
 /*
  * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    setDIOSimDevice
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DIOJNI_setDIOSimDevice
+  (JNIEnv* env, jclass, jint handle, jint device)
+{
+  HAL_SetDIOSimDevice((HAL_DigitalHandle)handle, (HAL_SimDeviceHandle)device);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
  * Method:    setDIO
  * Signature: (IS)V
  */
@@ -89,12 +82,8 @@
 Java_edu_wpi_first_hal_DIOJNI_setDIO
   (JNIEnv* env, jclass, jint id, jshort value)
 {
-  // DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDIO";
-  // DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
-  // DIOJNI_LOG(logDEBUG) << "Value = " << value;
   int32_t status = 0;
   HAL_SetDIO((HAL_DigitalHandle)id, value, &status);
-  // DIOJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -107,12 +96,8 @@
 Java_edu_wpi_first_hal_DIOJNI_setDIODirection
   (JNIEnv* env, jclass, jint id, jboolean input)
 {
-  // DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDIO";
-  // DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
-  // DIOJNI_LOG(logDEBUG) << "IsInput = " << input;
   int32_t status = 0;
   HAL_SetDIODirection((HAL_DigitalHandle)id, input, &status);
-  // DIOJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -125,12 +110,8 @@
 Java_edu_wpi_first_hal_DIOJNI_getDIO
   (JNIEnv* env, jclass, jint id)
 {
-  // DIOJNI_LOG(logDEBUG) << "Calling DIOJNI getDIO";
-  // DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   jboolean returnValue = HAL_GetDIO((HAL_DigitalHandle)id, &status);
-  // DIOJNI_LOG(logDEBUG) << "Status = " << status;
-  // DIOJNI_LOG(logDEBUG) << "getDIOResult = " << (jint)returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -144,12 +125,8 @@
 Java_edu_wpi_first_hal_DIOJNI_getDIODirection
   (JNIEnv* env, jclass, jint id)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI getDIODirection (RR upd)";
-  // DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   jboolean returnValue = HAL_GetDIODirection((HAL_DigitalHandle)id, &status);
-  // DIOJNI_LOG(logDEBUG) << "Status = " << status;
-  DIOJNI_LOG(logDEBUG) << "getDIODirectionResult = " << (jint)returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -163,12 +140,8 @@
 Java_edu_wpi_first_hal_DIOJNI_pulse
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI pulse (RR upd)";
-  // DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
-  // DIOJNI_LOG(logDEBUG) << "Value = " << value;
   int32_t status = 0;
   HAL_Pulse((HAL_DigitalHandle)id, value, &status);
-  DIOJNI_LOG(logDEBUG) << "Did it work? Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -181,12 +154,8 @@
 Java_edu_wpi_first_hal_DIOJNI_isPulsing
   (JNIEnv* env, jclass, jint id)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI isPulsing (RR upd)";
-  // DIOJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   jboolean returnValue = HAL_IsPulsing((HAL_DigitalHandle)id, &status);
-  // DIOJNI_LOG(logDEBUG) << "Status = " << status;
-  DIOJNI_LOG(logDEBUG) << "isPulsingResult = " << (jint)returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -200,11 +169,8 @@
 Java_edu_wpi_first_hal_DIOJNI_isAnyPulsing
   (JNIEnv* env, jclass)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI isAnyPulsing (RR upd)";
   int32_t status = 0;
   jboolean returnValue = HAL_IsAnyPulsing(&status);
-  // DIOJNI_LOG(logDEBUG) << "Status = " << status;
-  DIOJNI_LOG(logDEBUG) << "isAnyPulsingResult = " << (jint)returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -218,11 +184,8 @@
 Java_edu_wpi_first_hal_DIOJNI_getLoopTiming
   (JNIEnv* env, jclass)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI getLoopTimeing";
   int32_t status = 0;
   jshort returnValue = HAL_GetPWMLoopTiming(&status);
-  DIOJNI_LOG(logDEBUG) << "Status = " << status;
-  DIOJNI_LOG(logDEBUG) << "LoopTiming = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -236,11 +199,8 @@
 Java_edu_wpi_first_hal_DIOJNI_allocateDigitalPWM
   (JNIEnv* env, jclass)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI allocateDigitalPWM";
   int32_t status = 0;
   auto pwm = HAL_AllocateDigitalPWM(&status);
-  DIOJNI_LOG(logDEBUG) << "Status = " << status;
-  DIOJNI_LOG(logDEBUG) << "PWM Handle = " << pwm;
   CheckStatus(env, status);
   return (jint)pwm;
 }
@@ -254,11 +214,8 @@
 Java_edu_wpi_first_hal_DIOJNI_freeDigitalPWM
   (JNIEnv* env, jclass, jint id)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI freeDigitalPWM";
-  DIOJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalPWMHandle)id;
   int32_t status = 0;
   HAL_FreeDigitalPWM((HAL_DigitalPWMHandle)id, &status);
-  DIOJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -271,11 +228,8 @@
 Java_edu_wpi_first_hal_DIOJNI_setDigitalPWMRate
   (JNIEnv* env, jclass, jdouble value)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDigitalPWMRate";
-  DIOJNI_LOG(logDEBUG) << "Rate= " << value;
   int32_t status = 0;
   HAL_SetDigitalPWMRate(value, &status);
-  DIOJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -288,12 +242,8 @@
 Java_edu_wpi_first_hal_DIOJNI_setDigitalPWMDutyCycle
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDigitalPWMDutyCycle";
-  DIOJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalPWMHandle)id;
-  DIOJNI_LOG(logDEBUG) << "DutyCycle= " << value;
   int32_t status = 0;
   HAL_SetDigitalPWMDutyCycle((HAL_DigitalPWMHandle)id, value, &status);
-  DIOJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -306,13 +256,9 @@
 Java_edu_wpi_first_hal_DIOJNI_setDigitalPWMOutputChannel
   (JNIEnv* env, jclass, jint id, jint value)
 {
-  DIOJNI_LOG(logDEBUG) << "Calling DIOJNI setDigitalPWMOutputChannel";
-  DIOJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalPWMHandle)id;
-  DIOJNI_LOG(logDEBUG) << "Channel= " << value;
   int32_t status = 0;
   HAL_SetDigitalPWMOutputChannel((HAL_DigitalPWMHandle)id,
                                  static_cast<uint32_t>(value), &status);
-  DIOJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
diff --git a/hal/src/main/native/cpp/jni/EncoderJNI.cpp b/hal/src/main/native/cpp/jni/EncoderJNI.cpp
index 10c4332..e5aa7e8 100644
--- a/hal/src/main/native/cpp/jni/EncoderJNI.cpp
+++ b/hal/src/main/native/cpp/jni/EncoderJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,19 +13,9 @@
 #include "edu_wpi_first_hal_EncoderJNI.h"
 #include "hal/Encoder.h"
 #include "hal/Errors.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel encoderJNILogLevel = logWARNING;
-
-#define ENCODERJNI_LOG(level)     \
-  if (level > encoderJNILogLevel) \
-    ;                             \
-  else                            \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -39,13 +29,6 @@
    jint digitalSourceHandleB, jint analogTriggerTypeB,
    jboolean reverseDirection, jint encodingType)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI initializeEncoder";
-  ENCODERJNI_LOG(logDEBUG) << "Source Handle A = " << digitalSourceHandleA;
-  ENCODERJNI_LOG(logDEBUG) << "Analog Trigger Type A = " << analogTriggerTypeA;
-  ENCODERJNI_LOG(logDEBUG) << "Source Handle B = " << digitalSourceHandleB;
-  ENCODERJNI_LOG(logDEBUG) << "Analog Trigger Type B = " << analogTriggerTypeB;
-  ENCODERJNI_LOG(logDEBUG) << "Reverse direction = " << (jint)reverseDirection;
-  ENCODERJNI_LOG(logDEBUG) << "EncodingType = " << encodingType;
   int32_t status = 0;
   auto encoder = HAL_InitializeEncoder(
       (HAL_Handle)digitalSourceHandleA,
@@ -53,9 +36,6 @@
       (HAL_Handle)digitalSourceHandleB,
       (HAL_AnalogTriggerType)analogTriggerTypeB, reverseDirection,
       (HAL_EncoderEncodingType)encodingType, &status);
-
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "ENCODER Handle = " << encoder;
   CheckStatusForceThrow(env, status);
   return (jint)encoder;
 }
@@ -69,16 +49,26 @@
 Java_edu_wpi_first_hal_EncoderJNI_freeEncoder
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI freeEncoder";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   HAL_FreeEncoder((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    setEncoderSimDevice
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_EncoderJNI_setEncoderSimDevice
+  (JNIEnv* env, jclass, jint handle, jint device)
+{
+  HAL_SetEncoderSimDevice((HAL_EncoderHandle)handle,
+                          (HAL_SimDeviceHandle)device);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
  * Method:    getEncoder
  * Signature: (I)I
  */
@@ -86,12 +76,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoder
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoder";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jint returnValue = HAL_GetEncoder((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -105,12 +91,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderRaw
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderRaw";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jint returnValue = HAL_GetEncoderRaw((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getRawEncoderResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -124,13 +106,9 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncodingScaleFactor
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncodingScaleFactor";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetEncoderEncodingScale((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncodingScaleFactorResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -144,11 +122,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_resetEncoder
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI resetEncoder";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   HAL_ResetEncoder((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -161,12 +136,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderPeriod
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderPeriod";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   double returnValue = HAL_GetEncoderPeriod((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderPeriodEncoderResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -180,11 +151,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_setEncoderMaxPeriod
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI setEncoderMaxPeriod";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   HAL_SetEncoderMaxPeriod((HAL_EncoderHandle)id, value, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -197,12 +165,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderStopped
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderStopped";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jboolean returnValue = HAL_GetEncoderStopped((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getStoppedEncoderResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -216,13 +180,9 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderDirection
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderDirection";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jboolean returnValue =
       HAL_GetEncoderDirection((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getDirectionEncoderResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -236,12 +196,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderDistance
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderDistance";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jdouble returnValue = HAL_GetEncoderDistance((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getDistanceEncoderResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -255,12 +211,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderRate
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderRate";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jdouble returnValue = HAL_GetEncoderRate((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getRateEncoderResult = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -274,11 +226,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_setEncoderMinRate
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI setEncoderMinRate";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   HAL_SetEncoderMinRate((HAL_EncoderHandle)id, value, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -291,11 +240,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_setEncoderDistancePerPulse
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI setEncoderDistancePerPulse";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   HAL_SetEncoderDistancePerPulse((HAL_EncoderHandle)id, value, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -308,11 +254,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_setEncoderReverseDirection
   (JNIEnv* env, jclass, jint id, jboolean value)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI setEncoderReverseDirection";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   HAL_SetEncoderReverseDirection((HAL_EncoderHandle)id, value, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -325,11 +268,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_setEncoderSamplesToAverage
   (JNIEnv* env, jclass, jint id, jint value)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI setEncoderSamplesToAverage";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   HAL_SetEncoderSamplesToAverage((HAL_EncoderHandle)id, value, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   if (status == PARAMETER_OUT_OF_RANGE) {
     ThrowBoundaryException(env, value, 1, 127);
     return;
@@ -346,14 +286,9 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderSamplesToAverage
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderSamplesToAverage";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetEncoderSamplesToAverage((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderSamplesToAverageResult = "
-                           << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -368,17 +303,11 @@
   (JNIEnv* env, jclass, jint id, jint digitalSourceHandle,
    jint analogTriggerType, jint type)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI setEncoderIndexSource";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
-  ENCODERJNI_LOG(logDEBUG) << "Source Handle = " << digitalSourceHandle;
-  ENCODERJNI_LOG(logDEBUG) << "Analog Trigger Type = " << analogTriggerType;
-  ENCODERJNI_LOG(logDEBUG) << "IndexingType = " << type;
   int32_t status = 0;
   HAL_SetEncoderIndexSource((HAL_EncoderHandle)id,
                             (HAL_Handle)digitalSourceHandle,
                             (HAL_AnalogTriggerType)analogTriggerType,
                             (HAL_EncoderIndexingType)type, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -391,13 +320,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderFPGAIndex
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderSamplesToAverage";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jint returnValue = HAL_GetEncoderFPGAIndex((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderSamplesToAverageResult = "
-                           << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -411,14 +335,9 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderEncodingScale
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderSamplesToAverage";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jint returnValue =
       HAL_GetEncoderEncodingScale((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderSamplesToAverageResult = "
-                           << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -432,14 +351,9 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderDecodingScaleFactor
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderSamplesToAverage";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jdouble returnValue =
       HAL_GetEncoderDecodingScaleFactor((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderSamplesToAverageResult = "
-                           << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -453,14 +367,9 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderDistancePerPulse
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderSamplesToAverage";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jdouble returnValue =
       HAL_GetEncoderDistancePerPulse((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderSamplesToAverageResult = "
-                           << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -474,13 +383,8 @@
 Java_edu_wpi_first_hal_EncoderJNI_getEncoderEncodingType
   (JNIEnv* env, jclass, jint id)
 {
-  ENCODERJNI_LOG(logDEBUG) << "Calling ENCODERJNI getEncoderSamplesToAverage";
-  ENCODERJNI_LOG(logDEBUG) << "Encoder Handle = " << (HAL_EncoderHandle)id;
   int32_t status = 0;
   jint returnValue = HAL_GetEncoderEncodingType((HAL_EncoderHandle)id, &status);
-  ENCODERJNI_LOG(logDEBUG) << "Status = " << status;
-  ENCODERJNI_LOG(logDEBUG) << "getEncoderSamplesToAverageResult = "
-                           << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
diff --git a/hal/src/main/native/cpp/jni/HAL.cpp b/hal/src/main/native/cpp/jni/HAL.cpp
index cc5f7cf..393b0b4 100644
--- a/hal/src/main/native/cpp/jni/HAL.cpp
+++ b/hal/src/main/native/cpp/jni/HAL.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -17,20 +17,11 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_HAL.h"
 #include "hal/DriverStation.h"
-#include "hal/cpp/Log.h"
+#include "hal/Main.h"
 
 using namespace frc;
 using namespace wpi::java;
 
-// set the logging level
-static TLogLevel netCommLogLevel = logWARNING;
-
-#define NETCOMM_LOG(level)     \
-  if (level > netCommLogLevel) \
-    ;                          \
-  else                         \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -47,6 +38,42 @@
 
 /*
  * Class:     edu_wpi_first_hal_HAL
+ * Method:    hasMain
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_HAL_hasMain
+  (JNIEnv*, jclass)
+{
+  return HAL_HasMain();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    runMain
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_runMain
+  (JNIEnv*, jclass)
+{
+  HAL_RunMain();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    exitMain
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_exitMain
+  (JNIEnv*, jclass)
+{
+  HAL_ExitMain();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
  * Method:    observeUserProgramStarting
  * Signature: ()V
  */
@@ -116,11 +143,6 @@
    jint paramContext, jstring paramFeature)
 {
   JStringRef featureStr{paramEnv, paramFeature};
-  NETCOMM_LOG(logDEBUG) << "Calling HAL report "
-                        << "res:" << paramResource
-                        << " instance:" << paramInstanceNumber
-                        << " context:" << paramContext
-                        << " feature:" << featureStr.c_str();
   jint returnValue = HAL_Report(paramResource, paramInstanceNumber,
                                 paramContext, featureStr.c_str());
   return returnValue;
@@ -135,7 +157,6 @@
 Java_edu_wpi_first_hal_HAL_nativeGetControlWord
   (JNIEnv*, jclass)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HAL Control Word";
   static_assert(sizeof(HAL_ControlWord) == sizeof(jint),
                 "Java int must match the size of control word");
   HAL_ControlWord controlWord;
@@ -155,7 +176,6 @@
 Java_edu_wpi_first_hal_HAL_nativeGetAllianceStation
   (JNIEnv*, jclass)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HAL Alliance Station";
   int32_t status = 0;
   auto allianceStation = HAL_GetAllianceStation(&status);
   return static_cast<jint>(allianceStation);
@@ -170,7 +190,6 @@
 Java_edu_wpi_first_hal_HAL_getJoystickAxes
   (JNIEnv* env, jclass, jbyte joystickNum, jfloatArray axesArray)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HALJoystickAxes";
   HAL_JoystickAxes axes;
   HAL_GetJoystickAxes(joystickNum, &axes);
 
@@ -200,7 +219,6 @@
 Java_edu_wpi_first_hal_HAL_getJoystickPOVs
   (JNIEnv* env, jclass, jbyte joystickNum, jshortArray povsArray)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HALJoystickPOVs";
   HAL_JoystickPOVs povs;
   HAL_GetJoystickPOVs(joystickNum, &povs);
 
@@ -230,15 +248,11 @@
 Java_edu_wpi_first_hal_HAL_getJoystickButtons
   (JNIEnv* env, jclass, jbyte joystickNum, jobject count)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HALJoystickButtons";
   HAL_JoystickButtons joystickButtons;
   HAL_GetJoystickButtons(joystickNum, &joystickButtons);
   jbyte* countPtr =
       reinterpret_cast<jbyte*>(env->GetDirectBufferAddress(count));
-  NETCOMM_LOG(logDEBUG) << "Buttons = " << joystickButtons.buttons;
-  NETCOMM_LOG(logDEBUG) << "Count = " << (jint)joystickButtons.count;
   *countPtr = joystickButtons.count;
-  NETCOMM_LOG(logDEBUG) << "CountBuffer = " << (jint)*countPtr;
   return joystickButtons.buttons;
 }
 
@@ -252,10 +266,6 @@
   (JNIEnv*, jclass, jbyte port, jint outputs, jshort leftRumble,
    jshort rightRumble)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HAL_SetJoystickOutputs on port " << port;
-  NETCOMM_LOG(logDEBUG) << "Outputs: " << outputs;
-  NETCOMM_LOG(logDEBUG) << "Left Rumble: " << leftRumble
-                        << " Right Rumble: " << rightRumble;
   return HAL_SetJoystickOutputs(port, outputs, leftRumble, rightRumble);
 }
 
@@ -268,7 +278,6 @@
 Java_edu_wpi_first_hal_HAL_getJoystickIsXbox
   (JNIEnv*, jclass, jbyte port)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickIsXbox";
   return HAL_GetJoystickIsXbox(port);
 }
 
@@ -281,7 +290,6 @@
 Java_edu_wpi_first_hal_HAL_getJoystickType
   (JNIEnv*, jclass, jbyte port)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickType";
   return HAL_GetJoystickType(port);
 }
 
@@ -294,7 +302,6 @@
 Java_edu_wpi_first_hal_HAL_getJoystickName
   (JNIEnv* env, jclass, jbyte port)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickName";
   char* joystickName = HAL_GetJoystickName(port);
   jstring str = MakeJString(env, joystickName);
   HAL_FreeJoystickName(joystickName);
@@ -310,7 +317,6 @@
 Java_edu_wpi_first_hal_HAL_getJoystickAxisType
   (JNIEnv*, jclass, jbyte joystickNum, jbyte axis)
 {
-  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickAxisType";
   return HAL_GetJoystickAxisType(joystickNum, axis);
 }
 
@@ -436,9 +442,6 @@
   JStringRef locationStr{env, location};
   JStringRef callStackStr{env, callStack};
 
-  NETCOMM_LOG(logDEBUG) << "Send Error: " << detailsStr.c_str();
-  NETCOMM_LOG(logDEBUG) << "Location: " << locationStr.c_str();
-  NETCOMM_LOG(logDEBUG) << "Call Stack: " << callStackStr.c_str();
   jint returnValue =
       HAL_SendError(isError, errorCode, isLVCode, detailsStr.c_str(),
                     locationStr.c_str(), callStackStr.c_str(), printMsg);
@@ -454,11 +457,7 @@
 Java_edu_wpi_first_hal_HAL_getPortWithModule
   (JNIEnv* env, jclass, jbyte module, jbyte channel)
 {
-  // FILE_LOG(logDEBUG) << "Calling HAL getPortWithModlue";
-  // FILE_LOG(logDEBUG) << "Module = " << (jint)module;
-  // FILE_LOG(logDEBUG) << "Channel = " << (jint)channel;
   HAL_PortHandle port = HAL_GetPortWithModule(module, channel);
-  // FILE_LOG(logDEBUG) << "Port Handle = " << port;
   return (jint)port;
 }
 
@@ -471,11 +470,7 @@
 Java_edu_wpi_first_hal_HAL_getPort
   (JNIEnv* env, jclass, jbyte channel)
 {
-  // FILE_LOG(logDEBUG) << "Calling HAL getPortWithModlue";
-  // FILE_LOG(logDEBUG) << "Module = " << (jint)module;
-  // FILE_LOG(logDEBUG) << "Channel = " << (jint)channel;
   HAL_PortHandle port = HAL_GetPort(channel);
-  // FILE_LOG(logDEBUG) << "Port Handle = " << port;
   return (jint)port;
 }
 
diff --git a/hal/src/main/native/cpp/jni/HALUtil.cpp b/hal/src/main/native/cpp/jni/HALUtil.cpp
index 92d09b4..26b7919 100644
--- a/hal/src/main/native/cpp/jni/HALUtil.cpp
+++ b/hal/src/main/native/cpp/jni/HALUtil.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -24,19 +24,9 @@
 #include "hal/DriverStation.h"
 #include "hal/Errors.h"
 #include "hal/HAL.h"
-#include "hal/cpp/Log.h"
 
 using namespace wpi::java;
 
-// set the logging level
-TLogLevel halUtilLogLevel = logWARNING;
-
-#define HALUTIL_LOG(level)     \
-  if (level > halUtilLogLevel) \
-    ;                          \
-  else                         \
-    Log().Get(level)
-
 #define kRioStatusOffset -63000
 #define kRioStatusSuccess 0
 #define kRIOStatusBufferInvalidSize (kRioStatusOffset - 80)
@@ -59,13 +49,15 @@
 static JClass matchInfoDataCls;
 static JClass accumulatorResultCls;
 static JClass canDataCls;
+static JClass halValueCls;
 
 static const JClassInit classes[] = {
     {"edu/wpi/first/hal/PWMConfigDataResult", &pwmConfigDataResultCls},
     {"edu/wpi/first/hal/can/CANStatus", &canStatusCls},
     {"edu/wpi/first/hal/MatchInfoData", &matchInfoDataCls},
     {"edu/wpi/first/hal/AccumulatorResult", &accumulatorResultCls},
-    {"edu/wpi/first/hal/CANData", &canDataCls}};
+    {"edu/wpi/first/hal/CANData", &canDataCls},
+    {"edu/wpi/first/hal/HALValue", &halValueCls}};
 
 static const JExceptionInit exceptions[] = {
     {"java/lang/IllegalArgumentException", &illegalArgExCls},
@@ -234,8 +226,9 @@
                                   int32_t deadbandMinPwm, int32_t minPwm) {
   static jmethodID constructor =
       env->GetMethodID(pwmConfigDataResultCls, "<init>", "(IIIII)V");
-  return env->NewObject(pwmConfigDataResultCls, constructor, maxPwm,
-                        deadbandMaxPwm, centerPwm, deadbandMinPwm, minPwm);
+  return env->NewObject(pwmConfigDataResultCls, constructor, (jint)maxPwm,
+                        (jint)deadbandMaxPwm, (jint)centerPwm,
+                        (jint)deadbandMinPwm, (jint)minPwm);
 }
 
 void SetCanStatusObject(JNIEnv* env, jobject canStatus,
@@ -281,6 +274,34 @@
   return retVal;
 }
 
+jobject CreateHALValue(JNIEnv* env, const HAL_Value& value) {
+  static jmethodID fromNative = env->GetStaticMethodID(
+      halValueCls, "fromNative", "(IJD)Ledu/wpi/first/hal/HALValue;");
+  jlong value1 = 0;
+  jdouble value2 = 0.0;
+  switch (value.type) {
+    case HAL_BOOLEAN:
+      value1 = value.data.v_boolean;
+      break;
+    case HAL_DOUBLE:
+      value2 = value.data.v_double;
+      break;
+    case HAL_ENUM:
+      value1 = value.data.v_enum;
+      break;
+    case HAL_INT:
+      value1 = value.data.v_int;
+      break;
+    case HAL_LONG:
+      value1 = value.data.v_long;
+      break;
+    default:
+      break;
+  }
+  return env->CallStaticObjectMethod(halValueCls, fromNative, (jint)value.type,
+                                     value1, value2);
+}
+
 JavaVM* GetJVM() { return jvm; }
 
 }  // namespace frc
@@ -300,9 +321,6 @@
 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
   jvm = vm;
 
-  // set our logging level
-  Log::ReportingLevel() = logDEBUG;
-
   JNIEnv* env;
   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
     return JNI_ERR;
@@ -346,11 +364,8 @@
 Java_edu_wpi_first_hal_HALUtil_getFPGAVersion
   (JNIEnv* env, jclass)
 {
-  HALUTIL_LOG(logDEBUG) << "Calling HALUtil getFPGAVersion";
   int32_t status = 0;
   jshort returnValue = HAL_GetFPGAVersion(&status);
-  HALUTIL_LOG(logDEBUG) << "Status = " << status;
-  HALUTIL_LOG(logDEBUG) << "FPGAVersion = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -364,11 +379,8 @@
 Java_edu_wpi_first_hal_HALUtil_getFPGARevision
   (JNIEnv* env, jclass)
 {
-  HALUTIL_LOG(logDEBUG) << "Calling HALUtil getFPGARevision";
   int32_t status = 0;
   jint returnValue = HAL_GetFPGARevision(&status);
-  HALUTIL_LOG(logDEBUG) << "Status = " << status;
-  HALUTIL_LOG(logDEBUG) << "FPGARevision = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -382,11 +394,8 @@
 Java_edu_wpi_first_hal_HALUtil_getFPGATime
   (JNIEnv* env, jclass)
 {
-  // HALUTIL_LOG(logDEBUG) << "Calling HALUtil getFPGATime";
   int32_t status = 0;
   jlong returnValue = HAL_GetFPGATime(&status);
-  // HALUTIL_LOG(logDEBUG) << "Status = " << status;
-  // HALUTIL_LOG(logDEBUG) << "FPGATime = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -400,9 +409,7 @@
 Java_edu_wpi_first_hal_HALUtil_getHALRuntimeType
   (JNIEnv* env, jclass)
 {
-  // HALUTIL_LOG(logDEBUG) << "Calling HALUtil getHALRuntimeType";
   jint returnValue = HAL_GetRuntimeType();
-  // HALUTIL_LOG(logDEBUG) << "RuntimeType = " << returnValue;
   return returnValue;
 }
 
@@ -415,11 +422,8 @@
 Java_edu_wpi_first_hal_HALUtil_getFPGAButton
   (JNIEnv* env, jclass)
 {
-  // HALUTIL_LOG(logDEBUG) << "Calling HALUtil getFPGATime";
   int32_t status = 0;
   jboolean returnValue = HAL_GetFPGAButton(&status);
-  // HALUTIL_LOG(logDEBUG) << "Status = " << status;
-  // HALUTIL_LOG(logDEBUG) << "FPGATime = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -434,8 +438,6 @@
   (JNIEnv* paramEnv, jclass, jint paramId)
 {
   const char* msg = HAL_GetErrorMessage(paramId);
-  HALUTIL_LOG(logDEBUG) << "Calling HALUtil HAL_GetErrorMessage id=" << paramId
-                        << " msg=" << msg;
   return MakeJString(paramEnv, msg);
 }
 
@@ -461,8 +463,6 @@
   (JNIEnv* env, jclass, jint errorCode)
 {
   const char* msg = std::strerror(errno);
-  HALUTIL_LOG(logDEBUG) << "Calling HALUtil getHALstrerror errorCode="
-                        << errorCode << " msg=" << msg;
   return MakeJString(env, msg);
 }
 
diff --git a/hal/src/main/native/cpp/jni/HALUtil.h b/hal/src/main/native/cpp/jni/HALUtil.h
index 8197e1a..c035f75 100644
--- a/hal/src/main/native/cpp/jni/HALUtil.h
+++ b/hal/src/main/native/cpp/jni/HALUtil.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -14,6 +14,7 @@
 #include <wpi/StringRef.h>
 
 struct HAL_MatchInfo;
+struct HAL_Value;
 
 namespace frc {
 
@@ -67,6 +68,8 @@
 jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
                             uint64_t timestamp);
 
+jobject CreateHALValue(JNIEnv* env, const HAL_Value& value);
+
 JavaVM* GetJVM();
 
 }  // namespace frc
diff --git a/hal/src/main/native/cpp/jni/I2CJNI.cpp b/hal/src/main/native/cpp/jni/I2CJNI.cpp
index 9dafd4a..7812bdb 100644
--- a/hal/src/main/native/cpp/jni/I2CJNI.cpp
+++ b/hal/src/main/native/cpp/jni/I2CJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -14,20 +14,10 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_I2CJNI.h"
 #include "hal/I2C.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 using namespace wpi::java;
 
-// set the logging level
-TLogLevel i2cJNILogLevel = logWARNING;
-
-#define I2CJNI_LOG(level)     \
-  if (level > i2cJNILogLevel) \
-    ;                         \
-  else                        \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -39,11 +29,8 @@
 Java_edu_wpi_first_hal_I2CJNI_i2CInitialize
   (JNIEnv* env, jclass, jint port)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CInititalize";
-  I2CJNI_LOG(logDEBUG) << "Port: " << port;
   int32_t status = 0;
   HAL_InitializeI2C(static_cast<HAL_I2CPort>(port), &status);
-  I2CJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatusForceThrow(env, status);
 }
 
@@ -57,26 +44,16 @@
   (JNIEnv* env, jclass, jint port, jbyte address, jobject dataToSend,
    jbyte sendSize, jobject dataReceived, jbyte receiveSize)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CTransaction";
-  I2CJNI_LOG(logDEBUG) << "Port = " << port;
-  I2CJNI_LOG(logDEBUG) << "Address = " << (jint)address;
   uint8_t* dataToSendPtr = nullptr;
   if (dataToSend != 0) {
     dataToSendPtr =
         reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
   }
-  I2CJNI_LOG(logDEBUG) << "DataToSendPtr = "
-                       << reinterpret_cast<jint*>(dataToSendPtr);
-  I2CJNI_LOG(logDEBUG) << "SendSize = " << (jint)sendSize;
   uint8_t* dataReceivedPtr =
       reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataReceived));
-  I2CJNI_LOG(logDEBUG) << "DataReceivedPtr = "
-                       << reinterpret_cast<jint*>(dataReceivedPtr);
-  I2CJNI_LOG(logDEBUG) << "ReceiveSize = " << (jint)receiveSize;
   jint returnValue =
       HAL_TransactionI2C(static_cast<HAL_I2CPort>(port), address, dataToSendPtr,
                          sendSize, dataReceivedPtr, receiveSize);
-  I2CJNI_LOG(logDEBUG) << "ReturnValue = " << returnValue;
   return returnValue;
 }
 
@@ -90,13 +67,8 @@
   (JNIEnv* env, jclass, jint port, jbyte address, jbyteArray dataToSend,
    jbyte sendSize, jbyteArray dataReceived, jbyte receiveSize)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CTransactionB";
-  I2CJNI_LOG(logDEBUG) << "Port = " << port;
-  I2CJNI_LOG(logDEBUG) << "Address = " << (jint)address;
-  I2CJNI_LOG(logDEBUG) << "SendSize = " << (jint)sendSize;
   wpi::SmallVector<uint8_t, 128> recvBuf;
   recvBuf.resize(receiveSize);
-  I2CJNI_LOG(logDEBUG) << "ReceiveSize = " << (jint)receiveSize;
   jint returnValue =
       HAL_TransactionI2C(static_cast<HAL_I2CPort>(port), address,
                          reinterpret_cast<const uint8_t*>(
@@ -104,7 +76,6 @@
                          sendSize, recvBuf.data(), receiveSize);
   env->SetByteArrayRegion(dataReceived, 0, receiveSize,
                           reinterpret_cast<const jbyte*>(recvBuf.data()));
-  I2CJNI_LOG(logDEBUG) << "ReturnValue = " << returnValue;
   return returnValue;
 }
 
@@ -118,20 +89,14 @@
   (JNIEnv* env, jclass, jint port, jbyte address, jobject dataToSend,
    jbyte sendSize)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CWrite";
-  I2CJNI_LOG(logDEBUG) << "Port = " << port;
-  I2CJNI_LOG(logDEBUG) << "Address = " << (jint)address;
   uint8_t* dataToSendPtr = nullptr;
 
   if (dataToSend != 0) {
     dataToSendPtr =
         reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
   }
-  I2CJNI_LOG(logDEBUG) << "DataToSendPtr = " << dataToSendPtr;
-  I2CJNI_LOG(logDEBUG) << "SendSize = " << (jint)sendSize;
   jint returnValue = HAL_WriteI2C(static_cast<HAL_I2CPort>(port), address,
                                   dataToSendPtr, sendSize);
-  I2CJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)returnValue;
   return returnValue;
 }
 
@@ -145,16 +110,11 @@
   (JNIEnv* env, jclass, jint port, jbyte address, jbyteArray dataToSend,
    jbyte sendSize)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CWrite";
-  I2CJNI_LOG(logDEBUG) << "Port = " << port;
-  I2CJNI_LOG(logDEBUG) << "Address = " << (jint)address;
-  I2CJNI_LOG(logDEBUG) << "SendSize = " << (jint)sendSize;
   jint returnValue =
       HAL_WriteI2C(static_cast<HAL_I2CPort>(port), address,
                    reinterpret_cast<const uint8_t*>(
                        JByteArrayRef(env, dataToSend).array().data()),
                    sendSize);
-  I2CJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)returnValue;
   return returnValue;
 }
 
@@ -168,16 +128,10 @@
   (JNIEnv* env, jclass, jint port, jbyte address, jobject dataReceived,
    jbyte receiveSize)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CRead";
-  I2CJNI_LOG(logDEBUG) << "Port = " << port;
-  I2CJNI_LOG(logDEBUG) << "Address = " << address;
   uint8_t* dataReceivedPtr =
       reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataReceived));
-  I2CJNI_LOG(logDEBUG) << "DataReceivedPtr = " << dataReceivedPtr;
-  I2CJNI_LOG(logDEBUG) << "ReceiveSize = " << receiveSize;
   jint returnValue = HAL_ReadI2C(static_cast<HAL_I2CPort>(port), address,
                                  dataReceivedPtr, receiveSize);
-  I2CJNI_LOG(logDEBUG) << "ReturnValue = " << returnValue;
   return returnValue;
 }
 
@@ -191,17 +145,12 @@
   (JNIEnv* env, jclass, jint port, jbyte address, jbyteArray dataReceived,
    jbyte receiveSize)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CRead";
-  I2CJNI_LOG(logDEBUG) << "Port = " << port;
-  I2CJNI_LOG(logDEBUG) << "Address = " << address;
-  I2CJNI_LOG(logDEBUG) << "ReceiveSize = " << receiveSize;
   wpi::SmallVector<uint8_t, 128> recvBuf;
   recvBuf.resize(receiveSize);
   jint returnValue = HAL_ReadI2C(static_cast<HAL_I2CPort>(port), address,
                                  recvBuf.data(), receiveSize);
   env->SetByteArrayRegion(dataReceived, 0, receiveSize,
                           reinterpret_cast<const jbyte*>(recvBuf.data()));
-  I2CJNI_LOG(logDEBUG) << "ReturnValue = " << returnValue;
   return returnValue;
 }
 
@@ -214,7 +163,6 @@
 Java_edu_wpi_first_hal_I2CJNI_i2CClose
   (JNIEnv*, jclass, jint port)
 {
-  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CClose";
   HAL_CloseI2C(static_cast<HAL_I2CPort>(port));
 }
 
diff --git a/hal/src/main/native/cpp/jni/InterruptJNI.cpp b/hal/src/main/native/cpp/jni/InterruptJNI.cpp
index 2dd4abf..e3a783d 100644
--- a/hal/src/main/native/cpp/jni/InterruptJNI.cpp
+++ b/hal/src/main/native/cpp/jni/InterruptJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -17,18 +17,9 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_InterruptJNI.h"
 #include "hal/Interrupts.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
-TLogLevel interruptJNILogLevel = logERROR;
-
-#define INTERRUPTJNI_LOG(level)     \
-  if (level > interruptJNILogLevel) \
-    ;                               \
-  else                              \
-    Log().Get(level)
-
 // Thread where callbacks are actually performed.
 //
 // JNI's AttachCurrentThread() creates a Java Thread object on every
@@ -88,7 +79,7 @@
       reinterpret_cast<void**>(&env), &args);
   if (rs != JNI_OK) return;
 
-  std::unique_lock<wpi::mutex> lock(m_mutex);
+  std::unique_lock lock(m_mutex);
   while (m_active) {
     m_cond.wait(lock, [&] { return !m_active || m_notify; });
     if (!m_active) break;
@@ -129,15 +120,9 @@
 Java_edu_wpi_first_hal_InterruptJNI_initializeInterrupts
   (JNIEnv* env, jclass, jboolean watcher)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI initializeInterrupts";
-  INTERRUPTJNI_LOG(logDEBUG) << "watcher = " << static_cast<bool>(watcher);
-
   int32_t status = 0;
   HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(watcher, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Interrupt Handle = " << interrupt;
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
-
   CheckStatusForceThrow(env, status);
   return (jint)interrupt;
 }
@@ -151,10 +136,6 @@
 Java_edu_wpi_first_hal_InterruptJNI_cleanInterrupts
   (JNIEnv* env, jclass, jint interruptHandle)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI cleanInterrupts";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-
   int32_t status = 0;
   auto param =
       HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle, &status);
@@ -162,8 +143,6 @@
     delete static_cast<InterruptJNI*>(param);
   }
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
-
   // ignore status, as an invalid handle just needs to be ignored.
 }
 
@@ -177,16 +156,10 @@
   (JNIEnv* env, jclass, jint interruptHandle, jdouble timeout,
    jboolean ignorePrevious)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI waitForInterrupt";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-
   int32_t status = 0;
   int32_t result = HAL_WaitForInterrupt((HAL_InterruptHandle)interruptHandle,
                                         timeout, ignorePrevious, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
-
   CheckStatus(env, status);
   return result;
 }
@@ -200,15 +173,9 @@
 Java_edu_wpi_first_hal_InterruptJNI_enableInterrupts
   (JNIEnv* env, jclass, jint interruptHandle)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI enableInterrupts";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-
   int32_t status = 0;
   HAL_EnableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
-
   CheckStatus(env, status);
 }
 
@@ -221,15 +188,9 @@
 Java_edu_wpi_first_hal_InterruptJNI_disableInterrupts
   (JNIEnv* env, jclass, jint interruptHandle)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI disableInterrupts";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-
   int32_t status = 0;
   HAL_DisableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
-
   CheckStatus(env, status);
 }
 
@@ -242,16 +203,10 @@
 Java_edu_wpi_first_hal_InterruptJNI_readInterruptRisingTimestamp
   (JNIEnv* env, jclass, jint interruptHandle)
 {
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Calling INTERRUPTJNI readInterruptRisingTimestamp";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-
   int32_t status = 0;
   jlong timeStamp = HAL_ReadInterruptRisingTimestamp(
       (HAL_InterruptHandle)interruptHandle, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
   return timeStamp;
 }
@@ -265,16 +220,10 @@
 Java_edu_wpi_first_hal_InterruptJNI_readInterruptFallingTimestamp
   (JNIEnv* env, jclass, jint interruptHandle)
 {
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Calling INTERRUPTJNI readInterruptFallingTimestamp";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-
   int32_t status = 0;
   jlong timeStamp = HAL_ReadInterruptFallingTimestamp(
       (HAL_InterruptHandle)interruptHandle, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
   return timeStamp;
 }
@@ -289,18 +238,11 @@
   (JNIEnv* env, jclass, jint interruptHandle, jint digitalSourceHandle,
    jint analogTriggerType)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI requestInterrupts";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-  INTERRUPTJNI_LOG(logDEBUG) << "digitalSourceHandle = " << digitalSourceHandle;
-  INTERRUPTJNI_LOG(logDEBUG) << "analogTriggerType = " << analogTriggerType;
-
   int32_t status = 0;
   HAL_RequestInterrupts((HAL_InterruptHandle)interruptHandle,
                         (HAL_Handle)digitalSourceHandle,
                         (HAL_AnalogTriggerType)analogTriggerType, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -313,21 +255,13 @@
 Java_edu_wpi_first_hal_InterruptJNI_attachInterruptHandler
   (JNIEnv* env, jclass, jint interruptHandle, jobject handler, jobject param)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI attachInterruptHandler";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-
   jclass cls = env->GetObjectClass(handler);
-  INTERRUPTJNI_LOG(logDEBUG) << "class = " << cls;
   if (cls == 0) {
-    INTERRUPTJNI_LOG(logERROR) << "Error getting java class";
     assert(false);
     return;
   }
   jmethodID mid = env->GetMethodID(cls, "apply", "(ILjava/lang/Object;)V");
-  INTERRUPTJNI_LOG(logDEBUG) << "method = " << mid;
   if (mid == 0) {
-    INTERRUPTJNI_LOG(logERROR) << "Error getting java method ID";
     assert(false);
     return;
   }
@@ -336,13 +270,10 @@
   intr->Start();
   intr->SetFunc(env, handler, mid, param);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "InterruptThreadJNI Ptr = " << intr;
-
   int32_t status = 0;
   HAL_AttachInterruptHandler((HAL_InterruptHandle)interruptHandle,
                              interruptHandler, intr, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -356,19 +287,10 @@
   (JNIEnv* env, jclass, jint interruptHandle, jboolean risingEdge,
    jboolean fallingEdge)
 {
-  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI setInterruptUpSourceEdge";
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Interrupt Handle = " << (HAL_InterruptHandle)interruptHandle;
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Rising Edge = " << static_cast<bool>(risingEdge);
-  INTERRUPTJNI_LOG(logDEBUG)
-      << "Falling Edge = " << static_cast<bool>(fallingEdge);
-
   int32_t status = 0;
   HAL_SetInterruptUpSourceEdge((HAL_InterruptHandle)interruptHandle, risingEdge,
                                fallingEdge, &status);
 
-  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
diff --git a/hal/src/main/native/cpp/jni/NotifierJNI.cpp b/hal/src/main/native/cpp/jni/NotifierJNI.cpp
index 61fe32f..588614e 100644
--- a/hal/src/main/native/cpp/jni/NotifierJNI.cpp
+++ b/hal/src/main/native/cpp/jni/NotifierJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,19 +13,9 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_NotifierJNI.h"
 #include "hal/Notifier.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel notifierJNILogLevel = logWARNING;
-
-#define NOTIFIERJNI_LOG(level)     \
-  if (level > notifierJNILogLevel) \
-    ;                              \
-  else                             \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -37,14 +27,9 @@
 Java_edu_wpi_first_hal_NotifierJNI_initializeNotifier
   (JNIEnv* env, jclass)
 {
-  NOTIFIERJNI_LOG(logDEBUG) << "Calling NOTIFIERJNI initializeNotifier";
-
   int32_t status = 0;
   HAL_NotifierHandle notifierHandle = HAL_InitializeNotifier(&status);
 
-  NOTIFIERJNI_LOG(logDEBUG) << "Notifier Handle = " << notifierHandle;
-  NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status;
-
   if (notifierHandle <= 0 || !CheckStatusForceThrow(env, status)) {
     return 0;  // something went wrong in HAL
   }
@@ -61,13 +46,8 @@
 Java_edu_wpi_first_hal_NotifierJNI_stopNotifier
   (JNIEnv* env, jclass cls, jint notifierHandle)
 {
-  NOTIFIERJNI_LOG(logDEBUG) << "Calling NOTIFIERJNI stopNotifier";
-
-  NOTIFIERJNI_LOG(logDEBUG) << "Notifier Handle = " << notifierHandle;
-
   int32_t status = 0;
   HAL_StopNotifier((HAL_NotifierHandle)notifierHandle, &status);
-  NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -80,13 +60,8 @@
 Java_edu_wpi_first_hal_NotifierJNI_cleanNotifier
   (JNIEnv* env, jclass, jint notifierHandle)
 {
-  NOTIFIERJNI_LOG(logDEBUG) << "Calling NOTIFIERJNI cleanNotifier";
-
-  NOTIFIERJNI_LOG(logDEBUG) << "Notifier Handle = " << notifierHandle;
-
   int32_t status = 0;
   HAL_CleanNotifier((HAL_NotifierHandle)notifierHandle, &status);
-  NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -99,16 +74,9 @@
 Java_edu_wpi_first_hal_NotifierJNI_updateNotifierAlarm
   (JNIEnv* env, jclass cls, jint notifierHandle, jlong triggerTime)
 {
-  NOTIFIERJNI_LOG(logDEBUG) << "Calling NOTIFIERJNI updateNotifierAlarm";
-
-  NOTIFIERJNI_LOG(logDEBUG) << "Notifier Handle = " << notifierHandle;
-
-  NOTIFIERJNI_LOG(logDEBUG) << "triggerTime = " << triggerTime;
-
   int32_t status = 0;
   HAL_UpdateNotifierAlarm((HAL_NotifierHandle)notifierHandle,
                           static_cast<uint64_t>(triggerTime), &status);
-  NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -121,13 +89,8 @@
 Java_edu_wpi_first_hal_NotifierJNI_cancelNotifierAlarm
   (JNIEnv* env, jclass cls, jint notifierHandle)
 {
-  NOTIFIERJNI_LOG(logDEBUG) << "Calling NOTIFIERJNI cancelNotifierAlarm";
-
-  NOTIFIERJNI_LOG(logDEBUG) << "Notifier Handle = " << notifierHandle;
-
   int32_t status = 0;
   HAL_CancelNotifierAlarm((HAL_NotifierHandle)notifierHandle, &status);
-  NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -140,15 +103,10 @@
 Java_edu_wpi_first_hal_NotifierJNI_waitForNotifierAlarm
   (JNIEnv* env, jclass cls, jint notifierHandle)
 {
-  NOTIFIERJNI_LOG(logDEBUG) << "Calling NOTIFIERJNI waitForNotifierAlarm";
-
-  NOTIFIERJNI_LOG(logDEBUG) << "Notifier Handle = " << notifierHandle;
-
   int32_t status = 0;
   uint64_t time =
       HAL_WaitForNotifierAlarm((HAL_NotifierHandle)notifierHandle, &status);
-  NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status;
-  NOTIFIERJNI_LOG(logDEBUG) << "Time = " << time;
+
   CheckStatus(env, status);
 
   return (jlong)time;
diff --git a/hal/src/main/native/cpp/jni/PWMJNI.cpp b/hal/src/main/native/cpp/jni/PWMJNI.cpp
index 1509f94..80293c4 100644
--- a/hal/src/main/native/cpp/jni/PWMJNI.cpp
+++ b/hal/src/main/native/cpp/jni/PWMJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -14,20 +14,10 @@
 #include "hal/DIO.h"
 #include "hal/PWM.h"
 #include "hal/Ports.h"
-#include "hal/cpp/Log.h"
 #include "hal/handles/HandlesInternal.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel pwmJNILogLevel = logWARNING;
-
-#define PWMJNI_LOG(level)     \
-  if (level > pwmJNILogLevel) \
-    ;                         \
-  else                        \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -39,12 +29,8 @@
 Java_edu_wpi_first_hal_PWMJNI_initializePWMPort
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "Calling PWMJNI initializePWMPort";
-  PWMJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_PortHandle)id;
   int32_t status = 0;
   auto pwm = HAL_InitializePWMPort((HAL_PortHandle)id, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << pwm;
   CheckStatusRange(env, status, 0, HAL_GetNumPWMChannels(),
                    hal::getPortHandleChannel((HAL_PortHandle)id));
   return (jint)pwm;
@@ -59,8 +45,6 @@
 Java_edu_wpi_first_hal_PWMJNI_checkPWMChannel
   (JNIEnv* env, jclass, jint channel)
 {
-  PWMJNI_LOG(logDEBUG) << "Calling PWMJNI checkPWMChannel";
-  PWMJNI_LOG(logDEBUG) << "Channel = " << channel;
   return HAL_CheckPWMChannel(channel);
 }
 
@@ -73,8 +57,6 @@
 Java_edu_wpi_first_hal_PWMJNI_freePWMPort
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "Calling PWMJNI freePWMPort";
-  PWMJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   HAL_FreePWMPort((HAL_DigitalHandle)id, &status);
   CheckStatus(env, status);
@@ -90,8 +72,6 @@
   (JNIEnv* env, jclass, jint id, jint maxPwm, jint deadbandMaxPwm,
    jint centerPwm, jint deadbandMinPwm, jint minPwm)
 {
-  PWMJNI_LOG(logDEBUG) << "Calling PWMJNI setPWMConfigRaw";
-  PWMJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   HAL_SetPWMConfigRaw((HAL_DigitalHandle)id, maxPwm, deadbandMaxPwm, centerPwm,
                       deadbandMinPwm, minPwm, &status);
@@ -108,8 +88,6 @@
   (JNIEnv* env, jclass, jint id, jdouble maxPwm, jdouble deadbandMaxPwm,
    jdouble centerPwm, jdouble deadbandMinPwm, jdouble minPwm)
 {
-  PWMJNI_LOG(logDEBUG) << "Calling PWMJNI setPWMConfig";
-  PWMJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   HAL_SetPWMConfig((HAL_DigitalHandle)id, maxPwm, deadbandMaxPwm, centerPwm,
                    deadbandMinPwm, minPwm, &status);
@@ -125,8 +103,6 @@
 Java_edu_wpi_first_hal_PWMJNI_getPWMConfigRaw
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "Calling PWMJNI getPWMConfigRaw";
-  PWMJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   int32_t maxPwm = 0;
   int32_t deadbandMaxPwm = 0;
@@ -149,10 +125,8 @@
 Java_edu_wpi_first_hal_PWMJNI_setPWMEliminateDeadband
   (JNIEnv* env, jclass, jint id, jboolean value)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   HAL_SetPWMEliminateDeadband((HAL_DigitalHandle)id, value, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -165,10 +139,8 @@
 Java_edu_wpi_first_hal_PWMJNI_getPWMEliminateDeadband
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   auto val = HAL_GetPWMEliminateDeadband((HAL_DigitalHandle)id, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
   return (jboolean)val;
 }
@@ -182,11 +154,8 @@
 Java_edu_wpi_first_hal_PWMJNI_setPWMRaw
   (JNIEnv* env, jclass, jint id, jshort value)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
-  PWMJNI_LOG(logDEBUG) << "PWM Value = " << value;
   int32_t status = 0;
   HAL_SetPWMRaw((HAL_DigitalHandle)id, value, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -199,11 +168,8 @@
 Java_edu_wpi_first_hal_PWMJNI_setPWMSpeed
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
-  PWMJNI_LOG(logDEBUG) << "PWM Value = " << value;
   int32_t status = 0;
   HAL_SetPWMSpeed((HAL_DigitalHandle)id, value, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -216,11 +182,8 @@
 Java_edu_wpi_first_hal_PWMJNI_setPWMPosition
   (JNIEnv* env, jclass, jint id, jdouble value)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
-  PWMJNI_LOG(logDEBUG) << "PWM Value = " << value;
   int32_t status = 0;
   HAL_SetPWMPosition((HAL_DigitalHandle)id, value, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -233,11 +196,8 @@
 Java_edu_wpi_first_hal_PWMJNI_getPWMRaw
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   jshort returnValue = HAL_GetPWMRaw((HAL_DigitalHandle)id, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
-  PWMJNI_LOG(logDEBUG) << "Value = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -251,11 +211,8 @@
 Java_edu_wpi_first_hal_PWMJNI_getPWMSpeed
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   jdouble returnValue = HAL_GetPWMSpeed((HAL_DigitalHandle)id, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
-  PWMJNI_LOG(logDEBUG) << "Value = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -269,11 +226,8 @@
 Java_edu_wpi_first_hal_PWMJNI_getPWMPosition
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   jdouble returnValue = HAL_GetPWMPosition((HAL_DigitalHandle)id, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
-  PWMJNI_LOG(logDEBUG) << "Value = " << returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
@@ -287,10 +241,8 @@
 Java_edu_wpi_first_hal_PWMJNI_setPWMDisabled
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   HAL_SetPWMDisabled((HAL_DigitalHandle)id, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -303,10 +255,8 @@
 Java_edu_wpi_first_hal_PWMJNI_latchPWMZero
   (JNIEnv* env, jclass, jint id)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
   int32_t status = 0;
   HAL_LatchPWMZero((HAL_DigitalHandle)id, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -319,11 +269,8 @@
 Java_edu_wpi_first_hal_PWMJNI_setPWMPeriodScale
   (JNIEnv* env, jclass, jint id, jint value)
 {
-  PWMJNI_LOG(logDEBUG) << "PWM Handle = " << (HAL_DigitalHandle)id;
-  PWMJNI_LOG(logDEBUG) << "PeriodScale Value = " << value;
   int32_t status = 0;
   HAL_SetPWMPeriodScale((HAL_DigitalHandle)id, value, &status);
-  PWMJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
diff --git a/hal/src/main/native/cpp/jni/PortsJNI.cpp b/hal/src/main/native/cpp/jni/PortsJNI.cpp
index 4e14984..1adb7fb 100644
--- a/hal/src/main/native/cpp/jni/PortsJNI.cpp
+++ b/hal/src/main/native/cpp/jni/PortsJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -12,19 +12,9 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_PortsJNI.h"
 #include "hal/Ports.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel portsJNILogLevel = logWARNING;
-
-#define PORTSJNI_LOG(level)     \
-  if (level > portsJNILogLevel) \
-    ;                           \
-  else                          \
-    Log().Get(level)
-
 extern "C" {
 /*
  * Class:     edu_wpi_first_hal_PortsJNI
@@ -35,9 +25,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumAccumulators
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumAccumulators";
   jint value = HAL_GetNumAccumulators();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -50,9 +38,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumAnalogTriggers
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumAnalogTriggers";
   jint value = HAL_GetNumAnalogTriggers();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -65,9 +51,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumAnalogInputs
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumAnalogInputs";
   jint value = HAL_GetNumAnalogInputs();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -80,9 +64,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumAnalogOutputs
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumAnalogOutputs";
   jint value = HAL_GetNumAnalogOutputs();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -95,9 +77,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumCounters
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumCounters";
   jint value = HAL_GetNumCounters();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -110,9 +90,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumDigitalHeaders
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumDigitalHeaders";
   jint value = HAL_GetNumDigitalHeaders();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -125,9 +103,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumPWMHeaders
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumPWMHeaders";
   jint value = HAL_GetNumPWMHeaders();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -140,9 +116,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumDigitalChannels
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumDigitalChannels";
   jint value = HAL_GetNumDigitalChannels();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -155,9 +129,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumPWMChannels
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumPWMChannels";
   jint value = HAL_GetNumPWMChannels();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -170,9 +142,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumDigitalPWMOutputs
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumDigitalPWMOutputs";
   jint value = HAL_GetNumDigitalPWMOutputs();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -185,9 +155,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumEncoders
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumEncoders";
   jint value = HAL_GetNumEncoders();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -200,9 +168,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumInterrupts
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumInterrupts";
   jint value = HAL_GetNumInterrupts();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -215,9 +181,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumRelayChannels
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumRelayChannels";
   jint value = HAL_GetNumRelayChannels();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -230,9 +194,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumRelayHeaders
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumRelayHeaders";
   jint value = HAL_GetNumRelayHeaders();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -245,9 +207,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumPCMModules
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumPCMModules";
   jint value = HAL_GetNumPCMModules();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -260,9 +220,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumSolenoidChannels
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumSolenoidChannels";
   jint value = HAL_GetNumSolenoidChannels();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -275,9 +233,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumPDPModules
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumPDPModules";
   jint value = HAL_GetNumPDPModules();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 
@@ -290,9 +246,7 @@
 Java_edu_wpi_first_hal_PortsJNI_getNumPDPChannels
   (JNIEnv* env, jclass)
 {
-  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumPDPChannels";
   jint value = HAL_GetNumPDPChannels();
-  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
   return value;
 }
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/RelayJNI.cpp b/hal/src/main/native/cpp/jni/RelayJNI.cpp
index 0cc70fb..c058435 100644
--- a/hal/src/main/native/cpp/jni/RelayJNI.cpp
+++ b/hal/src/main/native/cpp/jni/RelayJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,20 +13,10 @@
 #include "edu_wpi_first_hal_RelayJNI.h"
 #include "hal/Ports.h"
 #include "hal/Relay.h"
-#include "hal/cpp/Log.h"
 #include "hal/handles/HandlesInternal.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel relayJNILogLevel = logWARNING;
-
-#define RELAYJNI_LOG(level)     \
-  if (level > relayJNILogLevel) \
-    ;                           \
-  else                          \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -38,14 +28,9 @@
 Java_edu_wpi_first_hal_RelayJNI_initializeRelayPort
   (JNIEnv* env, jclass, jint id, jboolean fwd)
 {
-  RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI initializeRelayPort";
-  RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_PortHandle)id;
-  RELAYJNI_LOG(logDEBUG) << "Forward = " << (jint)fwd;
   int32_t status = 0;
   HAL_RelayHandle handle = HAL_InitializeRelayPort(
       (HAL_PortHandle)id, static_cast<uint8_t>(fwd), &status);
-  RELAYJNI_LOG(logDEBUG) << "Status = " << status;
-  RELAYJNI_LOG(logDEBUG) << "Relay Handle = " << handle;
   CheckStatusRange(env, status, 0, HAL_GetNumRelayChannels(),
                    hal::getPortHandleChannel((HAL_PortHandle)id));
   return (jint)handle;
@@ -60,8 +45,6 @@
 Java_edu_wpi_first_hal_RelayJNI_freeRelayPort
   (JNIEnv* env, jclass, jint id)
 {
-  RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI freeRelayPort";
-  RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_RelayHandle)id;
   HAL_FreeRelayPort((HAL_RelayHandle)id);
 }
 
@@ -74,8 +57,6 @@
 Java_edu_wpi_first_hal_RelayJNI_checkRelayChannel
   (JNIEnv* env, jclass, jint channel)
 {
-  RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI checkRelayChannel";
-  RELAYJNI_LOG(logDEBUG) << "Channel = " << channel;
   return (jboolean)HAL_CheckRelayChannel(static_cast<uint8_t>(channel));
 }
 
@@ -88,12 +69,8 @@
 Java_edu_wpi_first_hal_RelayJNI_setRelay
   (JNIEnv* env, jclass, jint id, jboolean value)
 {
-  RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI setRelay";
-  RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_RelayHandle)id;
-  RELAYJNI_LOG(logDEBUG) << "Flag = " << (jint)value;
   int32_t status = 0;
   HAL_SetRelay((HAL_RelayHandle)id, value, &status);
-  RELAYJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -106,12 +83,8 @@
 Java_edu_wpi_first_hal_RelayJNI_getRelay
   (JNIEnv* env, jclass, jint id)
 {
-  RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI getRelay";
-  RELAYJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_RelayHandle)id;
   int32_t status = 0;
   jboolean returnValue = HAL_GetRelay((HAL_RelayHandle)id, &status);
-  RELAYJNI_LOG(logDEBUG) << "Status = " << status;
-  RELAYJNI_LOG(logDEBUG) << "getRelayResult = " << (jint)returnValue;
   CheckStatus(env, status);
   return returnValue;
 }
diff --git a/hal/src/main/native/cpp/jni/SPIJNI.cpp b/hal/src/main/native/cpp/jni/SPIJNI.cpp
index d594058..27078fd 100644
--- a/hal/src/main/native/cpp/jni/SPIJNI.cpp
+++ b/hal/src/main/native/cpp/jni/SPIJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -14,20 +14,10 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_SPIJNI.h"
 #include "hal/SPI.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 using namespace wpi::java;
 
-// set the logging level
-TLogLevel spiJNILogLevel = logWARNING;
-
-#define SPIJNI_LOG(level)     \
-  if (level > spiJNILogLevel) \
-    ;                         \
-  else                        \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -39,11 +29,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiInitialize
   (JNIEnv* env, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiInitialize";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   int32_t status = 0;
   HAL_InitializeSPI(static_cast<HAL_SPIPort>(port), &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatusForceThrow(env, status);
 }
 
@@ -57,8 +44,6 @@
   (JNIEnv* env, jclass, jint port, jobject dataToSend, jobject dataReceived,
    jbyte size)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiTransaction";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   uint8_t* dataToSendPtr = nullptr;
   if (dataToSend != 0) {
     dataToSendPtr =
@@ -66,12 +51,8 @@
   }
   uint8_t* dataReceivedPtr =
       reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataReceived));
-  SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size;
-  SPIJNI_LOG(logDEBUG) << "DataToSendPtr = " << dataToSendPtr;
-  SPIJNI_LOG(logDEBUG) << "DataReceivedPtr = " << dataReceivedPtr;
   jint retVal = HAL_TransactionSPI(static_cast<HAL_SPIPort>(port),
                                    dataToSendPtr, dataReceivedPtr, size);
-  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
   return retVal;
 }
 
@@ -85,9 +66,6 @@
   (JNIEnv* env, jclass, jint port, jbyteArray dataToSend,
    jbyteArray dataReceived, jbyte size)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiTransactionB";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
-  SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size;
   wpi::SmallVector<uint8_t, 128> recvBuf;
   recvBuf.resize(size);
   jint retVal =
@@ -97,7 +75,6 @@
                          recvBuf.data(), size);
   env->SetByteArrayRegion(dataReceived, 0, size,
                           reinterpret_cast<const jbyte*>(recvBuf.data()));
-  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
   return retVal;
 }
 
@@ -110,18 +87,13 @@
 Java_edu_wpi_first_hal_SPIJNI_spiWrite
   (JNIEnv* env, jclass, jint port, jobject dataToSend, jbyte size)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiWrite";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   uint8_t* dataToSendPtr = nullptr;
   if (dataToSend != 0) {
     dataToSendPtr =
         reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
   }
-  SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size;
-  SPIJNI_LOG(logDEBUG) << "DataToSendPtr = " << dataToSendPtr;
   jint retVal =
       HAL_WriteSPI(static_cast<HAL_SPIPort>(port), dataToSendPtr, size);
-  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
   return retVal;
 }
 
@@ -134,14 +106,10 @@
 Java_edu_wpi_first_hal_SPIJNI_spiWriteB
   (JNIEnv* env, jclass, jint port, jbyteArray dataToSend, jbyte size)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiWriteB";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
-  SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size;
   jint retVal = HAL_WriteSPI(static_cast<HAL_SPIPort>(port),
                              reinterpret_cast<const uint8_t*>(
                                  JByteArrayRef(env, dataToSend).array().data()),
                              size);
-  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
   return retVal;
 }
 
@@ -155,13 +123,8 @@
   (JNIEnv* env, jclass, jint port, jboolean initiate, jobject dataReceived,
    jbyte size)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiRead";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
-  SPIJNI_LOG(logDEBUG) << "Initiate = " << (jboolean)initiate;
   uint8_t* dataReceivedPtr =
       reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataReceived));
-  SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size;
-  SPIJNI_LOG(logDEBUG) << "DataReceivedPtr = " << dataReceivedPtr;
   jint retVal;
   if (initiate) {
     wpi::SmallVector<uint8_t, 128> sendBuf;
@@ -172,7 +135,6 @@
     retVal = HAL_ReadSPI(static_cast<HAL_SPIPort>(port),
                          reinterpret_cast<uint8_t*>(dataReceivedPtr), size);
   }
-  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
   return retVal;
 }
 
@@ -186,10 +148,6 @@
   (JNIEnv* env, jclass, jint port, jboolean initiate, jbyteArray dataReceived,
    jbyte size)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiReadB";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
-  SPIJNI_LOG(logDEBUG) << "Initiate = " << (jboolean)initiate;
-  SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size;
   jint retVal;
   wpi::SmallVector<uint8_t, 128> recvBuf;
   recvBuf.resize(size);
@@ -203,7 +161,6 @@
   }
   env->SetByteArrayRegion(dataReceived, 0, size,
                           reinterpret_cast<const jbyte*>(recvBuf.data()));
-  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
   return retVal;
 }
 
@@ -216,8 +173,6 @@
 Java_edu_wpi_first_hal_SPIJNI_spiClose
   (JNIEnv*, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiClose";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   HAL_CloseSPI(static_cast<HAL_SPIPort>(port));
 }
 
@@ -230,9 +185,6 @@
 Java_edu_wpi_first_hal_SPIJNI_spiSetSpeed
   (JNIEnv*, jclass, jint port, jint speed)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiSetSpeed";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
-  SPIJNI_LOG(logDEBUG) << "Speed = " << (jint)speed;
   HAL_SetSPISpeed(static_cast<HAL_SPIPort>(port), speed);
 }
 
@@ -246,11 +198,6 @@
   (JNIEnv*, jclass, jint port, jint msb_first, jint sample_on_trailing,
    jint clk_idle_high)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiSetOpts";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
-  SPIJNI_LOG(logDEBUG) << "msb_first = " << msb_first;
-  SPIJNI_LOG(logDEBUG) << "sample_on_trailing = " << sample_on_trailing;
-  SPIJNI_LOG(logDEBUG) << "clk_idle_high = " << clk_idle_high;
   HAL_SetSPIOpts(static_cast<HAL_SPIPort>(port), msb_first, sample_on_trailing,
                  clk_idle_high);
 }
@@ -264,11 +211,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiSetChipSelectActiveHigh
   (JNIEnv* env, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiSetCSActiveHigh";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   int32_t status = 0;
   HAL_SetSPIChipSelectActiveHigh(static_cast<HAL_SPIPort>(port), &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -281,11 +225,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiSetChipSelectActiveLow
   (JNIEnv* env, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiSetCSActiveLow";
-  SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   int32_t status = 0;
   HAL_SetSPIChipSelectActiveLow(static_cast<HAL_SPIPort>(port), &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -298,12 +239,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiInitAuto
   (JNIEnv* env, jclass, jint port, jint bufferSize)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiInitAuto";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
-  SPIJNI_LOG(logDEBUG) << "BufferSize = " << bufferSize;
   int32_t status = 0;
   HAL_InitSPIAuto(static_cast<HAL_SPIPort>(port), bufferSize, &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -316,11 +253,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiFreeAuto
   (JNIEnv* env, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiFreeAuto";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
   int32_t status = 0;
   HAL_FreeSPIAuto(static_cast<HAL_SPIPort>(port), &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -333,12 +267,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiStartAutoRate
   (JNIEnv* env, jclass, jint port, jdouble period)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiStartAutoRate";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
-  SPIJNI_LOG(logDEBUG) << "Period = " << period;
   int32_t status = 0;
   HAL_StartSPIAutoRate(static_cast<HAL_SPIPort>(port), period, &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -352,17 +282,10 @@
   (JNIEnv* env, jclass, jint port, jint digitalSourceHandle,
    jint analogTriggerType, jboolean triggerRising, jboolean triggerFalling)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiStartAutoTrigger";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
-  SPIJNI_LOG(logDEBUG) << "DigitalSourceHandle = " << digitalSourceHandle;
-  SPIJNI_LOG(logDEBUG) << "AnalogTriggerType = " << analogTriggerType;
-  SPIJNI_LOG(logDEBUG) << "TriggerRising = " << (jint)triggerRising;
-  SPIJNI_LOG(logDEBUG) << "TriggerFalling = " << (jint)triggerFalling;
   int32_t status = 0;
   HAL_StartSPIAutoTrigger(static_cast<HAL_SPIPort>(port), digitalSourceHandle,
                           static_cast<HAL_AnalogTriggerType>(analogTriggerType),
                           triggerRising, triggerFalling, &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -375,11 +298,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiStopAuto
   (JNIEnv* env, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiStopAuto";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
   int32_t status = 0;
   HAL_StopSPIAuto(static_cast<HAL_SPIPort>(port), &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -392,16 +312,12 @@
 Java_edu_wpi_first_hal_SPIJNI_spiSetAutoTransmitData
   (JNIEnv* env, jclass, jint port, jbyteArray dataToSend, jint zeroSize)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiSetAutoTransmitData";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
-  SPIJNI_LOG(logDEBUG) << "ZeroSize = " << zeroSize;
   JByteArrayRef jarr(env, dataToSend);
   int32_t status = 0;
   HAL_SetSPIAutoTransmitData(
       static_cast<HAL_SPIPort>(port),
       reinterpret_cast<const uint8_t*>(jarr.array().data()),
       jarr.array().size(), zeroSize, &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -414,11 +330,8 @@
 Java_edu_wpi_first_hal_SPIJNI_spiForceAutoRead
   (JNIEnv* env, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiForceAutoRead";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
   int32_t status = 0;
   HAL_ForceSPIAutoRead(static_cast<HAL_SPIPort>(port), &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
@@ -432,17 +345,11 @@
   (JNIEnv* env, jclass, jint port, jobject buffer, jint numToRead,
    jdouble timeout)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiReadAutoReceivedData";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
-  SPIJNI_LOG(logDEBUG) << "NumToRead = " << numToRead;
-  SPIJNI_LOG(logDEBUG) << "Timeout = " << timeout;
   uint32_t* recvBuf =
       reinterpret_cast<uint32_t*>(env->GetDirectBufferAddress(buffer));
   int32_t status = 0;
   jint retval = HAL_ReadSPIAutoReceivedData(
       static_cast<HAL_SPIPort>(port), recvBuf, numToRead, timeout, &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
-  SPIJNI_LOG(logDEBUG) << "Return = " << retval;
   CheckStatus(env, status);
   return retval;
 }
@@ -457,18 +364,12 @@
   (JNIEnv* env, jclass, jint port, jintArray buffer, jint numToRead,
    jdouble timeout)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiReadAutoReceivedData";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
-  SPIJNI_LOG(logDEBUG) << "NumToRead = " << numToRead;
-  SPIJNI_LOG(logDEBUG) << "Timeout = " << timeout;
   wpi::SmallVector<uint32_t, 128> recvBuf;
   recvBuf.resize(numToRead);
   int32_t status = 0;
   jint retval =
       HAL_ReadSPIAutoReceivedData(static_cast<HAL_SPIPort>(port),
                                   recvBuf.data(), numToRead, timeout, &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
-  SPIJNI_LOG(logDEBUG) << "Return = " << retval;
   if (!CheckStatus(env, status)) return retval;
   if (numToRead > 0) {
     env->SetIntArrayRegion(buffer, 0, numToRead,
@@ -486,13 +387,9 @@
 Java_edu_wpi_first_hal_SPIJNI_spiGetAutoDroppedCount
   (JNIEnv* env, jclass, jint port)
 {
-  SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiGetAutoDroppedCount";
-  SPIJNI_LOG(logDEBUG) << "Port = " << port;
   int32_t status = 0;
   auto retval =
       HAL_GetSPIAutoDroppedCount(static_cast<HAL_SPIPort>(port), &status);
-  SPIJNI_LOG(logDEBUG) << "Status = " << status;
-  SPIJNI_LOG(logDEBUG) << "Return = " << retval;
   CheckStatus(env, status);
   return retval;
 }
diff --git a/hal/src/main/native/cpp/jni/SerialPortJNI.cpp b/hal/src/main/native/cpp/jni/SerialPortJNI.cpp
index 4524fe6..9fe9d92 100644
--- a/hal/src/main/native/cpp/jni/SerialPortJNI.cpp
+++ b/hal/src/main/native/cpp/jni/SerialPortJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -14,261 +14,222 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_SerialPortJNI.h"
 #include "hal/SerialPort.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 using namespace wpi::java;
 
-// set the logging level
-TLogLevel serialJNILogLevel = logWARNING;
-
-#define SERIALJNI_LOG(level)     \
-  if (level > serialJNILogLevel) \
-    ;                            \
-  else                           \
-    Log().Get(level)
-
 extern "C" {
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialInitializePort
- * Signature: (B)V
+ * Signature: (B)I
  */
-JNIEXPORT void JNICALL
+JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialInitializePort
   (JNIEnv* env, jclass, jbyte port)
 {
-  SERIALJNI_LOG(logDEBUG) << "Calling Serial Initialize";
-  SERIALJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   int32_t status = 0;
-  HAL_InitializeSerialPort(static_cast<HAL_SerialPort>(port), &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  auto handle =
+      HAL_InitializeSerialPort(static_cast<HAL_SerialPort>(port), &status);
   CheckStatusForceThrow(env, status);
+  return static_cast<jint>(handle);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialInitializePortDirect
- * Signature: (BLjava/lang/String;)V
+ * Signature: (BLjava/lang/String;)I
  */
-JNIEXPORT void JNICALL
+JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialInitializePortDirect
   (JNIEnv* env, jclass, jbyte port, jstring portName)
 {
-  SERIALJNI_LOG(logDEBUG) << "Calling Serial Initialize Direct";
-  SERIALJNI_LOG(logDEBUG) << "Port = " << (jint)port;
   JStringRef portNameRef{env, portName};
-  SERIALJNI_LOG(logDEBUG) << "PortName = " << portNameRef.c_str();
   int32_t status = 0;
-  HAL_InitializeSerialPortDirect(static_cast<HAL_SerialPort>(port),
-                                 portNameRef.c_str(), &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  auto handle = HAL_InitializeSerialPortDirect(
+      static_cast<HAL_SerialPort>(port), portNameRef.c_str(), &status);
   CheckStatusForceThrow(env, status);
+  return static_cast<jint>(handle);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetBaudRate
- * Signature: (BI)V
+ * Signature: (II)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetBaudRate
-  (JNIEnv* env, jclass, jbyte port, jint rate)
+  (JNIEnv* env, jclass, jint handle, jint rate)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Baud Rate";
-  SERIALJNI_LOG(logDEBUG) << "Baud: " << rate;
   int32_t status = 0;
-  HAL_SetSerialBaudRate(static_cast<HAL_SerialPort>(port), rate, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialBaudRate(static_cast<HAL_SerialPortHandle>(handle), rate,
+                        &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetDataBits
- * Signature: (BB)V
+ * Signature: (IB)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetDataBits
-  (JNIEnv* env, jclass, jbyte port, jbyte bits)
+  (JNIEnv* env, jclass, jint handle, jbyte bits)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Data Bits";
-  SERIALJNI_LOG(logDEBUG) << "Data Bits: " << bits;
   int32_t status = 0;
-  HAL_SetSerialDataBits(static_cast<HAL_SerialPort>(port), bits, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialDataBits(static_cast<HAL_SerialPortHandle>(handle), bits,
+                        &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetParity
- * Signature: (BB)V
+ * Signature: (IB)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetParity
-  (JNIEnv* env, jclass, jbyte port, jbyte parity)
+  (JNIEnv* env, jclass, jint handle, jbyte parity)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Parity";
-  SERIALJNI_LOG(logDEBUG) << "Parity: " << parity;
   int32_t status = 0;
-  HAL_SetSerialParity(static_cast<HAL_SerialPort>(port), parity, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialParity(static_cast<HAL_SerialPortHandle>(handle), parity,
+                      &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetStopBits
- * Signature: (BB)V
+ * Signature: (IB)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetStopBits
-  (JNIEnv* env, jclass, jbyte port, jbyte bits)
+  (JNIEnv* env, jclass, jint handle, jbyte bits)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Stop Bits";
-  SERIALJNI_LOG(logDEBUG) << "Stop Bits: " << bits;
   int32_t status = 0;
-  HAL_SetSerialStopBits(static_cast<HAL_SerialPort>(port), bits, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialStopBits(static_cast<HAL_SerialPortHandle>(handle), bits,
+                        &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetWriteMode
- * Signature: (BB)V
+ * Signature: (IB)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetWriteMode
-  (JNIEnv* env, jclass, jbyte port, jbyte mode)
+  (JNIEnv* env, jclass, jint handle, jbyte mode)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Write Mode";
-  SERIALJNI_LOG(logDEBUG) << "Write mode: " << mode;
   int32_t status = 0;
-  HAL_SetSerialWriteMode(static_cast<HAL_SerialPort>(port), mode, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialWriteMode(static_cast<HAL_SerialPortHandle>(handle), mode,
+                         &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetFlowControl
- * Signature: (BB)V
+ * Signature: (IB)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetFlowControl
-  (JNIEnv* env, jclass, jbyte port, jbyte flow)
+  (JNIEnv* env, jclass, jint handle, jbyte flow)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Flow Control";
-  SERIALJNI_LOG(logDEBUG) << "Flow Control: " << flow;
   int32_t status = 0;
-  HAL_SetSerialFlowControl(static_cast<HAL_SerialPort>(port), flow, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialFlowControl(static_cast<HAL_SerialPortHandle>(handle), flow,
+                           &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetTimeout
- * Signature: (BD)V
+ * Signature: (ID)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetTimeout
-  (JNIEnv* env, jclass, jbyte port, jdouble timeout)
+  (JNIEnv* env, jclass, jint handle, jdouble timeout)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Timeout";
-  SERIALJNI_LOG(logDEBUG) << "Timeout: " << timeout;
   int32_t status = 0;
-  HAL_SetSerialTimeout(static_cast<HAL_SerialPort>(port), timeout, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialTimeout(static_cast<HAL_SerialPortHandle>(handle), timeout,
+                       &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialEnableTermination
- * Signature: (BC)V
+ * Signature: (IC)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialEnableTermination
-  (JNIEnv* env, jclass, jbyte port, jchar terminator)
+  (JNIEnv* env, jclass, jint handle, jchar terminator)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Enable Termination";
-  SERIALJNI_LOG(logDEBUG) << "Terminator: " << terminator;
   int32_t status = 0;
-  HAL_EnableSerialTermination(static_cast<HAL_SerialPort>(port), terminator,
-                              &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_EnableSerialTermination(static_cast<HAL_SerialPortHandle>(handle),
+                              terminator, &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialDisableTermination
- * Signature: (B)V
+ * Signature: (I)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialDisableTermination
-  (JNIEnv* env, jclass, jbyte port)
+  (JNIEnv* env, jclass, jint handle)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Disable termination";
   int32_t status = 0;
-  HAL_DisableSerialTermination(static_cast<HAL_SerialPort>(port), &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_DisableSerialTermination(static_cast<HAL_SerialPortHandle>(handle),
+                               &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetReadBufferSize
- * Signature: (BI)V
+ * Signature: (II)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetReadBufferSize
-  (JNIEnv* env, jclass, jbyte port, jint size)
+  (JNIEnv* env, jclass, jint handle, jint size)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Read Buffer Size";
-  SERIALJNI_LOG(logDEBUG) << "Size: " << size;
   int32_t status = 0;
-  HAL_SetSerialReadBufferSize(static_cast<HAL_SerialPort>(port), size, &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_SetSerialReadBufferSize(static_cast<HAL_SerialPortHandle>(handle), size,
+                              &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialSetWriteBufferSize
- * Signature: (BI)V
+ * Signature: (II)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialSetWriteBufferSize
-  (JNIEnv* env, jclass, jbyte port, jint size)
+  (JNIEnv* env, jclass, jint handle, jint size)
 {
-  SERIALJNI_LOG(logDEBUG) << "Setting Serial Write Buffer Size";
-  SERIALJNI_LOG(logDEBUG) << "Size: " << size;
   int32_t status = 0;
-  HAL_SetSerialWriteBufferSize(static_cast<HAL_SerialPort>(port), size,
+  HAL_SetSerialWriteBufferSize(static_cast<HAL_SerialPortHandle>(handle), size,
                                &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialGetBytesReceived
- * Signature: (B)I
+ * Signature: (I)I
  */
 JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialGetBytesReceived
-  (JNIEnv* env, jclass, jbyte port)
+  (JNIEnv* env, jclass, jint handle)
 {
-  SERIALJNI_LOG(logDEBUG) << "Serial Get Bytes Received";
   int32_t status = 0;
-  jint retVal =
-      HAL_GetSerialBytesReceived(static_cast<HAL_SerialPort>(port), &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  jint retVal = HAL_GetSerialBytesReceived(
+      static_cast<HAL_SerialPortHandle>(handle), &status);
   CheckStatus(env, status);
   return retVal;
 }
@@ -276,22 +237,19 @@
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialRead
- * Signature: (B[BI)I
+ * Signature: (I[BI)I
  */
 JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialRead
-  (JNIEnv* env, jclass, jbyte port, jbyteArray dataReceived, jint size)
+  (JNIEnv* env, jclass, jint handle, jbyteArray dataReceived, jint size)
 {
-  SERIALJNI_LOG(logDEBUG) << "Serial Read";
   wpi::SmallVector<char, 128> recvBuf;
   recvBuf.resize(size);
   int32_t status = 0;
-  jint retVal = HAL_ReadSerial(static_cast<HAL_SerialPort>(port),
+  jint retVal = HAL_ReadSerial(static_cast<HAL_SerialPortHandle>(handle),
                                recvBuf.data(), size, &status);
   env->SetByteArrayRegion(dataReceived, 0, size,
                           reinterpret_cast<const jbyte*>(recvBuf.data()));
-  SERIALJNI_LOG(logDEBUG) << "ReturnValue = " << retVal;
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
   return retVal;
 }
@@ -299,21 +257,18 @@
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialWrite
- * Signature: (B[BI)I
+ * Signature: (I[BI)I
  */
 JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialWrite
-  (JNIEnv* env, jclass, jbyte port, jbyteArray dataToSend, jint size)
+  (JNIEnv* env, jclass, jint handle, jbyteArray dataToSend, jint size)
 {
-  SERIALJNI_LOG(logDEBUG) << "Serial Write";
   int32_t status = 0;
   jint retVal =
-      HAL_WriteSerial(static_cast<HAL_SerialPort>(port),
+      HAL_WriteSerial(static_cast<HAL_SerialPortHandle>(handle),
                       reinterpret_cast<const char*>(
                           JByteArrayRef(env, dataToSend).array().data()),
                       size, &status);
-  SERIALJNI_LOG(logDEBUG) << "ReturnValue = " << retVal;
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
   CheckStatus(env, status);
   return retVal;
 }
@@ -321,48 +276,42 @@
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialFlush
- * Signature: (B)V
+ * Signature: (I)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialFlush
-  (JNIEnv* env, jclass, jbyte port)
+  (JNIEnv* env, jclass, jint handle)
 {
-  SERIALJNI_LOG(logDEBUG) << "Serial Flush";
   int32_t status = 0;
-  HAL_FlushSerial(static_cast<HAL_SerialPort>(port), &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_FlushSerial(static_cast<HAL_SerialPortHandle>(handle), &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialClear
- * Signature: (B)V
+ * Signature: (I)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialClear
-  (JNIEnv* env, jclass, jbyte port)
+  (JNIEnv* env, jclass, jint handle)
 {
-  SERIALJNI_LOG(logDEBUG) << "Serial Clear";
   int32_t status = 0;
-  HAL_ClearSerial(static_cast<HAL_SerialPort>(port), &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_ClearSerial(static_cast<HAL_SerialPortHandle>(handle), &status);
   CheckStatus(env, status);
 }
 
 /*
  * Class:     edu_wpi_first_hal_SerialPortJNI
  * Method:    serialClose
- * Signature: (B)V
+ * Signature: (I)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_SerialPortJNI_serialClose
-  (JNIEnv* env, jclass, jbyte port)
+  (JNIEnv* env, jclass, jint handle)
 {
-  SERIALJNI_LOG(logDEBUG) << "Serial Close";
   int32_t status = 0;
-  HAL_CloseSerial(static_cast<HAL_SerialPort>(port), &status);
-  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  HAL_CloseSerial(static_cast<HAL_SerialPortHandle>(handle), &status);
   CheckStatus(env, status);
 }
 
diff --git a/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp b/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp
new file mode 100644
index 0000000..d9652cc
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp
@@ -0,0 +1,168 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_SimDeviceJNI.h"
+#include "hal/SimDevice.h"
+
+using namespace wpi::java;
+
+static HAL_Value ValueFromJava(jint type, jlong value1, jdouble value2) {
+  HAL_Value value;
+  value.type = static_cast<HAL_Type>(type);
+  switch (value.type) {
+    case HAL_BOOLEAN:
+      value.data.v_boolean = value1;
+      break;
+    case HAL_DOUBLE:
+      value.data.v_double = value2;
+      break;
+    case HAL_ENUM:
+      value.data.v_enum = value1;
+      break;
+    case HAL_INT:
+      value.data.v_int = value1;
+      break;
+    case HAL_LONG:
+      value.data.v_long = value1;
+      break;
+    default:
+      break;
+  }
+  return value;
+}
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    createSimDevice
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_createSimDevice
+  (JNIEnv* env, jclass, jstring name)
+{
+  return HAL_CreateSimDevice(JStringRef{env, name}.c_str());
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    freeSimDevice
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_freeSimDevice
+  (JNIEnv*, jclass, jint handle)
+{
+  HAL_FreeSimDevice(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    createSimValueNative
+ * Signature: (ILjava/lang/String;ZIJD)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueNative
+  (JNIEnv* env, jclass, jint device, jstring name, jboolean readonly, jint type,
+   jlong value1, jdouble value2)
+{
+  return HAL_CreateSimValue(device, JStringRef{env, name}.c_str(), readonly,
+                            ValueFromJava(type, value1, value2));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    createSimValueEnum
+ * Signature: (ILjava/lang/String;Z[Ljava/lang/Object;I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnum
+  (JNIEnv* env, jclass, jint device, jstring name, jboolean readonly,
+   jobjectArray options, jint initialValue)
+{
+  size_t len = env->GetArrayLength(options);
+  std::vector<std::string> arr;
+  arr.reserve(len);
+  for (size_t i = 0; i < len; ++i) {
+    JLocal<jstring> elem{
+        env, static_cast<jstring>(env->GetObjectArrayElement(options, i))};
+    if (!elem) return 0;
+    arr.push_back(JStringRef{env, elem}.str());
+  }
+  wpi::SmallVector<const char*, 8> carr;
+  for (auto&& val : arr) carr.push_back(val.c_str());
+  return HAL_CreateSimValueEnum(device, JStringRef{env, name}.c_str(), readonly,
+                                len, carr.data(), initialValue);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    getSimValue
+ * Signature: (I)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_getSimValue
+  (JNIEnv* env, jclass, jint handle)
+{
+  return frc::CreateHALValue(env, HAL_GetSimValue(handle));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    getSimValueDouble
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueDouble
+  (JNIEnv*, jclass, jint handle)
+{
+  return HAL_GetSimValueDouble(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    getSimValueEnum
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueEnum
+  (JNIEnv*, jclass, jint handle)
+{
+  return HAL_GetSimValueEnum(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    getSimValueBoolean
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueBoolean
+  (JNIEnv*, jclass, jint handle)
+{
+  return HAL_GetSimValueBoolean(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    setSimValueNative
+ * Signature: (IIJD)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_setSimValueNative
+  (JNIEnv*, jclass, jint handle, jint type, jlong value1, jdouble value2)
+{
+  HAL_SetSimValue(handle, ValueFromJava(type, value1, value2));
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/SolenoidJNI.cpp b/hal/src/main/native/cpp/jni/SolenoidJNI.cpp
index 524b70e..4e6f139 100644
--- a/hal/src/main/native/cpp/jni/SolenoidJNI.cpp
+++ b/hal/src/main/native/cpp/jni/SolenoidJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -11,19 +11,10 @@
 #include "edu_wpi_first_hal_SolenoidJNI.h"
 #include "hal/Ports.h"
 #include "hal/Solenoid.h"
-#include "hal/cpp/Log.h"
 #include "hal/handles/HandlesInternal.h"
 
 using namespace frc;
 
-TLogLevel solenoidJNILogLevel = logERROR;
-
-#define SOLENOIDJNI_LOG(level)     \
-  if (level > solenoidJNILogLevel) \
-    ;                              \
-  else                             \
-    Log().Get(level)
-
 extern "C" {
 
 /*
@@ -35,17 +26,10 @@
 Java_edu_wpi_first_hal_SolenoidJNI_initializeSolenoidPort
   (JNIEnv* env, jclass, jint id)
 {
-  SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI initializeSolenoidPort";
-
-  SOLENOIDJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_PortHandle)id;
-
   int32_t status = 0;
   HAL_SolenoidHandle handle =
       HAL_InitializeSolenoidPort((HAL_PortHandle)id, &status);
 
-  SOLENOIDJNI_LOG(logDEBUG) << "Status = " << status;
-  SOLENOIDJNI_LOG(logDEBUG) << "Solenoid Port Handle = " << handle;
-
   // Use solenoid channels, as we have to pick one.
   CheckStatusRange(env, status, 0, HAL_GetNumSolenoidChannels(),
                    hal::getPortHandleChannel((HAL_PortHandle)id));
@@ -61,8 +45,6 @@
 Java_edu_wpi_first_hal_SolenoidJNI_checkSolenoidChannel
   (JNIEnv* env, jclass, jint channel)
 {
-  SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI checkSolenoidChannel";
-  SOLENOIDJNI_LOG(logDEBUG) << "Channel = " << channel;
   return HAL_CheckSolenoidChannel(channel);
 }
 
@@ -75,8 +57,6 @@
 Java_edu_wpi_first_hal_SolenoidJNI_checkSolenoidModule
   (JNIEnv* env, jclass, jint module)
 {
-  SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI checkSolenoidModule";
-  SOLENOIDJNI_LOG(logDEBUG) << "Module = " << module;
   return HAL_CheckSolenoidModule(module);
 }
 
@@ -89,9 +69,6 @@
 Java_edu_wpi_first_hal_SolenoidJNI_freeSolenoidPort
   (JNIEnv* env, jclass, jint id)
 {
-  SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI initializeSolenoidPort";
-
-  SOLENOIDJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_SolenoidHandle)id;
   HAL_FreeSolenoidPort((HAL_SolenoidHandle)id);
 }
 
@@ -104,11 +81,6 @@
 Java_edu_wpi_first_hal_SolenoidJNI_setSolenoid
   (JNIEnv* env, jclass, jint solenoid_port, jboolean value)
 {
-  SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI SetSolenoid";
-
-  SOLENOIDJNI_LOG(logDEBUG)
-      << "Solenoid Port Handle = " << (HAL_SolenoidHandle)solenoid_port;
-
   int32_t status = 0;
   HAL_SetSolenoid((HAL_SolenoidHandle)solenoid_port, value, &status);
   CheckStatus(env, status);
@@ -209,12 +181,6 @@
 Java_edu_wpi_first_hal_SolenoidJNI_setOneShotDuration
   (JNIEnv* env, jclass, jint solenoid_port, jlong durationMS)
 {
-  SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI SetOneShotDuration";
-
-  SOLENOIDJNI_LOG(logDEBUG)
-      << "Solenoid Port Handle = " << (HAL_SolenoidHandle)solenoid_port;
-  SOLENOIDJNI_LOG(logDEBUG) << "Duration (MS) = " << durationMS;
-
   int32_t status = 0;
   HAL_SetOneShotDuration((HAL_SolenoidHandle)solenoid_port, durationMS,
                          &status);
@@ -230,11 +196,6 @@
 Java_edu_wpi_first_hal_SolenoidJNI_fireOneShot
   (JNIEnv* env, jclass, jint solenoid_port)
 {
-  SOLENOIDJNI_LOG(logDEBUG) << "Calling SolenoidJNI fireOneShot";
-
-  SOLENOIDJNI_LOG(logDEBUG)
-      << "Solenoid Port Handle = " << (HAL_SolenoidHandle)solenoid_port;
-
   int32_t status = 0;
   HAL_FireOneShot((HAL_SolenoidHandle)solenoid_port, &status);
   CheckStatus(env, status);
diff --git a/hal/src/main/native/cpp/jni/ThreadsJNI.cpp b/hal/src/main/native/cpp/jni/ThreadsJNI.cpp
index ea3cac6..d4620e2 100644
--- a/hal/src/main/native/cpp/jni/ThreadsJNI.cpp
+++ b/hal/src/main/native/cpp/jni/ThreadsJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -12,19 +12,9 @@
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_ThreadsJNI.h"
 #include "hal/Threads.h"
-#include "hal/cpp/Log.h"
 
 using namespace frc;
 
-// set the logging level
-TLogLevel threadsJNILogLevel = logWARNING;
-
-#define THREADSJNI_LOG(level)     \
-  if (level > threadsJNILogLevel) \
-    ;                             \
-  else                            \
-    Log().Get(level)
-
 extern "C" {
 /*
  * Class:     edu_wpi_first_hal_ThreadsJNI
@@ -35,7 +25,6 @@
 Java_edu_wpi_first_hal_ThreadsJNI_getCurrentThreadPriority
   (JNIEnv* env, jclass)
 {
-  THREADSJNI_LOG(logDEBUG) << "Callling GetCurrentThreadPriority";
   int32_t status = 0;
   HAL_Bool isRT = false;
   auto ret = HAL_GetCurrentThreadPriority(&isRT, &status);
@@ -52,7 +41,6 @@
 Java_edu_wpi_first_hal_ThreadsJNI_getCurrentThreadIsRealTime
   (JNIEnv* env, jclass)
 {
-  THREADSJNI_LOG(logDEBUG) << "Callling GetCurrentThreadIsRealTime";
   int32_t status = 0;
   HAL_Bool isRT = false;
   HAL_GetCurrentThreadPriority(&isRT, &status);
@@ -69,7 +57,6 @@
 Java_edu_wpi_first_hal_ThreadsJNI_setCurrentThreadPriority
   (JNIEnv* env, jclass, jboolean realTime, jint priority)
 {
-  THREADSJNI_LOG(logDEBUG) << "Callling SetCurrentThreadPriority";
   int32_t status = 0;
   auto ret = HAL_SetCurrentThreadPriority(
       (HAL_Bool)realTime, static_cast<int32_t>(priority), &status);
diff --git a/hal/src/main/native/include/hal/AnalogInput.h b/hal/src/main/native/include/hal/AnalogInput.h
index 45e6662..c0e45b3 100644
--- a/hal/src/main/native/include/hal/AnalogInput.h
+++ b/hal/src/main/native/include/hal/AnalogInput.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -56,6 +56,15 @@
 HAL_Bool HAL_CheckAnalogInputChannel(int32_t channel);
 
 /**
+ * Indicates the analog input is used by a simulated device.
+ *
+ * @param handle the analog input handle
+ * @param device simulated device handle
+ */
+void HAL_SetAnalogInputSimDevice(HAL_AnalogInputHandle handle,
+                                 HAL_SimDeviceHandle device);
+
+/**
  * Sets the sample rate.
  *
  * This is a global setting for the Athena and effects all channels.
diff --git a/hal/src/main/native/include/hal/CANAPI.h b/hal/src/main/native/include/hal/CANAPI.h
index 48c254d..7a6bd88 100644
--- a/hal/src/main/native/include/hal/CANAPI.h
+++ b/hal/src/main/native/include/hal/CANAPI.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -74,6 +74,20 @@
                                  int32_t repeatMs, int32_t* status);
 
 /**
+ * Writes an RTR frame of the specified length to the CAN device with the
+ * specific ID.
+ *
+ * By spec, the length must be equal to the length sent by the other device,
+ * otherwise behavior is unspecified.
+ *
+ * @param handle   the CAN handle
+ * @param length   the length of data to request (0-8)
+ * @param apiId    the ID to write (0-1023)
+ */
+void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
+                          int32_t* status);
+
+/**
  * Stops a repeating packet with a specific ID.
  *
  * This ID is 10 bits.
@@ -134,28 +148,6 @@
                               uint64_t* receivedTimestamp, int32_t timeoutMs,
                               int32_t* status);
 
-/**
- * Reads a CAN packet. The will return the last packet received until the
- * packet is older then the requested timeout. Then it will return an error
- * code. The period parameter is used when you know the packet is sent at
- * specific intervals, so calls will not attempt to read a new packet from the
- * network until that period has passed. We do not recommend users use this
- * API unless they know the implications.
- *
- * @param handle            the CAN handle
- * @param apiId             the ID to read (0-1023)
- * @param data              the packet data (8 bytes)
- * @param length            the received length (0-8 bytes)
- * @param receivedTimestamp the packet received timestamp (based off of
- * CLOCK_MONOTONIC)
- * @param timeoutMs         the timeout time for the packet
- * @param periodMs          the standard period for the packet
- */
-void HAL_ReadCANPeriodicPacket(HAL_CANHandle handle, int32_t apiId,
-                               uint8_t* data, int32_t* length,
-                               uint64_t* receivedTimestamp, int32_t timeoutMs,
-                               int32_t periodMs, int32_t* status);
-
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/hal/src/main/native/include/hal/CANAPITypes.h b/hal/src/main/native/include/hal/CANAPITypes.h
index 4bf98bd..31a64ab 100644
--- a/hal/src/main/native/include/hal/CANAPITypes.h
+++ b/hal/src/main/native/include/hal/CANAPITypes.h
@@ -1,56 +1,61 @@
-/*----------------------------------------------------------------------------*/

-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */

-/* Open Source Software - may be modified and shared by FRC teams. The code   */

-/* must be accompanied by the FIRST BSD license file in the root directory of */

-/* the project.                                                               */

-/*----------------------------------------------------------------------------*/

-

-#pragma once

-

-#include <stdint.h>

-

-#include "hal/Types.h"

-

-/**

- * @defgroup hal_canapi CAN API Functions

- * @ingroup hal_capi

- * @{

- */

-

-// clang-format off

-/**

- * The CAN device type.

- *

- * Teams should use HAL_CAN_Dev_kMiscellaneous

- */

-HAL_ENUM(HAL_CANDeviceType) {

-  HAL_CAN_Dev_kBroadcast = 0,

-  HAL_CAN_Dev_kRobotController = 1,

-  HAL_CAN_Dev_kMotorController = 2,

-  HAL_CAN_Dev_kRelayController = 3,

-  HAL_CAN_Dev_kGyroSensor = 4,

-  HAL_CAN_Dev_kAccelerometer = 5,

-  HAL_CAN_Dev_kUltrasonicSensor = 6,

-  HAL_CAN_Dev_kGearToothSensor = 7,

-  HAL_CAN_Dev_kPowerDistribution = 8,

-  HAL_CAN_Dev_kPneumatics = 9,

-  HAL_CAN_Dev_kMiscellaneous = 10,

-  HAL_CAN_Dev_kFirmwareUpdate = 31

-};

-

-/**

- * The CAN manufacturer ID.

- *

- * Teams should use HAL_CAN_Man_kTeamUse.

- */

-HAL_ENUM(HAL_CANManufacturer) {

-  HAL_CAN_Man_kBroadcast = 0,

-  HAL_CAN_Man_kNI = 1,

-  HAL_CAN_Man_kLM = 2,

-  HAL_CAN_Man_kDEKA = 3,

-  HAL_CAN_Man_kCTRE = 4,

-  HAL_CAN_Man_kMS = 7,

-  HAL_CAN_Man_kTeamUse = 8,

-};

-// clang-format on

-/** @} */

+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_canapi CAN API Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+/**
+ * The CAN device type.
+ *
+ * Teams should use HAL_CAN_Dev_kMiscellaneous
+ */
+HAL_ENUM(HAL_CANDeviceType) {
+  HAL_CAN_Dev_kBroadcast = 0,
+  HAL_CAN_Dev_kRobotController = 1,
+  HAL_CAN_Dev_kMotorController = 2,
+  HAL_CAN_Dev_kRelayController = 3,
+  HAL_CAN_Dev_kGyroSensor = 4,
+  HAL_CAN_Dev_kAccelerometer = 5,
+  HAL_CAN_Dev_kUltrasonicSensor = 6,
+  HAL_CAN_Dev_kGearToothSensor = 7,
+  HAL_CAN_Dev_kPowerDistribution = 8,
+  HAL_CAN_Dev_kPneumatics = 9,
+  HAL_CAN_Dev_kMiscellaneous = 10,
+  HAL_CAN_Dev_kFirmwareUpdate = 31
+};
+
+/**
+ * The CAN manufacturer ID.
+ *
+ * Teams should use HAL_CAN_Man_kTeamUse.
+ */
+HAL_ENUM(HAL_CANManufacturer) {
+  HAL_CAN_Man_kBroadcast = 0,
+  HAL_CAN_Man_kNI = 1,
+  HAL_CAN_Man_kLM = 2,
+  HAL_CAN_Man_kDEKA = 3,
+  HAL_CAN_Man_kCTRE = 4,
+  HAL_CAN_Man_kREV = 5,
+  HAL_CAN_Man_kGrapple = 6,
+  HAL_CAN_Man_kMS = 7,
+  HAL_CAN_Man_kTeamUse = 8,
+  HAL_CAN_Man_kKauaiLabs = 9,
+  HAL_CAN_Man_kCopperforge = 10,
+  HAL_CAN_Man_kPWF = 11
+};
+// clang-format on
+/** @} */
diff --git a/hal/src/main/native/include/hal/DIO.h b/hal/src/main/native/include/hal/DIO.h
index 7812306..6ffc71f 100644
--- a/hal/src/main/native/include/hal/DIO.h
+++ b/hal/src/main/native/include/hal/DIO.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -42,6 +42,14 @@
 void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle);
 
 /**
+ * Indicates the DIO channel is used by a simulated device.
+ *
+ * @param handle the DIO channel handle
+ * @param device simulated device handle
+ */
+void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device);
+
+/**
  * Allocates a DO PWM Generator.
  *
  * @return the allocated digital PWM handle
diff --git a/hal/src/main/native/include/hal/DriverStation.h b/hal/src/main/native/include/hal/DriverStation.h
index 1c18681..db98698 100644
--- a/hal/src/main/native/include/hal/DriverStation.h
+++ b/hal/src/main/native/include/hal/DriverStation.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2013-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2013-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -187,8 +187,6 @@
  */
 int32_t HAL_GetMatchInfo(HAL_MatchInfo* info);
 
-#ifndef HAL_USE_LABVIEW
-
 /**
  * Releases the DS Mutex to allow proper shutdown of any threads that are
  * waiting on it.
@@ -268,8 +266,6 @@
  */
 void HAL_ObserveUserProgramTest(void);
 
-#endif  // HAL_USE_LABVIEW
-
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/hal/src/main/native/include/hal/Encoder.h b/hal/src/main/native/include/hal/Encoder.h
index 449b814..9d2b5d0 100644
--- a/hal/src/main/native/include/hal/Encoder.h
+++ b/hal/src/main/native/include/hal/Encoder.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -73,6 +73,15 @@
 void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
 
 /**
+ * Indicates the encoder is used by a simulated device.
+ *
+ * @param handle the encoder handle
+ * @param device simulated device handle
+ */
+void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
+                             HAL_SimDeviceHandle device);
+
+/**
  * Gets the current counts of the encoder after encoding type scaling.
  *
  * This is scaled by the value passed duing initialization to encodingType.
diff --git a/hal/src/main/native/include/hal/HAL.h b/hal/src/main/native/include/hal/HAL.h
index f0da13f..2f71d79 100644
--- a/hal/src/main/native/include/hal/HAL.h
+++ b/hal/src/main/native/include/hal/HAL.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2013-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2013-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -9,8 +9,6 @@
 
 #include <stdint.h>
 
-#ifndef HAL_USE_LABVIEW
-
 #include "hal/Accelerometer.h"
 #include "hal/AnalogAccumulator.h"
 #include "hal/AnalogGyro.h"
@@ -18,14 +16,18 @@
 #include "hal/AnalogOutput.h"
 #include "hal/AnalogTrigger.h"
 #include "hal/CAN.h"
+#include "hal/CANAPI.h"
 #include "hal/Compressor.h"
 #include "hal/Constants.h"
 #include "hal/Counter.h"
 #include "hal/DIO.h"
 #include "hal/DriverStation.h"
+#include "hal/Encoder.h"
 #include "hal/Errors.h"
+#include "hal/HALBase.h"
 #include "hal/I2C.h"
 #include "hal/Interrupts.h"
+#include "hal/Main.h"
 #include "hal/Notifier.h"
 #include "hal/PDP.h"
 #include "hal/PWM.h"
@@ -34,12 +36,11 @@
 #include "hal/Relay.h"
 #include "hal/SPI.h"
 #include "hal/SerialPort.h"
+#include "hal/SimDevice.h"
 #include "hal/Solenoid.h"
-
-#endif  // HAL_USE_LABVIEW
-
+#include "hal/Threads.h"
 #include "hal/Types.h"
-#include "hal/HALBase.h"
+#include "hal/Value.h"
 
 #ifdef __cplusplus
 #include "hal/FRCUsageReporting.h"
diff --git a/hal/src/main/native/include/hal/HALBase.h b/hal/src/main/native/include/hal/HALBase.h
index fd22c0c..a958f2b 100644
--- a/hal/src/main/native/include/hal/HALBase.h
+++ b/hal/src/main/native/include/hal/HALBase.h
@@ -1,182 +1,169 @@
-/*----------------------------------------------------------------------------*/

-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */

-/* Open Source Software - may be modified and shared by FRC teams. The code   */

-/* must be accompanied by the FIRST BSD license file in the root directory of */

-/* the project.                                                               */

-/*----------------------------------------------------------------------------*/

-

-#pragma once

-

-#include <stdint.h>

-

-#include "hal/Types.h"

-

-/**

- * @defgroup hal_capi WPILib HAL API

- * Hardware Abstraction Layer to hardware or simulator

- * @{

- */

-

-// clang-format off

-HAL_ENUM(HAL_RuntimeType) { HAL_Athena, HAL_Mock };

-// clang-format on

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-/**

- * Gets the error message for a specific status code.

- *

- * @param code the status code

- * @return     the error message for the code. This does not need to be freed.

- */

-const char* HAL_GetErrorMessage(int32_t code);

-

-/**

- * Returns the FPGA Version number.

- *

- * For now, expect this to be competition year.

- *

- * @return FPGA Version number.

- */

-int32_t HAL_GetFPGAVersion(int32_t* status);

-

-/**

- * Returns the FPGA Revision number.

- *

- * The format of the revision is 3 numbers.

- * The 12 most significant bits are the Major Revision.

- * the next 8 bits are the Minor Revision.

- * The 12 least significant bits are the Build Number.

- *

- * @return FPGA Revision number.

- */

-int64_t HAL_GetFPGARevision(int32_t* status);

-

-HAL_RuntimeType HAL_GetRuntimeType(void);

-

-/**

- * Gets the state of the "USER" button on the roboRIO.

- *

- * @return true if the button is currently pressed down

- */

-HAL_Bool HAL_GetFPGAButton(int32_t* status);

-

-/**

- * Gets if the system outputs are currently active

- *

- * @return true if the system outputs are active, false if disabled

- */

-HAL_Bool HAL_GetSystemActive(int32_t* status);

-

-/**

- * Gets if the system is in a browned out state.

- *

- * @return true if the system is in a low voltage brown out, false otherwise

- */

-HAL_Bool HAL_GetBrownedOut(int32_t* status);

-

-/**

- * The base HAL initialize function. Useful if you need to ensure the DS and

- * base HAL functions (the ones above this declaration in HAL.h) are properly

- * initialized. For normal programs and executables, please use HAL_Initialize.

- *

- * This is mainly expected to be use from libraries that are expected to be used

- * from LabVIEW, as it handles its own initialization for objects.

- */

-void HAL_BaseInitialize(int32_t* status);

-

-#ifndef HAL_USE_LABVIEW

-

-/**

- * Gets a port handle for a specific channel.

- *

- * The created handle does not need to be freed.

- *

- * @param channel the channel number

- * @return        the created port

- */

-HAL_PortHandle HAL_GetPort(int32_t channel);

-

-/**

- * Gets a port handle for a specific channel and module.

- *

- * This is expected to be used for PCMs, as the roboRIO does not work with

- * modules anymore.

- *

- * The created handle does not need to be freed.

- *

- * @param module  the module number

- * @param channel the channel number

- * @return        the created port

- */

-HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel);

-

-/**

- * Reads the microsecond-resolution timer on the FPGA.

- *

- * @return The current time in microseconds according to the FPGA (since FPGA

- * reset).

- */

-uint64_t HAL_GetFPGATime(int32_t* status);

-

-/**

- * Call this to start up HAL. This is required for robot programs.

- *

- * This must be called before any other HAL functions. Failure to do so will

- * result in undefined behavior, and likely segmentation faults. This means that

- * any statically initialized variables in a program MUST call this function in

- * their constructors if they want to use other HAL calls.

- *

- * The common parameters are 500 for timeout and 0 for mode.

- *

- * This function is safe to call from any thread, and as many times as you wish.

- * It internally guards from any reentrancy.

- *

- * The applicable modes are:

- *   0: Try to kill an existing HAL from another program, if not successful,

- * error.

- *   1: Force kill a HAL from another program.

- *   2: Just warn if another hal exists and cannot be killed. Will likely result

- * in undefined behavior.

- *

- * @param timeout the initialization timeout (ms)

- * @param mode    the initialization mode (see remarks)

- * @return        true if initialization was successful, otherwise false.

- */

-HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode);

-

-// ifdef's definition is to allow for default parameters in C++.

-#ifdef __cplusplus

-/**

- * Reports a hardware usage to the HAL.

- *

- * @param resource       the used resource

- * @param instanceNumber the instance of the resource

- * @param context        a user specified context index

- * @param feature        a user specified feature string

- * @return               the index of the added value in NetComm

- */

-int64_t HAL_Report(int32_t resource, int32_t instanceNumber,

-                   int32_t context = 0, const char* feature = nullptr);

-#else

-

-/**

- * Reports a hardware usage to the HAL.

- *

- * @param resource       the used resource

- * @param instanceNumber the instance of the resource

- * @param context        a user specified context index

- * @param feature        a user specified feature string

- * @return               the index of the added value in NetComm

- */

-int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,

-                   const char* feature);

-#endif

-

-#endif  // HAL_USE_LABVIEW

-#ifdef __cplusplus

-}  // extern "C"

-#endif

-/** @} */

+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2008-2019 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_capi WPILib HAL API
+ * Hardware Abstraction Layer to hardware or simulator
+ * @{
+ */
+
+// clang-format off
+HAL_ENUM(HAL_RuntimeType) { HAL_Athena, HAL_Mock };
+// clang-format on
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the error message for a specific status code.
+ *
+ * @param code the status code
+ * @return     the error message for the code. This does not need to be freed.
+ */
+const char* HAL_GetErrorMessage(int32_t code);
+
+/**
+ * Returns the FPGA Version number.
+ *
+ * For now, expect this to be competition year.
+ *
+ * @return FPGA Version number.
+ */
+int32_t HAL_GetFPGAVersion(int32_t* status);
+
+/**
+ * Returns the FPGA Revision number.
+ *
+ * The format of the revision is 3 numbers.
+ * The 12 most significant bits are the Major Revision.
+ * the next 8 bits are the Minor Revision.
+ * The 12 least significant bits are the Build Number.
+ *
+ * @return FPGA Revision number.
+ */
+int64_t HAL_GetFPGARevision(int32_t* status);
+
+HAL_RuntimeType HAL_GetRuntimeType(void);
+
+/**
+ * Gets the state of the "USER" button on the roboRIO.
+ *
+ * @return true if the button is currently pressed down
+ */
+HAL_Bool HAL_GetFPGAButton(int32_t* status);
+
+/**
+ * Gets if the system outputs are currently active
+ *
+ * @return true if the system outputs are active, false if disabled
+ */
+HAL_Bool HAL_GetSystemActive(int32_t* status);
+
+/**
+ * Gets if the system is in a browned out state.
+ *
+ * @return true if the system is in a low voltage brown out, false otherwise
+ */
+HAL_Bool HAL_GetBrownedOut(int32_t* status);
+
+/**
+ * Gets a port handle for a specific channel.
+ *
+ * The created handle does not need to be freed.
+ *
+ * @param channel the channel number
+ * @return        the created port
+ */
+HAL_PortHandle HAL_GetPort(int32_t channel);
+
+/**
+ * Gets a port handle for a specific channel and module.
+ *
+ * This is expected to be used for PCMs, as the roboRIO does not work with
+ * modules anymore.
+ *
+ * The created handle does not need to be freed.
+ *
+ * @param module  the module number
+ * @param channel the channel number
+ * @return        the created port
+ */
+HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel);
+
+/**
+ * Reads the microsecond-resolution timer on the FPGA.
+ *
+ * @return The current time in microseconds according to the FPGA (since FPGA
+ * reset).
+ */
+uint64_t HAL_GetFPGATime(int32_t* status);
+
+/**
+ * Call this to start up HAL. This is required for robot programs.
+ *
+ * This must be called before any other HAL functions. Failure to do so will
+ * result in undefined behavior, and likely segmentation faults. This means that
+ * any statically initialized variables in a program MUST call this function in
+ * their constructors if they want to use other HAL calls.
+ *
+ * The common parameters are 500 for timeout and 0 for mode.
+ *
+ * This function is safe to call from any thread, and as many times as you wish.
+ * It internally guards from any reentrancy.
+ *
+ * The applicable modes are:
+ *   0: Try to kill an existing HAL from another program, if not successful,
+ * error.
+ *   1: Force kill a HAL from another program.
+ *   2: Just warn if another hal exists and cannot be killed. Will likely result
+ * in undefined behavior.
+ *
+ * @param timeout the initialization timeout (ms)
+ * @param mode    the initialization mode (see remarks)
+ * @return        true if initialization was successful, otherwise false.
+ */
+HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode);
+
+// ifdef's definition is to allow for default parameters in C++.
+#ifdef __cplusplus
+/**
+ * Reports a hardware usage to the HAL.
+ *
+ * @param resource       the used resource
+ * @param instanceNumber the instance of the resource
+ * @param context        a user specified context index
+ * @param feature        a user specified feature string
+ * @return               the index of the added value in NetComm
+ */
+int64_t HAL_Report(int32_t resource, int32_t instanceNumber,
+                   int32_t context = 0, const char* feature = nullptr);
+#else
+
+/**
+ * Reports a hardware usage to the HAL.
+ *
+ * @param resource       the used resource
+ * @param instanceNumber the instance of the resource
+ * @param context        a user specified context index
+ * @param feature        a user specified feature string
+ * @return               the index of the added value in NetComm
+ */
+int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
+                   const char* feature);
+#endif
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/I2CTypes.h b/hal/src/main/native/include/hal/I2CTypes.h
index d0b269f..b5e8235 100644
--- a/hal/src/main/native/include/hal/I2CTypes.h
+++ b/hal/src/main/native/include/hal/I2CTypes.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -21,4 +21,15 @@
 HAL_ENUM(HAL_I2CPort) { HAL_I2C_kInvalid = -1, HAL_I2C_kOnboard, HAL_I2C_kMXP };
 // clang-format on
 
+#ifdef __cplusplus
+namespace hal {
+
+/**
+ * A move-only C++ wrapper around HAL_I2CPort.
+ * Does not ensure destruction.
+ */
+using I2CPort = Handle<HAL_I2CPort, HAL_I2C_kInvalid>;
+
+}  // namespace hal
+#endif
 /** @} */
diff --git a/hal/src/main/native/include/hal/Main.h b/hal/src/main/native/include/hal/Main.h
new file mode 100644
index 0000000..866e274
--- /dev/null
+++ b/hal/src/main/native/include/hal/Main.h
@@ -0,0 +1,67 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_relay Main loop functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Sets up the system to run the provided main loop in the main thread (e.g.
+ * the thread in which main() starts execution) and run the robot code in a
+ * separate thread.
+ *
+ * Normally the robot code runs in the main thread, but some GUI systems
+ * require the GUI be run in the main thread.
+ *
+ * To be effective, this function must be called before the robot code starts
+ * the main loop (e.g. by frc::StartRobot()).
+ *
+ * @param param parameter data to pass to mainFunc and exitFunc
+ * @param mainFunc the function to be run when HAL_RunMain() is called.
+ * @param exitFunc the function to be run when HAL_ExitMain() is called.
+ */
+void HAL_SetMain(void* param, void (*mainFunc)(void*), void (*exitFunc)(void*));
+
+/**
+ * Returns true if HAL_SetMain() has been called.
+ *
+ * @return True if HAL_SetMain() has been called, false otherwise.
+ */
+HAL_Bool HAL_HasMain(void);
+
+/**
+ * Runs the main function provided to HAL_SetMain().
+ *
+ * If HAL_SetMain() has not been called, simply sleeps until HAL_ExitMain()
+ * is called.
+ */
+void HAL_RunMain(void);
+
+/**
+ * Causes HAL_RunMain() to exit.
+ *
+ * If HAL_SetMain() has been called, this calls the exit function provided
+ * to that function.
+ */
+void HAL_ExitMain(void);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/SPITypes.h b/hal/src/main/native/include/hal/SPITypes.h
index 907623c..170bd27 100644
--- a/hal/src/main/native/include/hal/SPITypes.h
+++ b/hal/src/main/native/include/hal/SPITypes.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -27,4 +27,16 @@
   HAL_SPI_kMXP
 };
 // clang-format on
+
+#ifdef __cplusplus
+namespace hal {
+
+/**
+ * A move-only C++ wrapper around HAL_SPIPort.
+ * Does not ensure destruction.
+ */
+using SPIPort = Handle<HAL_SPIPort, HAL_SPI_kInvalid>;
+
+}  // namespace hal
+#endif
 /** @} */
diff --git a/hal/src/main/native/include/hal/SerialPort.h b/hal/src/main/native/include/hal/SerialPort.h
index c2fd105..226a2cb 100644
--- a/hal/src/main/native/include/hal/SerialPort.h
+++ b/hal/src/main/native/include/hal/SerialPort.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -38,39 +38,51 @@
  *
  * @param port the serial port to initialize
  */
-void HAL_InitializeSerialPort(HAL_SerialPort port, int32_t* status);
+HAL_SerialPortHandle HAL_InitializeSerialPort(HAL_SerialPort port,
+                                              int32_t* status);
 
 /**
  * Initializes a serial port with a direct name.
  *
- * This name is the VISA name for a specific port (find this in the web dash).
+ * This name is the /dev name for a specific port.
  * Note these are not always consistent between roboRIO reboots.
  *
  * @param port     the serial port to initialize
- * @param portName the VISA port name
+ * @param portName the dev port name
  */
-void HAL_InitializeSerialPortDirect(HAL_SerialPort port, const char* portName,
-                                    int32_t* status);
+HAL_SerialPortHandle HAL_InitializeSerialPortDirect(HAL_SerialPort port,
+                                                    const char* portName,
+                                                    int32_t* status);
+
+/**
+ * Gets the raw serial port file descriptor from a handle.
+ *
+ * @param handle the serial port handle
+ * @return       the raw port descriptor
+ */
+int HAL_GetSerialFD(HAL_SerialPortHandle handle, int32_t* status);
 
 /**
  * Sets the baud rate of a serial port.
  *
  * Any value between 0 and 0xFFFFFFFF may be used. Default is 9600.
  *
- * @param port the serial port
- * @param baud the baud rate to set
+ * @param handle the serial port handle
+ * @param baud   the baud rate to set
  */
-void HAL_SetSerialBaudRate(HAL_SerialPort port, int32_t baud, int32_t* status);
+void HAL_SetSerialBaudRate(HAL_SerialPortHandle handle, int32_t baud,
+                           int32_t* status);
 
 /**
  * Sets the number of data bits on a serial port.
  *
  * Defaults to 8.
  *
- * @param port the serial port
- * @param bits the number of data bits (5-8)
+ * @param handle the serial port handle
+ * @param bits   the number of data bits (5-8)
  */
-void HAL_SetSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status);
+void HAL_SetSerialDataBits(HAL_SerialPortHandle handle, int32_t bits,
+                           int32_t* status);
 
 /**
  * Sets the number of parity bits on a serial port.
@@ -82,10 +94,11 @@
  *   3: Mark - Means exists and always 1
  *   4: Space - Means exists and always 0
  *
- * @param port   the serial port
+ * @param handle the serial port handle
  * @param parity the parity bit mode (see remarks for valid values)
  */
-void HAL_SetSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status);
+void HAL_SetSerialParity(HAL_SerialPortHandle handle, int32_t parity,
+                         int32_t* status);
 
 /**
  * Sets the number of stop bits on a serial port.
@@ -95,10 +108,10 @@
  *   15: One and a half stop bits
  *   20: Two stop bits
  *
- * @param port     the serial port
+ * @param handle   the serial port handle
  * @param stopBits the stop bit value (see remarks for valid values)
  */
-void HAL_SetSerialStopBits(HAL_SerialPort port, int32_t stopBits,
+void HAL_SetSerialStopBits(HAL_SerialPortHandle handle, int32_t stopBits,
                            int32_t* status);
 
 /**
@@ -108,10 +121,11 @@
  *   1: Flush on access
  *   2: Flush when full (default)
  *
- * @param port the serial port
- * @param mode the mode to set (see remarks for valid values)
+ * @param handle the serial port handle
+ * @param mode   the mode to set (see remarks for valid values)
  */
-void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode, int32_t* status);
+void HAL_SetSerialWriteMode(HAL_SerialPortHandle handle, int32_t mode,
+                            int32_t* status);
 
 /**
  * Sets the flow control mode of a serial port.
@@ -122,63 +136,65 @@
  *   2: RTS-CTS
  *   3: DTR-DSR
  *
- * @param port the serial port
- * @param flow the mode to set (see remarks for valid values)
+ * @param handle the serial port handle
+ * @param flow   the mode to set (see remarks for valid values)
  */
-void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
+void HAL_SetSerialFlowControl(HAL_SerialPortHandle handle, int32_t flow,
                               int32_t* status);
 
 /**
  * Sets the minimum serial read timeout of a port.
  *
- * @param port    the serial port
+ * @param handle  the serial port handle
  * @param timeout the timeout in milliseconds
  */
-void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout, int32_t* status);
+void HAL_SetSerialTimeout(HAL_SerialPortHandle handle, double timeout,
+                          int32_t* status);
 
 /**
  * Sets the termination character that terminates a read.
  *
  * By default this is disabled.
  *
- * @param port       the serial port
+ * @param handle     the serial port handle
  * @param terminator the termination character to set
  */
-void HAL_EnableSerialTermination(HAL_SerialPort port, char terminator,
+void HAL_EnableSerialTermination(HAL_SerialPortHandle handle, char terminator,
                                  int32_t* status);
 
 /**
  * Disables a termination character for reads.
  *
- * @param port the serial port
+ * @param handle the serial port handle
  */
-void HAL_DisableSerialTermination(HAL_SerialPort port, int32_t* status);
+void HAL_DisableSerialTermination(HAL_SerialPortHandle handle, int32_t* status);
 
 /**
  * Sets the size of the read buffer.
  *
- * @param port the serial port
- * @param size the read buffer size
+ * @param handle the serial port handle
+ * @param size   the read buffer size
  */
-void HAL_SetSerialReadBufferSize(HAL_SerialPort port, int32_t size,
+void HAL_SetSerialReadBufferSize(HAL_SerialPortHandle handle, int32_t size,
                                  int32_t* status);
 
 /**
  * Sets the size of the write buffer.
  *
- * @param port the serial port
- * @param size the write buffer size
+ * @param handle the serial port handle
+ * @param size   the write buffer size
  */
-void HAL_SetSerialWriteBufferSize(HAL_SerialPort port, int32_t size,
+void HAL_SetSerialWriteBufferSize(HAL_SerialPortHandle handle, int32_t size,
                                   int32_t* status);
 
 /**
  * Gets the number of bytes currently in the read buffer.
  *
- * @param port the serial port
- * @return     the number of bytes in the read buffer
+ * @param handle the serial port handle
+ * @return       the number of bytes in the read buffer
  */
-int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status);
+int32_t HAL_GetSerialBytesReceived(HAL_SerialPortHandle handle,
+                                   int32_t* status);
 
 /**
  * Reads data from the serial port.
@@ -186,44 +202,44 @@
  * Will wait for either timeout (if set), the termination char (if set), or the
  * count to be full. Whichever one comes first.
  *
- * @param port  the serial port
- * @param count the number of bytes maximum to read
- * @return      the number of bytes actually read
+ * @param handle the serial port handle
+ * @param count  the number of bytes maximum to read
+ * @return       the number of bytes actually read
  */
-int32_t HAL_ReadSerial(HAL_SerialPort port, char* buffer, int32_t count,
+int32_t HAL_ReadSerial(HAL_SerialPortHandle handle, char* buffer, int32_t count,
                        int32_t* status);
 
 /**
  * Writes data to the serial port.
  *
- * @param port   the serial port
+ * @param handle the serial port handle
  * @param buffer the buffer to write
  * @param count  the number of bytes to write from the buffer
  * @return       the number of bytes actually written
  */
-int32_t HAL_WriteSerial(HAL_SerialPort port, const char* buffer, int32_t count,
-                        int32_t* status);
+int32_t HAL_WriteSerial(HAL_SerialPortHandle handle, const char* buffer,
+                        int32_t count, int32_t* status);
 
 /**
  * Flushes the serial write buffer out to the port.
  *
- * @param port the serial port
+ * @param handle the serial port handle
  */
-void HAL_FlushSerial(HAL_SerialPort port, int32_t* status);
+void HAL_FlushSerial(HAL_SerialPortHandle handle, int32_t* status);
 
 /**
  * Clears the receive buffer of the serial port.
  *
- * @param port the serial port
+ * @param handle the serial port handle
  */
-void HAL_ClearSerial(HAL_SerialPort port, int32_t* status);
+void HAL_ClearSerial(HAL_SerialPortHandle handle, int32_t* status);
 
 /**
  * Closes a serial port.
  *
- * @param port the serial port to close
+ * @param handle the serial port handle to close
  */
-void HAL_CloseSerial(HAL_SerialPort port, int32_t* status);
+void HAL_CloseSerial(HAL_SerialPortHandle handle, int32_t* status);
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/hal/src/main/native/include/hal/SimDevice.h b/hal/src/main/native/include/hal/SimDevice.h
new file mode 100644
index 0000000..b05021e
--- /dev/null
+++ b/hal/src/main/native/include/hal/SimDevice.h
@@ -0,0 +1,610 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+#include <initializer_list>
+
+#include <wpi/ArrayRef.h>
+#endif
+
+#include "hal/Types.h"
+#include "hal/Value.h"
+
+/**
+ * @defgroup hal_simdevice Simulator Device Framework
+ * @ingroup hal_capi
+ * HAL Simulator Device Framework.  This enables creating simulation-only
+ * variables for higher level device access.  For example, a device such as
+ * a SPI gyro can expose angle and rate variables to enable direct access
+ * from simulation extensions or user test code instead of requiring that
+ * the SPI bit-level protocol be implemented in simulation code.
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a simulated device.
+ *
+ * The device name must be unique.  0 is returned if the device name already
+ * exists.  If multiple instances of the same device are desired, recommend
+ * appending the instance/unique identifer in brackets to the base name,
+ * e.g. "device[1]".
+ *
+ * 0 is returned if not in simulation.
+ *
+ * @param name device name
+ * @return simulated device handle
+ */
+HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name);
+
+/**
+ * Frees a simulated device.
+ *
+ * This also allows the same device name to be used again.
+ * This also frees all the simulated values created on the device.
+ *
+ * @param handle simulated device handle
+ */
+void HAL_FreeSimDevice(HAL_SimDeviceHandle handle);
+
+/**
+ * Creates a value on a simulated device.
+ *
+ * Returns 0 if not in simulation; this can be used to avoid calls
+ * to Set/Get functions.
+ *
+ * @param device simulated device handle
+ * @param name value name
+ * @param readonly if the value should not be written from simulation side
+ * @param initialValue initial value
+ * @return simulated value handle
+ */
+HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
+                                      const char* name, HAL_Bool readonly,
+                                      const struct HAL_Value* initialValue);
+
+#ifdef __cplusplus
+extern "C++" {
+inline HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
+                                             const char* name,
+                                             HAL_Bool readonly,
+                                             const HAL_Value& initialValue) {
+  return HAL_CreateSimValue(device, name, readonly, &initialValue);
+}
+}  // extern "C++"
+#endif
+
+/**
+ * Creates a double value on a simulated device.
+ *
+ * Returns 0 if not in simulation; this can be used to avoid calls
+ * to Set/Get functions.
+ *
+ * @param device simulated device handle
+ * @param name value name
+ * @param readonly if the value should not be written from simulation side
+ * @param initialValue initial value
+ * @return simulated value handle
+ */
+inline HAL_SimValueHandle HAL_CreateSimValueDouble(HAL_SimDeviceHandle device,
+                                                   const char* name,
+                                                   HAL_Bool readonly,
+                                                   double initialValue) {
+  struct HAL_Value v = HAL_MakeDouble(initialValue);
+  return HAL_CreateSimValue(device, name, readonly, &v);
+}
+
+/**
+ * Creates an enumerated value on a simulated device.
+ *
+ * Enumerated values are always in the range 0 to numOptions-1.
+ *
+ * Returns 0 if not in simulation; this can be used to avoid calls
+ * to Set/Get functions.
+ *
+ * @param device simulated device handle
+ * @param name value name
+ * @param readonly if the value should not be written from simulation side
+ * @param numOptions number of enumerated value options (length of options)
+ * @param options array of option descriptions
+ * @param initialValue initial value (selection)
+ * @return simulated value handle
+ */
+HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
+                                          const char* name, HAL_Bool readonly,
+                                          int32_t numOptions,
+                                          const char** options,
+                                          int32_t initialValue);
+
+/**
+ * Creates a boolean value on a simulated device.
+ *
+ * Returns 0 if not in simulation; this can be used to avoid calls
+ * to Set/Get functions.
+ *
+ * @param device simulated device handle
+ * @param name value name
+ * @param readonly if the value should not be written from simulation side
+ * @param initialValue initial value
+ * @return simulated value handle
+ */
+inline HAL_SimValueHandle HAL_CreateSimValueBoolean(HAL_SimDeviceHandle device,
+                                                    const char* name,
+                                                    HAL_Bool readonly,
+                                                    HAL_Bool initialValue) {
+  struct HAL_Value v = HAL_MakeBoolean(initialValue);
+  return HAL_CreateSimValue(device, name, readonly, &v);
+}
+
+/**
+ * Gets a simulated value.
+ *
+ * @param handle simulated value handle
+ * @param value value (output parameter)
+ */
+void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value);
+
+#ifdef __cplusplus
+extern "C++" {
+inline HAL_Value HAL_GetSimValue(HAL_SimValueHandle handle) {
+  HAL_Value v;
+  HAL_GetSimValue(handle, &v);
+  return v;
+}
+}  // extern "C++"
+#endif
+
+/**
+ * Gets a simulated value (double).
+ *
+ * @param handle simulated value handle
+ * @return The current value
+ */
+inline double HAL_GetSimValueDouble(HAL_SimValueHandle handle) {
+  struct HAL_Value v;
+  HAL_GetSimValue(handle, &v);
+  return v.type == HAL_DOUBLE ? v.data.v_double : 0.0;
+}
+
+/**
+ * Gets a simulated value (enum).
+ *
+ * @param handle simulated value handle
+ * @return The current value
+ */
+inline int32_t HAL_GetSimValueEnum(HAL_SimValueHandle handle) {
+  struct HAL_Value v;
+  HAL_GetSimValue(handle, &v);
+  return v.type == HAL_ENUM ? v.data.v_enum : 0;
+}
+
+/**
+ * Gets a simulated value (boolean).
+ *
+ * @param handle simulated value handle
+ * @return The current value
+ */
+inline HAL_Bool HAL_GetSimValueBoolean(HAL_SimValueHandle handle) {
+  struct HAL_Value v;
+  HAL_GetSimValue(handle, &v);
+  return v.type == HAL_BOOLEAN ? v.data.v_boolean : 0;
+}
+
+/**
+ * Sets a simulated value.
+ *
+ * @param handle simulated value handle
+ * @param value the value to set
+ */
+void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value);
+
+#ifdef __cplusplus
+extern "C++" {
+inline void HAL_SetSimValue(HAL_SimValueHandle handle, const HAL_Value& value) {
+  HAL_SetSimValue(handle, &value);
+}
+}  // extern "C++"
+#endif
+
+/**
+ * Sets a simulated value (double).
+ *
+ * @param handle simulated value handle
+ * @param value the value to set
+ */
+inline void HAL_SetSimValueDouble(HAL_SimValueHandle handle, double value) {
+  struct HAL_Value v = HAL_MakeDouble(value);
+  HAL_SetSimValue(handle, &v);
+}
+
+/**
+ * Sets a simulated value (enum).
+ *
+ * @param handle simulated value handle
+ * @param value the value to set
+ */
+inline void HAL_SetSimValueEnum(HAL_SimValueHandle handle, int32_t value) {
+  struct HAL_Value v = HAL_MakeEnum(value);
+  HAL_SetSimValue(handle, &v);
+}
+
+/**
+ * Sets a simulated value (boolean).
+ *
+ * @param handle simulated value handle
+ * @param value the value to set
+ */
+inline void HAL_SetSimValueBoolean(HAL_SimValueHandle handle, HAL_Bool value) {
+  struct HAL_Value v = HAL_MakeBoolean(value);
+  HAL_SetSimValue(handle, &v);
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#ifdef __cplusplus
+namespace hal {
+
+/**
+ * C++ wrapper around a HAL simulator value handle.
+ */
+class SimValue {
+ public:
+  /**
+   * Default constructor that results in an "empty" object that is false in
+   * a boolean context.
+   */
+  SimValue() = default;
+
+  /**
+   * Wraps a simulated value handle as returned by HAL_CreateSimValue().
+   *
+   * @param handle simulated value handle
+   */
+  /*implicit*/ SimValue(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+      : m_handle(val) {}
+
+  /**
+   * Determine if handle is empty.  Should be used to optimize out code paths
+   * that are taken/not taken in simulation.
+   *
+   * @return False if handle is empty, true if handle is valid.
+   */
+  explicit operator bool() const { return m_handle != HAL_kInvalidHandle; }
+
+  /**
+   * Get the internal device handle.
+   *
+   * @return internal handle
+   */
+  operator HAL_SimValueHandle() const { return m_handle; }
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  HAL_Value GetValue() const { return HAL_GetSimValue(m_handle); }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  void SetValue(const HAL_Value& value) { HAL_SetSimValue(m_handle, value); }
+
+ protected:
+  HAL_SimValueHandle m_handle = HAL_kInvalidHandle;
+};
+
+/**
+ * C++ wrapper around a HAL simulator double value handle.
+ */
+class SimDouble : public SimValue {
+ public:
+  /**
+   * Default constructor that results in an "empty" object that is false in
+   * a boolean context.
+   */
+  SimDouble() = default;
+
+  /**
+   * Wraps a simulated value handle as returned by HAL_CreateSimValueDouble().
+   *
+   * @param handle simulated value handle
+   */
+  /*implicit*/ SimDouble(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+      : SimValue(val) {}
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  double Get() const { return HAL_GetSimValueDouble(m_handle); }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  void Set(double value) { HAL_SetSimValueDouble(m_handle, value); }
+};
+
+/**
+ * C++ wrapper around a HAL simulator enum value handle.
+ */
+class SimEnum : public SimValue {
+ public:
+  /**
+   * Default constructor that results in an "empty" object that is false in
+   * a boolean context.
+   */
+  SimEnum() = default;
+
+  /**
+   * Wraps a simulated value handle as returned by HAL_CreateSimValueEnum().
+   *
+   * @param handle simulated value handle
+   */
+  /*implicit*/ SimEnum(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+      : SimValue(val) {}
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  int32_t Get() const { return HAL_GetSimValueEnum(m_handle); }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  void Set(int32_t value) { HAL_SetSimValueEnum(m_handle, value); }
+};
+
+/**
+ * C++ wrapper around a HAL simulator boolean value handle.
+ */
+class SimBoolean : public SimValue {
+ public:
+  /**
+   * Default constructor that results in an "empty" object that is false in
+   * a boolean context.
+   */
+  SimBoolean() = default;
+
+  /**
+   * Wraps a simulated value handle as returned by HAL_CreateSimValueBoolean().
+   *
+   * @param handle simulated value handle
+   */
+  /*implicit*/ SimBoolean(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+      : SimValue(val) {}
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  bool Get() const { return HAL_GetSimValueBoolean(m_handle); }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  void Set(bool value) { HAL_SetSimValueBoolean(m_handle, value); }
+};
+
+/**
+ * A move-only C++ wrapper around a HAL simulator device handle.
+ */
+class SimDevice {
+ public:
+  /**
+   * Default constructor that results in an "empty" object that is false in
+   * a boolean context.
+   */
+  SimDevice() = default;
+
+  /**
+   * Creates a simulated device.
+   *
+   * The device name must be unique.  Returns null if the device name
+   * already exists.  If multiple instances of the same device are desired,
+   * recommend appending the instance/unique identifer in brackets to the base
+   * name, e.g. "device[1]".
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name device name
+   */
+  explicit SimDevice(const char* name) : m_handle(HAL_CreateSimDevice(name)) {}
+
+  /**
+   * Creates a simulated device.
+   *
+   * The device name must be unique.  Returns null if the device name
+   * already exists.  This is a convenience method that appends index in
+   * brackets to the device name, e.g. passing index=1 results in "device[1]"
+   * for the device name.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name device name
+   * @param index device index number to append to name
+   */
+  SimDevice(const char* name, int index);
+
+  /**
+   * Creates a simulated device.
+   *
+   * The device name must be unique.  Returns null if the device name
+   * already exists.  This is a convenience method that appends index and
+   * channel in brackets to the device name, e.g. passing index=1 and channel=2
+   * results in "device[1,2]" for the device name.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name device name
+   * @param index device index number to append to name
+   * @param channel device channel number to append to name
+   */
+  SimDevice(const char* name, int index, int channel);
+
+  /**
+   * Wraps a simulated device handle as returned by HAL_CreateSimDevice().
+   *
+   * @param handle simulated device handle
+   */
+  /*implicit*/ SimDevice(HAL_SimDeviceHandle val)  // NOLINT(runtime/explicit)
+      : m_handle(val) {}
+
+  ~SimDevice() {
+    if (m_handle != HAL_kInvalidHandle) HAL_FreeSimDevice(m_handle);
+  }
+
+  SimDevice(const SimDevice&) = delete;
+  SimDevice& operator=(const SimDevice&) = delete;
+
+  SimDevice(SimDevice&& rhs) : m_handle(rhs.m_handle) {
+    rhs.m_handle = HAL_kInvalidHandle;
+  }
+
+  SimDevice& operator=(SimDevice&& rhs) {
+    m_handle = rhs.m_handle;
+    rhs.m_handle = HAL_kInvalidHandle;
+    return *this;
+  }
+
+  /**
+   * Determine if handle is empty.  Should be used to optimize out code paths
+   * that are taken/not taken in simulation.
+   *
+   * @return False if handle is empty, true if handle is valid.
+   */
+  explicit operator bool() const { return m_handle != HAL_kInvalidHandle; }
+
+  /**
+   * Get the internal device handle.
+   *
+   * @return internal handle
+   */
+  operator HAL_SimDeviceHandle() const { return m_handle; }
+
+  /**
+   * Creates a value on the simulated device.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param readonly if the value should not be written from simulation side
+   * @param initialValue initial value
+   * @return simulated value object
+   */
+  SimValue CreateValue(const char* name, bool readonly,
+                       const HAL_Value& initialValue) {
+    return HAL_CreateSimValue(m_handle, name, readonly, &initialValue);
+  }
+
+  /**
+   * Creates a double value on the simulated device.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param readonly if the value should not be written from simulation side
+   * @param initialValue initial value
+   * @return simulated double value object
+   */
+  SimDouble CreateDouble(const char* name, bool readonly, double initialValue) {
+    return HAL_CreateSimValueDouble(m_handle, name, readonly, initialValue);
+  }
+
+  /**
+   * Creates an enumerated value on the simulated device.
+   *
+   * Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param readonly if the value should not be written from simulation side
+   * @param options array of option descriptions
+   * @param initialValue initial value (selection)
+   * @return simulated enum value object
+   */
+  SimEnum CreateEnum(const char* name, bool readonly,
+                     std::initializer_list<const char*> options,
+                     int32_t initialValue) {
+    return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
+                                  const_cast<const char**>(options.begin()),
+                                  initialValue);
+  }
+
+  /**
+   * Creates an enumerated value on the simulated device.
+   *
+   * Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param readonly if the value should not be written from simulation side
+   * @param options array of option descriptions
+   * @param initialValue initial value (selection)
+   * @return simulated enum value object
+   */
+  SimEnum CreateEnum(const char* name, bool readonly,
+                     wpi::ArrayRef<const char*> options, int32_t initialValue) {
+    return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
+                                  const_cast<const char**>(options.data()),
+                                  initialValue);
+  }
+
+  /**
+   * Creates a boolean value on the simulated device.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param readonly if the value should not be written from simulation side
+   * @param initialValue initial value
+   * @return simulated boolean value object
+   */
+  SimBoolean CreateBoolean(const char* name, bool readonly, bool initialValue) {
+    return HAL_CreateSimValueBoolean(m_handle, name, readonly, initialValue);
+  }
+
+ protected:
+  HAL_SimDeviceHandle m_handle = HAL_kInvalidHandle;
+};
+
+}  // namespace hal
+#endif  // __cplusplus
diff --git a/hal/src/main/native/include/hal/Threads.h b/hal/src/main/native/include/hal/Threads.h
index 4908c9c..aea4399 100644
--- a/hal/src/main/native/include/hal/Threads.h
+++ b/hal/src/main/native/include/hal/Threads.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#define NativeThreadHandle const void*
-
 #include "hal/Types.h"
 
 /**
@@ -17,7 +15,12 @@
  * @{
  */
 
+typedef const void* NativeThreadHandle;
+
+#ifdef __cplusplus
 extern "C" {
+#endif
+
 /**
  * Gets the thread priority for the specified thread.
  *
@@ -68,5 +71,8 @@
  */
 HAL_Bool HAL_SetCurrentThreadPriority(HAL_Bool realTime, int32_t priority,
                                       int32_t* status);
+
+#ifdef __cplusplus
 }  // extern "C"
+#endif
 /** @} */
diff --git a/hal/src/main/native/include/hal/Types.h b/hal/src/main/native/include/hal/Types.h
index 6180439..5ce6009 100644
--- a/hal/src/main/native/include/hal/Types.h
+++ b/hal/src/main/native/include/hal/Types.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -49,8 +49,14 @@
 
 typedef HAL_Handle HAL_SolenoidHandle;
 
+typedef HAL_Handle HAL_SerialPortHandle;
+
 typedef HAL_Handle HAL_CANHandle;
 
+typedef HAL_Handle HAL_SimDeviceHandle;
+
+typedef HAL_Handle HAL_SimValueHandle;
+
 typedef HAL_CANHandle HAL_PDPHandle;
 
 typedef int32_t HAL_Bool;
@@ -62,4 +68,37 @@
   typedef int32_t name; \
   enum name
 #endif
+
+#ifdef __cplusplus
+namespace hal {
+
+/**
+ * A move-only C++ wrapper around a HAL handle.
+ * Does not ensure destruction.
+ */
+template <typename CType, int32_t CInvalid = HAL_kInvalidHandle>
+class Handle {
+ public:
+  Handle() = default;
+  /*implicit*/ Handle(CType val) : m_handle(val) {}  // NOLINT(runtime/explicit)
+
+  Handle(const Handle&) = delete;
+  Handle& operator=(const Handle&) = delete;
+
+  Handle(Handle&& rhs) : m_handle(rhs.m_handle) { rhs.m_handle = CInvalid; }
+
+  Handle& operator=(Handle&& rhs) {
+    m_handle = rhs.m_handle;
+    rhs.m_handle = CInvalid;
+    return *this;
+  }
+
+  operator CType() const { return m_handle; }
+
+ private:
+  CType m_handle = CInvalid;
+};
+
+}  // namespace hal
+#endif
 /** @} */
diff --git a/hal/src/main/native/include/mockdata/HAL_Value.h b/hal/src/main/native/include/hal/Value.h
similarity index 66%
rename from hal/src/main/native/include/mockdata/HAL_Value.h
rename to hal/src/main/native/include/hal/Value.h
index ee348b9..578d989 100644
--- a/hal/src/main/native/include/mockdata/HAL_Value.h
+++ b/hal/src/main/native/include/hal/Value.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "hal/Types.h"
 
 /** HAL data types. */
@@ -16,9 +14,9 @@
   HAL_UNASSIGNED = 0,
   HAL_BOOLEAN = 0x01,
   HAL_DOUBLE = 0x02,
-  HAL_ENUM = 0x16,
-  HAL_INT = 0x32,
-  HAL_LONG = 0x64,
+  HAL_ENUM = 0x04,
+  HAL_INT = 0x08,
+  HAL_LONG = 0x10,
 };
 
 /** HAL Entry Value.  Note this is a typed union. */
@@ -33,39 +31,45 @@
   enum HAL_Type type;
 };
 
-inline HAL_Value MakeBoolean(HAL_Bool v) {
-  HAL_Value value;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+inline struct HAL_Value HAL_MakeBoolean(HAL_Bool v) {
+  struct HAL_Value value;
   value.type = HAL_BOOLEAN;
   value.data.v_boolean = v;
   return value;
 }
 
-inline HAL_Value MakeEnum(int v) {
-  HAL_Value value;
+inline struct HAL_Value HAL_MakeEnum(int v) {
+  struct HAL_Value value;
   value.type = HAL_ENUM;
   value.data.v_enum = v;
   return value;
 }
 
-inline HAL_Value MakeInt(int v) {
-  HAL_Value value;
+inline struct HAL_Value HAL_MakeInt(int v) {
+  struct HAL_Value value;
   value.type = HAL_INT;
   value.data.v_int = v;
   return value;
 }
 
-inline HAL_Value MakeLong(int64_t v) {
-  HAL_Value value;
+inline struct HAL_Value HAL_MakeLong(int64_t v) {
+  struct HAL_Value value;
   value.type = HAL_LONG;
   value.data.v_long = v;
   return value;
 }
 
-inline HAL_Value MakeDouble(double v) {
-  HAL_Value value;
+inline struct HAL_Value HAL_MakeDouble(double v) {
+  struct HAL_Value value;
   value.type = HAL_DOUBLE;
   value.data.v_double = v;
   return value;
 }
 
+#ifdef __cplusplus
+}  // extern "C"
 #endif
diff --git a/hal/src/main/native/include/hal/cpp/Log.h b/hal/src/main/native/include/hal/cpp/Log.h
deleted file mode 100644
index bcc3995..0000000
--- a/hal/src/main/native/include/hal/cpp/Log.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <chrono>
-#include <string>
-
-#include <wpi/SmallString.h>
-#include <wpi/raw_ostream.h>
-
-inline std::string NowTime();
-
-enum TLogLevel {
-  logNONE,
-  logERROR,
-  logWARNING,
-  logINFO,
-  logDEBUG,
-  logDEBUG1,
-  logDEBUG2,
-  logDEBUG3,
-  logDEBUG4
-};
-
-class Log {
- public:
-  Log();
-  virtual ~Log();
-  wpi::raw_ostream& Get(TLogLevel level = logINFO);
-
- public:
-  static TLogLevel& ReportingLevel();
-  static std::string ToString(TLogLevel level);
-  static TLogLevel FromString(const std::string& level);
-
- protected:
-  wpi::SmallString<128> buf;
-  wpi::raw_svector_ostream oss{buf};
-
- private:
-  Log(const Log&);
-  Log& operator=(const Log&);
-};
-
-inline Log::Log() {}
-
-inline wpi::raw_ostream& Log::Get(TLogLevel level) {
-  oss << "- " << NowTime();
-  oss << " " << ToString(level) << ": ";
-  if (level > logDEBUG) {
-    oss << std::string(level - logDEBUG, '\t');
-  }
-  return oss;
-}
-
-inline Log::~Log() {
-  oss << "\n";
-  wpi::errs() << oss.str();
-}
-
-inline TLogLevel& Log::ReportingLevel() {
-  static TLogLevel reportingLevel = logDEBUG4;
-  return reportingLevel;
-}
-
-inline std::string Log::ToString(TLogLevel level) {
-  static const char* const buffer[] = {"NONE",   "ERROR",  "WARNING",
-                                       "INFO",   "DEBUG",  "DEBUG1",
-                                       "DEBUG2", "DEBUG3", "DEBUG4"};
-  return buffer[level];
-}
-
-inline TLogLevel Log::FromString(const std::string& level) {
-  if (level == "DEBUG4") return logDEBUG4;
-  if (level == "DEBUG3") return logDEBUG3;
-  if (level == "DEBUG2") return logDEBUG2;
-  if (level == "DEBUG1") return logDEBUG1;
-  if (level == "DEBUG") return logDEBUG;
-  if (level == "INFO") return logINFO;
-  if (level == "WARNING") return logWARNING;
-  if (level == "ERROR") return logERROR;
-  if (level == "NONE") return logNONE;
-  Log().Get(logWARNING) << "Unknown logging level '" << level
-                        << "'. Using INFO level as default.";
-  return logINFO;
-}
-
-using FILELog = Log;  // NOLINT
-
-#define FILE_LOG(level)                  \
-  if (level > FILELog::ReportingLevel()) \
-    ;                                    \
-  else                                   \
-    Log().Get(level)
-
-inline std::string NowTime() {
-  wpi::SmallString<128> buf;
-  wpi::raw_svector_ostream oss(buf);
-
-  using std::chrono::duration_cast;
-
-  auto now = std::chrono::system_clock::now().time_since_epoch();
-
-  // Hours
-  auto count = duration_cast<std::chrono::hours>(now).count() % 24;
-  if (count < 10) oss << "0";
-  oss << count << ":";
-
-  // Minutes
-  count = duration_cast<std::chrono::minutes>(now).count() % 60;
-  if (count < 10) oss << "0";
-  oss << count << ":";
-
-  // Seconds
-  count = duration_cast<std::chrono::seconds>(now).count() % 60;
-  if (count < 10) oss << "0";
-  oss << count << ".";
-
-  // Milliseconds
-  oss << duration_cast<std::chrono::milliseconds>(now).count() % 1000;
-
-  return oss.str();
-}
diff --git a/hal/src/main/native/include/hal/cpp/UnsafeDIO.h b/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
index ceb41c3..dad5eb7 100644
--- a/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
+++ b/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -77,7 +77,7 @@
   tDIO* dSys = detail::UnsafeGetDigialSystem();
   auto mask = detail::ComputeDigitalMask(handle, status);
   if (status != 0) return;
-  std::lock_guard<wpi::mutex> lock(dioMutex);
+  std::scoped_lock lock(dioMutex);
 
   tDIO::tOutputEnable enableOE = dSys->readOutputEnable(status);
   enableOE.value |= mask;
diff --git a/hal/src/main/native/include/hal/handles/DigitalHandleResource.h b/hal/src/main/native/include/hal/handles/DigitalHandleResource.h
index 23fb676..dcd4b97 100644
--- a/hal/src/main/native/include/hal/handles/DigitalHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/DigitalHandleResource.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -59,7 +59,7 @@
     *status = RESOURCE_OUT_OF_RANGE;
     return HAL_kInvalidHandle;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // check for allocation, otherwise allocate and return a valid handle
   if (m_structures[index] != nullptr) {
     *status = RESOURCE_IS_ALLOCATED;
@@ -77,7 +77,7 @@
   if (index < 0 || index >= size) {
     return nullptr;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // return structure. Null will propogate correctly, so no need to manually
   // check.
   return m_structures[index];
@@ -90,14 +90,14 @@
   int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
   if (index < 0 || index >= size) return;
   // lock and deallocated handle
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   m_structures[index].reset();
 }
 
 template <typename THandle, typename TStruct, int16_t size>
 void DigitalHandleResource<THandle, TStruct, size>::ResetHandles() {
   for (int i = 0; i < size; i++) {
-    std::lock_guard<wpi::mutex> lock(m_handleMutexes[i]);
+    std::scoped_lock lock(m_handleMutexes[i]);
     m_structures[i].reset();
   }
   HandleBase::ResetHandles();
diff --git a/hal/src/main/native/include/hal/handles/HandlesInternal.h b/hal/src/main/native/include/hal/handles/HandlesInternal.h
index 85b3493..5340d82 100644
--- a/hal/src/main/native/include/hal/handles/HandlesInternal.h
+++ b/hal/src/main/native/include/hal/handles/HandlesInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -65,6 +65,7 @@
   Vendor = 17,
   SimulationJni = 18,
   CAN = 19,
+  SerialPort = 20,
 };
 
 /**
diff --git a/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h b/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h
index a038e04..2725573 100644
--- a/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -66,7 +66,7 @@
     *status = RESOURCE_OUT_OF_RANGE;
     return HAL_kInvalidHandle;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // check for allocation, otherwise allocate and return a valid handle
   if (m_structures[index] != nullptr) {
     *status = RESOURCE_IS_ALLOCATED;
@@ -86,7 +86,7 @@
   if (index < 0 || index >= size) {
     return nullptr;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // return structure. Null will propogate correctly, so no need to manually
   // check.
   return m_structures[index];
@@ -100,7 +100,7 @@
   int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
   if (index < 0 || index >= size) return;
   // lock and deallocated handle
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   m_structures[index].reset();
 }
 
@@ -109,7 +109,7 @@
 void IndexedClassedHandleResource<THandle, TStruct, size,
                                   enumValue>::ResetHandles() {
   for (int i = 0; i < size; i++) {
-    std::lock_guard<wpi::mutex> lock(m_handleMutexes[i]);
+    std::scoped_lock lock(m_handleMutexes[i]);
     m_structures[i].reset();
   }
   HandleBase::ResetHandles();
diff --git a/hal/src/main/native/include/hal/handles/IndexedHandleResource.h b/hal/src/main/native/include/hal/handles/IndexedHandleResource.h
index 39abf58..2bca4ce 100644
--- a/hal/src/main/native/include/hal/handles/IndexedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/IndexedHandleResource.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -61,7 +61,7 @@
     *status = RESOURCE_OUT_OF_RANGE;
     return HAL_kInvalidHandle;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // check for allocation, otherwise allocate and return a valid handle
   if (m_structures[index] != nullptr) {
     *status = RESOURCE_IS_ALLOCATED;
@@ -80,7 +80,7 @@
   if (index < 0 || index >= size) {
     return nullptr;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // return structure. Null will propogate correctly, so no need to manually
   // check.
   return m_structures[index];
@@ -94,7 +94,7 @@
   int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
   if (index < 0 || index >= size) return;
   // lock and deallocated handle
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   m_structures[index].reset();
 }
 
@@ -102,7 +102,7 @@
           HAL_HandleEnum enumValue>
 void IndexedHandleResource<THandle, TStruct, size, enumValue>::ResetHandles() {
   for (int i = 0; i < size; i++) {
-    std::lock_guard<wpi::mutex> lock(m_handleMutexes[i]);
+    std::scoped_lock lock(m_handleMutexes[i]);
     m_structures[i].reset();
   }
   HandleBase::ResetHandles();
diff --git a/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h b/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h
index 2723129..a991fc3 100644
--- a/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -58,12 +58,12 @@
 LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
     std::shared_ptr<TStruct> toSet) {
   // globally lock to loop through indices
-  std::lock_guard<wpi::mutex> lock(m_allocateMutex);
+  std::scoped_lock lock(m_allocateMutex);
   for (int16_t i = 0; i < size; i++) {
     if (m_structures[i] == nullptr) {
       // if a false index is found, grab its specific mutex
       // and allocate it.
-      std::lock_guard<wpi::mutex> lock(m_handleMutexes[i]);
+      std::scoped_lock lock(m_handleMutexes[i]);
       m_structures[i] = toSet;
       return static_cast<THandle>(createHandle(i, enumValue, m_version));
     }
@@ -81,7 +81,7 @@
   if (index < 0 || index >= size) {
     return nullptr;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // return structure. Null will propogate correctly, so no need to manually
   // check.
   return m_structures[index];
@@ -95,8 +95,8 @@
   int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
   if (index < 0 || index >= size) return;
   // lock and deallocated handle
-  std::lock_guard<wpi::mutex> allocateLock(m_allocateMutex);
-  std::lock_guard<wpi::mutex> handleLock(m_handleMutexes[index]);
+  std::scoped_lock allocateLock(m_allocateMutex);
+  std::scoped_lock handleLock(m_handleMutexes[index]);
   m_structures[index].reset();
 }
 
@@ -105,9 +105,9 @@
 void LimitedClassedHandleResource<THandle, TStruct, size,
                                   enumValue>::ResetHandles() {
   {
-    std::lock_guard<wpi::mutex> allocateLock(m_allocateMutex);
+    std::scoped_lock allocateLock(m_allocateMutex);
     for (int i = 0; i < size; i++) {
-      std::lock_guard<wpi::mutex> handleLock(m_handleMutexes[i]);
+      std::scoped_lock handleLock(m_handleMutexes[i]);
       m_structures[i].reset();
     }
   }
diff --git a/hal/src/main/native/include/hal/handles/LimitedHandleResource.h b/hal/src/main/native/include/hal/handles/LimitedHandleResource.h
index a535829..0756634 100644
--- a/hal/src/main/native/include/hal/handles/LimitedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/LimitedHandleResource.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -54,12 +54,12 @@
           HAL_HandleEnum enumValue>
 THandle LimitedHandleResource<THandle, TStruct, size, enumValue>::Allocate() {
   // globally lock to loop through indices
-  std::lock_guard<wpi::mutex> lock(m_allocateMutex);
+  std::scoped_lock lock(m_allocateMutex);
   for (int16_t i = 0; i < size; i++) {
     if (m_structures[i] == nullptr) {
       // if a false index is found, grab its specific mutex
       // and allocate it.
-      std::lock_guard<wpi::mutex> lock(m_handleMutexes[i]);
+      std::scoped_lock lock(m_handleMutexes[i]);
       m_structures[i] = std::make_shared<TStruct>();
       return static_cast<THandle>(createHandle(i, enumValue, m_version));
     }
@@ -76,7 +76,7 @@
   if (index < 0 || index >= size) {
     return nullptr;
   }
-  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  std::scoped_lock lock(m_handleMutexes[index]);
   // return structure. Null will propogate correctly, so no need to manually
   // check.
   return m_structures[index];
@@ -90,8 +90,8 @@
   int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
   if (index < 0 || index >= size) return;
   // lock and deallocated handle
-  std::lock_guard<wpi::mutex> allocateLock(m_allocateMutex);
-  std::lock_guard<wpi::mutex> handleLock(m_handleMutexes[index]);
+  std::scoped_lock allocateLock(m_allocateMutex);
+  std::scoped_lock handleLock(m_handleMutexes[index]);
   m_structures[index].reset();
 }
 
@@ -99,9 +99,9 @@
           HAL_HandleEnum enumValue>
 void LimitedHandleResource<THandle, TStruct, size, enumValue>::ResetHandles() {
   {
-    std::lock_guard<wpi::mutex> allocateLock(m_allocateMutex);
+    std::scoped_lock allocateLock(m_allocateMutex);
     for (int i = 0; i < size; i++) {
-      std::lock_guard<wpi::mutex> handleLock(m_handleMutexes[i]);
+      std::scoped_lock handleLock(m_handleMutexes[i]);
       m_structures[i].reset();
     }
   }
diff --git a/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h b/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
index 7df8061..96a91f8 100644
--- a/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2008-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -63,7 +63,7 @@
 template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
 THandle UnlimitedHandleResource<THandle, TStruct, enumValue>::Allocate(
     std::shared_ptr<TStruct> structure) {
-  std::lock_guard<wpi::mutex> lock(m_handleMutex);
+  std::scoped_lock lock(m_handleMutex);
   size_t i;
   for (i = 0; i < m_structures.size(); i++) {
     if (m_structures[i] == nullptr) {
@@ -82,7 +82,7 @@
 std::shared_ptr<TStruct>
 UnlimitedHandleResource<THandle, TStruct, enumValue>::Get(THandle handle) {
   int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
-  std::lock_guard<wpi::mutex> lock(m_handleMutex);
+  std::scoped_lock lock(m_handleMutex);
   if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
     return nullptr;
   return m_structures[index];
@@ -92,7 +92,7 @@
 std::shared_ptr<TStruct>
 UnlimitedHandleResource<THandle, TStruct, enumValue>::Free(THandle handle) {
   int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
-  std::lock_guard<wpi::mutex> lock(m_handleMutex);
+  std::scoped_lock lock(m_handleMutex);
   if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
     return nullptr;
   return std::move(m_structures[index]);
@@ -101,7 +101,7 @@
 template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
 void UnlimitedHandleResource<THandle, TStruct, enumValue>::ResetHandles() {
   {
-    std::lock_guard<wpi::mutex> lock(m_handleMutex);
+    std::scoped_lock lock(m_handleMutex);
     for (size_t i = 0; i < m_structures.size(); i++) {
       m_structures[i].reset();
     }
@@ -113,7 +113,7 @@
 template <typename Functor>
 void UnlimitedHandleResource<THandle, TStruct, enumValue>::ForEach(
     Functor func) {
-  std::lock_guard<wpi::mutex> lock(m_handleMutex);
+  std::scoped_lock lock(m_handleMutex);
   size_t i;
   for (i = 0; i < m_structures.size(); i++) {
     if (m_structures[i] != nullptr) {
diff --git a/hal/src/main/native/include/mockdata/AccelerometerData.h b/hal/src/main/native/include/mockdata/AccelerometerData.h
index 79f151d..aa89f6e 100644
--- a/hal/src/main/native/include/mockdata/AccelerometerData.h
+++ b/hal/src/main/native/include/mockdata/AccelerometerData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Accelerometer.h"
 #include "hal/Types.h"
@@ -66,5 +64,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/AnalogGyroData.h b/hal/src/main/native/include/mockdata/AnalogGyroData.h
index 5b648ee..56c739d 100644
--- a/hal/src/main/native/include/mockdata/AnalogGyroData.h
+++ b/hal/src/main/native/include/mockdata/AnalogGyroData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -47,5 +45,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/AnalogInData.h b/hal/src/main/native/include/mockdata/AnalogInData.h
index 7a95164..e571563 100644
--- a/hal/src/main/native/include/mockdata/AnalogInData.h
+++ b/hal/src/main/native/include/mockdata/AnalogInData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -25,6 +23,8 @@
 HAL_Bool HALSIM_GetAnalogInInitialized(int32_t index);
 void HALSIM_SetAnalogInInitialized(int32_t index, HAL_Bool initialized);
 
+HAL_SimDeviceHandle HALSIM_GetAnalogInSimDevice(int32_t index);
+
 int32_t HALSIM_RegisterAnalogInAverageBitsCallback(int32_t index,
                                                    HAL_NotifyCallback callback,
                                                    void* param,
@@ -97,5 +97,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/AnalogOutData.h b/hal/src/main/native/include/mockdata/AnalogOutData.h
index 48046ec..e8f55f6 100644
--- a/hal/src/main/native/include/mockdata/AnalogOutData.h
+++ b/hal/src/main/native/include/mockdata/AnalogOutData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -40,5 +38,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/AnalogTriggerData.h b/hal/src/main/native/include/mockdata/AnalogTriggerData.h
index 8146b8f..7f06c2e 100644
--- a/hal/src/main/native/include/mockdata/AnalogTriggerData.h
+++ b/hal/src/main/native/include/mockdata/AnalogTriggerData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -64,5 +62,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/CanData.h b/hal/src/main/native/include/mockdata/CanData.h
index 4d76dca..0d48290 100644
--- a/hal/src/main/native/include/mockdata/CanData.h
+++ b/hal/src/main/native/include/mockdata/CanData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,11 +7,9 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
-#include "HAL_Value.h"
 #include "NotifyListener.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 
 typedef void (*HAL_CAN_SendMessageCallback)(const char* name, void* param,
                                             uint32_t messageID,
@@ -74,5 +72,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/DIOData.h b/hal/src/main/native/include/mockdata/DIOData.h
index b3bd9f2..d13eee1 100644
--- a/hal/src/main/native/include/mockdata/DIOData.h
+++ b/hal/src/main/native/include/mockdata/DIOData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -25,6 +23,8 @@
 HAL_Bool HALSIM_GetDIOInitialized(int32_t index);
 void HALSIM_SetDIOInitialized(int32_t index, HAL_Bool initialized);
 
+HAL_SimDeviceHandle HALSIM_GetDIOSimDevice(int32_t index);
+
 int32_t HALSIM_RegisterDIOValueCallback(int32_t index,
                                         HAL_NotifyCallback callback,
                                         void* param, HAL_Bool initialNotify);
@@ -61,5 +61,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/DigitalPWMData.h b/hal/src/main/native/include/mockdata/DigitalPWMData.h
index d35e313..5af17e3 100644
--- a/hal/src/main/native/include/mockdata/DigitalPWMData.h
+++ b/hal/src/main/native/include/mockdata/DigitalPWMData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -47,5 +45,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/DriverStationData.h b/hal/src/main/native/include/mockdata/DriverStationData.h
index 57ca4e0..1f69664 100644
--- a/hal/src/main/native/include/mockdata/DriverStationData.h
+++ b/hal/src/main/native/include/mockdata/DriverStationData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/DriverStationTypes.h"
 #include "hal/Types.h"
@@ -91,5 +89,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/EncoderData.h b/hal/src/main/native/include/mockdata/EncoderData.h
index bcd00a7..d5d12be 100644
--- a/hal/src/main/native/include/mockdata/EncoderData.h
+++ b/hal/src/main/native/include/mockdata/EncoderData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -17,7 +15,8 @@
 #endif
 
 void HALSIM_ResetEncoderData(int32_t index);
-int16_t HALSIM_GetDigitalChannelA(int32_t index);
+int32_t HALSIM_GetEncoderDigitalChannelA(int32_t index);
+int32_t HALSIM_GetEncoderDigitalChannelB(int32_t index);
 int32_t HALSIM_RegisterEncoderInitializedCallback(int32_t index,
                                                   HAL_NotifyCallback callback,
                                                   void* param,
@@ -26,6 +25,8 @@
 HAL_Bool HALSIM_GetEncoderInitialized(int32_t index);
 void HALSIM_SetEncoderInitialized(int32_t index, HAL_Bool initialized);
 
+HAL_SimDeviceHandle HALSIM_GetEncoderSimDevice(int32_t index);
+
 int32_t HALSIM_RegisterEncoderCountCallback(int32_t index,
                                             HAL_NotifyCallback callback,
                                             void* param,
@@ -95,5 +96,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/I2CData.h b/hal/src/main/native/include/mockdata/I2CData.h
index 8565fdb..32ae3a8 100644
--- a/hal/src/main/native/include/mockdata/I2CData.h
+++ b/hal/src/main/native/include/mockdata/I2CData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -39,5 +37,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/MockHooks.h b/hal/src/main/native/include/mockdata/MockHooks.h
index 37eb0e7..02401b0 100644
--- a/hal/src/main/native/include/mockdata/MockHooks.h
+++ b/hal/src/main/native/include/mockdata/MockHooks.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "hal/Types.h"
 
 extern "C" {
@@ -16,6 +14,10 @@
 void HALSIM_SetProgramStarted(void);
 HAL_Bool HALSIM_GetProgramStarted(void);
 void HALSIM_RestartTiming(void);
-}  // extern "C"
 
-#endif
+typedef int32_t (*HALSIM_SendErrorHandler)(
+    HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode, const char* details,
+    const char* location, const char* callStack, HAL_Bool printMsg);
+void HALSIM_SetSendError(HALSIM_SendErrorHandler handler);
+
+}  // extern "C"
diff --git a/hal/src/main/native/include/mockdata/NotifyListener.h b/hal/src/main/native/include/mockdata/NotifyListener.h
index 8d7e199..a455803 100644
--- a/hal/src/main/native/include/mockdata/NotifyListener.h
+++ b/hal/src/main/native/include/mockdata/NotifyListener.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,9 +7,7 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
-#include "HAL_Value.h"
+#include "hal/Value.h"
 
 typedef void (*HAL_NotifyCallback)(const char* name, void* param,
                                    const struct HAL_Value* value);
@@ -21,6 +19,8 @@
                                         const unsigned char* buffer,
                                         unsigned int count);
 
+#ifdef __cplusplus
+
 namespace hal {
 
 template <typename CallbackFunction>
diff --git a/hal/src/main/native/include/mockdata/PCMData.h b/hal/src/main/native/include/mockdata/PCMData.h
index d919cc9..74a591a 100644
--- a/hal/src/main/native/include/mockdata/PCMData.h
+++ b/hal/src/main/native/include/mockdata/PCMData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -89,5 +87,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/PDPData.h b/hal/src/main/native/include/mockdata/PDPData.h
index be24da8..a25b66d 100644
--- a/hal/src/main/native/include/mockdata/PDPData.h
+++ b/hal/src/main/native/include/mockdata/PDPData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -56,5 +54,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/PWMData.h b/hal/src/main/native/include/mockdata/PWMData.h
index 08ba357..2a8c63d 100644
--- a/hal/src/main/native/include/mockdata/PWMData.h
+++ b/hal/src/main/native/include/mockdata/PWMData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -68,5 +66,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/RelayData.h b/hal/src/main/native/include/mockdata/RelayData.h
index 6fdac7f..c0b853d 100644
--- a/hal/src/main/native/include/mockdata/RelayData.h
+++ b/hal/src/main/native/include/mockdata/RelayData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -56,5 +54,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/RoboRioData.h b/hal/src/main/native/include/mockdata/RoboRioData.h
index 88b6ece..3acb0ec 100644
--- a/hal/src/main/native/include/mockdata/RoboRioData.h
+++ b/hal/src/main/native/include/mockdata/RoboRioData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -142,5 +140,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/SPIAccelerometerData.h b/hal/src/main/native/include/mockdata/SPIAccelerometerData.h
index 6e37f40..c68da45 100644
--- a/hal/src/main/native/include/mockdata/SPIAccelerometerData.h
+++ b/hal/src/main/native/include/mockdata/SPIAccelerometerData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -63,5 +61,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/SPIData.h b/hal/src/main/native/include/mockdata/SPIData.h
index 54a2ec9..da21643 100644
--- a/hal/src/main/native/include/mockdata/SPIData.h
+++ b/hal/src/main/native/include/mockdata/SPIData.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "NotifyListener.h"
 #include "hal/Types.h"
 
@@ -49,5 +47,3 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-
-#endif
diff --git a/hal/src/main/native/include/mockdata/SimCallbackRegistry.h b/hal/src/main/native/include/mockdata/SimCallbackRegistry.h
index da3f0f9..7190dcf 100644
--- a/hal/src/main/native/include/mockdata/SimCallbackRegistry.h
+++ b/hal/src/main/native/include/mockdata/SimCallbackRegistry.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -29,12 +29,12 @@
 
  public:
   void Cancel(int32_t uid) {
-    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    std::scoped_lock lock(m_mutex);
     if (m_callbacks) m_callbacks->erase(uid - 1);
   }
 
   void Reset() {
-    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    std::scoped_lock lock(m_mutex);
     DoReset();
   }
 
@@ -68,13 +68,13 @@
 class SimCallbackRegistry : public impl::SimCallbackRegistryBase {
  public:
   int32_t Register(CallbackFunction callback, void* param) {
-    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    std::scoped_lock lock(m_mutex);
     return DoRegister(reinterpret_cast<RawFunctor>(callback), param);
   }
 
   template <typename... U>
   void Invoke(U&&... u) const {
-    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    std::scoped_lock lock(m_mutex);
     if (m_callbacks) {
       const char* name = GetName();
       for (auto&& cb : *m_callbacks)
diff --git a/hal/src/main/native/include/mockdata/SimDataValue.h b/hal/src/main/native/include/mockdata/SimDataValue.h
index 3b518b9..b6723bb 100644
--- a/hal/src/main/native/include/mockdata/SimDataValue.h
+++ b/hal/src/main/native/include/mockdata/SimDataValue.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -27,14 +27,14 @@
   LLVM_ATTRIBUTE_ALWAYS_INLINE void CancelCallback(int32_t uid) { Cancel(uid); }
 
   T Get() const {
-    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    std::scoped_lock lock(m_mutex);
     return m_value;
   }
 
   LLVM_ATTRIBUTE_ALWAYS_INLINE operator T() const { return Get(); }
 
   void Reset(T value) {
-    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    std::scoped_lock lock(m_mutex);
     DoReset();
     m_value = value;
   }
@@ -44,7 +44,7 @@
  protected:
   int32_t DoRegisterCallback(HAL_NotifyCallback callback, void* param,
                              HAL_Bool initialNotify, const char* name) {
-    std::unique_lock<wpi::recursive_spinlock> lock(m_mutex);
+    std::unique_lock lock(m_mutex);
     int32_t newUid = DoRegister(reinterpret_cast<RawFunctor>(callback), param);
     if (newUid == -1) return -1;
     if (initialNotify) {
@@ -57,7 +57,7 @@
   }
 
   void DoSet(T value, const char* name) {
-    std::lock_guard<wpi::recursive_spinlock> lock(this->m_mutex);
+    std::scoped_lock lock(this->m_mutex);
     if (m_value != value) {
       m_value = value;
       if (m_callbacks) {
diff --git a/hal/src/main/native/include/mockdata/SimDeviceData.h b/hal/src/main/native/include/mockdata/SimDeviceData.h
new file mode 100644
index 0000000..44398d7
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/SimDeviceData.h
@@ -0,0 +1,73 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+#include "hal/Value.h"
+
+typedef void (*HALSIM_SimDeviceCallback)(const char* name, void* param,
+                                         HAL_SimDeviceHandle handle);
+
+typedef void (*HALSIM_SimValueCallback)(const char* name, void* param,
+                                        HAL_SimValueHandle handle,
+                                        HAL_Bool readonly,
+                                        const struct HAL_Value* value);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int32_t HALSIM_RegisterSimDeviceCreatedCallback(
+    const char* prefix, void* param, HALSIM_SimDeviceCallback callback,
+    HAL_Bool initialNotify);
+
+void HALSIM_CancelSimDeviceCreatedCallback(int32_t uid);
+
+int32_t HALSIM_RegisterSimDeviceFreedCallback(
+    const char* prefix, void* param, HALSIM_SimDeviceCallback callback);
+
+void HALSIM_CancelSimDeviceFreedCallback(int32_t uid);
+
+HAL_SimDeviceHandle HALSIM_GetSimDeviceHandle(const char* name);
+
+const char* HALSIM_GetSimDeviceName(HAL_SimDeviceHandle handle);
+
+HAL_SimDeviceHandle HALSIM_GetSimValueDeviceHandle(HAL_SimValueHandle handle);
+
+void HALSIM_EnumerateSimDevices(const char* prefix, void* param,
+                                HALSIM_SimDeviceCallback callback);
+
+int32_t HALSIM_RegisterSimValueCreatedCallback(HAL_SimDeviceHandle device,
+                                               void* param,
+                                               HALSIM_SimValueCallback callback,
+                                               HAL_Bool initialNotify);
+
+void HALSIM_CancelSimValueCreatedCallback(int32_t uid);
+
+int32_t HALSIM_RegisterSimValueChangedCallback(HAL_SimValueHandle handle,
+                                               void* param,
+                                               HALSIM_SimValueCallback callback,
+                                               HAL_Bool initialNotify);
+
+void HALSIM_CancelSimValueChangedCallback(int32_t uid);
+
+HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device,
+                                            const char* name);
+
+void HALSIM_EnumerateSimValues(HAL_SimDeviceHandle device, void* param,
+                               HALSIM_SimValueCallback callback);
+
+const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
+                                           int32_t* numOptions);
+
+void HALSIM_ResetSimDeviceData(void);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/hal/src/main/native/include/simulation/AccelerometerSim.h b/hal/src/main/native/include/simulation/AccelerometerSim.h
index ea873c7..07860f0 100644
--- a/hal/src/main/native/include/simulation/AccelerometerSim.h
+++ b/hal/src/main/native/include/simulation/AccelerometerSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -99,4 +97,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/AnalogGyroSim.h b/hal/src/main/native/include/simulation/AnalogGyroSim.h
index b4c48ca..b2cdb85 100644
--- a/hal/src/main/native/include/simulation/AnalogGyroSim.h
+++ b/hal/src/main/native/include/simulation/AnalogGyroSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -71,4 +69,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/AnalogInSim.h b/hal/src/main/native/include/simulation/AnalogInSim.h
index a513c33..2a1bbea 100644
--- a/hal/src/main/native/include/simulation/AnalogInSim.h
+++ b/hal/src/main/native/include/simulation/AnalogInSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -177,4 +175,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/AnalogOutSim.h b/hal/src/main/native/include/simulation/AnalogOutSim.h
index 3617a66..6bb6e5a 100644
--- a/hal/src/main/native/include/simulation/AnalogOutSim.h
+++ b/hal/src/main/native/include/simulation/AnalogOutSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -60,4 +58,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/AnalogTriggerSim.h b/hal/src/main/native/include/simulation/AnalogTriggerSim.h
index 04faf05..2c41be1 100644
--- a/hal/src/main/native/include/simulation/AnalogTriggerSim.h
+++ b/hal/src/main/native/include/simulation/AnalogTriggerSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -81,4 +79,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/CallbackStore.h b/hal/src/main/native/include/simulation/CallbackStore.h
index 967e963..b2d4bdf 100644
--- a/hal/src/main/native/include/simulation/CallbackStore.h
+++ b/hal/src/main/native/include/simulation/CallbackStore.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,13 +7,11 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <functional>
 
 #include <wpi/StringRef.h>
 
-#include "mockdata/HAL_Value.h"
+#include "hal/Value.h"
 
 namespace frc {
 namespace sim {
@@ -89,5 +87,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-
-#endif
diff --git a/hal/src/main/native/include/simulation/DIOSim.h b/hal/src/main/native/include/simulation/DIOSim.h
index b4fe947..57079b9 100644
--- a/hal/src/main/native/include/simulation/DIOSim.h
+++ b/hal/src/main/native/include/simulation/DIOSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -99,4 +97,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/DigitalPWMSim.h b/hal/src/main/native/include/simulation/DigitalPWMSim.h
index ecfc56d..5f5769d 100644
--- a/hal/src/main/native/include/simulation/DigitalPWMSim.h
+++ b/hal/src/main/native/include/simulation/DigitalPWMSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -73,4 +71,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/DriverStationSim.h b/hal/src/main/native/include/simulation/DriverStationSim.h
index 55c38a9..e5071cc 100644
--- a/hal/src/main/native/include/simulation/DriverStationSim.h
+++ b/hal/src/main/native/include/simulation/DriverStationSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -109,4 +107,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/EncoderSim.h b/hal/src/main/native/include/simulation/EncoderSim.h
index 493f338..f80e8a8 100644
--- a/hal/src/main/native/include/simulation/EncoderSim.h
+++ b/hal/src/main/native/include/simulation/EncoderSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -163,4 +161,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/PCMSim.h b/hal/src/main/native/include/simulation/PCMSim.h
index bfefa6e..3f3ca9b 100644
--- a/hal/src/main/native/include/simulation/PCMSim.h
+++ b/hal/src/main/native/include/simulation/PCMSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -147,4 +145,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/PDPSim.h b/hal/src/main/native/include/simulation/PDPSim.h
index 7677ec2..e3ffd4b 100644
--- a/hal/src/main/native/include/simulation/PDPSim.h
+++ b/hal/src/main/native/include/simulation/PDPSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -88,4 +86,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/PWMSim.h b/hal/src/main/native/include/simulation/PWMSim.h
index b90b76f..7aba360 100644
--- a/hal/src/main/native/include/simulation/PWMSim.h
+++ b/hal/src/main/native/include/simulation/PWMSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -114,4 +112,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/RelaySim.h b/hal/src/main/native/include/simulation/RelaySim.h
index b21a047..6958a40 100644
--- a/hal/src/main/native/include/simulation/RelaySim.h
+++ b/hal/src/main/native/include/simulation/RelaySim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -88,4 +86,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/RoboRioSim.h b/hal/src/main/native/include/simulation/RoboRioSim.h
index 0d7c31c..9b020ae 100644
--- a/hal/src/main/native/include/simulation/RoboRioSim.h
+++ b/hal/src/main/native/include/simulation/RoboRioSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -273,4 +271,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/SPIAccelerometerSim.h b/hal/src/main/native/include/simulation/SPIAccelerometerSim.h
index 4369938..d7795ee 100644
--- a/hal/src/main/native/include/simulation/SPIAccelerometerSim.h
+++ b/hal/src/main/native/include/simulation/SPIAccelerometerSim.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include <memory>
 #include <utility>
 
@@ -95,4 +93,3 @@
 };
 }  // namespace sim
 }  // namespace frc
-#endif  // __FRC_ROBORIO__
diff --git a/hal/src/main/native/include/simulation/SimHooks.h b/hal/src/main/native/include/simulation/SimHooks.h
index 6f03952..537cef3 100644
--- a/hal/src/main/native/include/simulation/SimHooks.h
+++ b/hal/src/main/native/include/simulation/SimHooks.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,6 @@
 
 #pragma once
 
-#ifndef __FRC_ROBORIO__
-
 #include "mockdata/MockHooks.h"
 
 namespace frc {
@@ -24,5 +22,3 @@
 
 }  // namespace sim
 }  // namespace frc
-
-#endif
diff --git a/hal/src/main/native/sim/AnalogInput.cpp b/hal/src/main/native/sim/AnalogInput.cpp
index a0f44a7..dc56403 100644
--- a/hal/src/main/native/sim/AnalogInput.cpp
+++ b/hal/src/main/native/sim/AnalogInput.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -53,6 +53,7 @@
 
   SimAnalogInData[channel].initialized = true;
   SimAnalogInData[channel].accumulatorInitialized = false;
+  SimAnalogInData[channel].simDevice = 0;
 
   return handle;
 }
@@ -71,6 +72,13 @@
   return channel < kNumAnalogInputs && channel >= 0;
 }
 
+void HAL_SetAnalogInputSimDevice(HAL_AnalogInputHandle handle,
+                                 HAL_SimDeviceHandle device) {
+  auto port = analogInputHandles->Get(handle);
+  if (port == nullptr) return;
+  SimAnalogInData[port->channel].simDevice = device;
+}
+
 void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status) {
   // No op
 }
diff --git a/hal/src/main/native/sim/CANAPI.cpp b/hal/src/main/native/sim/CANAPI.cpp
index a54f06f..08b0989 100644
--- a/hal/src/main/native/sim/CANAPI.cpp
+++ b/hal/src/main/native/sim/CANAPI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -100,12 +100,12 @@
 void HAL_CleanCAN(HAL_CANHandle handle) {
   auto data = canHandles->Free(handle);
 
-  std::lock_guard<wpi::mutex> lock(data->mapMutex);
+  std::scoped_lock lock(data->mapMutex);
 
   for (auto&& i : data->periodicSends) {
     int32_t s = 0;
-    HAL_CAN_SendMessage(i.first, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING,
-                        &s);
+    auto id = CreateCANId(data.get(), i.first);
+    HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING, &s);
     i.second = -1;
   }
 }
@@ -124,7 +124,7 @@
   if (*status != 0) {
     return;
   }
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   can->periodicSends[apiId] = -1;
 }
 
@@ -143,10 +143,31 @@
   if (*status != 0) {
     return;
   }
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   can->periodicSends[apiId] = repeatMs;
 }
 
+void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
+                          int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  auto id = CreateCANId(can.get(), apiId);
+  id |= HAL_CAN_IS_FRAME_REMOTE;
+  uint8_t data[8];
+  std::memset(data, 0, sizeof(data));
+
+  HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::scoped_lock lock(can->mapMutex);
+  can->periodicSends[apiId] = -1;
+}
+
 void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
                                 int32_t* status) {
   auto can = canHandles->Get(handle);
@@ -162,7 +183,7 @@
   if (*status != 0) {
     return;
   }
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   can->periodicSends[apiId] = -1;
 }
 
@@ -181,7 +202,7 @@
   HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
 
   if (*status == 0) {
-    std::lock_guard<wpi::mutex> lock(can->mapMutex);
+    std::scoped_lock lock(can->mapMutex);
     auto& msg = can->receives[messageId];
     msg.length = dataSize;
     msg.lastTimeStamp = ts;
@@ -206,7 +227,7 @@
   uint32_t ts = 0;
   HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
 
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   if (*status == 0) {
     // fresh update
     auto& msg = can->receives[messageId];
@@ -243,7 +264,7 @@
   uint32_t ts = 0;
   HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
 
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   if (*status == 0) {
     // fresh update
     auto& msg = can->receives[messageId];
@@ -285,7 +306,7 @@
   uint32_t messageId = CreateCANId(can.get(), apiId);
 
   {
-    std::lock_guard<wpi::mutex> lock(can->mapMutex);
+    std::scoped_lock lock(can->mapMutex);
     auto i = can->receives.find(messageId);
     if (i != can->receives.end()) {
       // Found, check if new enough
@@ -305,7 +326,7 @@
   uint32_t ts = 0;
   HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
 
-  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  std::scoped_lock lock(can->mapMutex);
   if (*status == 0) {
     // fresh update
     auto& msg = can->receives[messageId];
diff --git a/hal/src/main/native/sim/DIO.cpp b/hal/src/main/native/sim/DIO.cpp
index e67b756..2158136 100644
--- a/hal/src/main/native/sim/DIO.cpp
+++ b/hal/src/main/native/sim/DIO.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -63,8 +63,8 @@
   port->channel = static_cast<uint8_t>(channel);
 
   SimDIOData[channel].initialized = true;
-
   SimDIOData[channel].isInput = input;
+  SimDIOData[channel].simDevice = 0;
 
   return handle;
 }
@@ -78,7 +78,13 @@
   // no status, so no need to check for a proper free.
   digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
   if (port == nullptr) return;
-  SimDIOData[port->channel].initialized = true;
+  SimDIOData[port->channel].initialized = false;
+}
+
+void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
+  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
+  if (port == nullptr) return;
+  SimDIOData[port->channel].simDevice = device;
 }
 
 HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
diff --git a/hal/src/main/native/sim/DigitalInternal.h b/hal/src/main/native/sim/DigitalInternal.h
index 89644a1..9df4c51 100644
--- a/hal/src/main/native/sim/DigitalInternal.h
+++ b/hal/src/main/native/sim/DigitalInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -44,11 +44,11 @@
  * scaling is implemented as an output squelch to get longer periods for old
  * devices.
  */
-constexpr float kDefaultPwmPeriod = 5.05;
+constexpr float kDefaultPwmPeriod = 5.05f;
 /**
  * kDefaultPwmCenter is the PWM range center in ms
  */
-constexpr float kDefaultPwmCenter = 1.5;
+constexpr float kDefaultPwmCenter = 1.5f;
 /**
  * kDefaultPWMStepsDown is the number of PWM steps below the centerpoint
  */
diff --git a/hal/src/main/native/sim/DriverStation.cpp b/hal/src/main/native/sim/DriverStation.cpp
index 0c9c028..a17994e 100644
--- a/hal/src/main/native/sim/DriverStation.cpp
+++ b/hal/src/main/native/sim/DriverStation.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -28,6 +28,7 @@
 static wpi::mutex newDSDataAvailableMutex;
 static int newDSDataAvailableCounter{0};
 static std::atomic_bool isFinalized{false};
+static std::atomic<HALSIM_SendErrorHandler> sendErrorHandler{nullptr};
 
 namespace hal {
 namespace init {
@@ -41,13 +42,22 @@
 using namespace hal;
 
 extern "C" {
+
+void HALSIM_SetSendError(HALSIM_SendErrorHandler handler) {
+  sendErrorHandler.store(handler);
+}
+
 int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
                       const char* details, const char* location,
                       const char* callStack, HAL_Bool printMsg) {
+  auto errorHandler = sendErrorHandler.load();
+  if (errorHandler)
+    return errorHandler(isError, errorCode, isLVCode, details, location,
+                        callStack, printMsg);
   // Avoid flooding console by keeping track of previous 5 error
   // messages and only printing again if they're longer than 1 second old.
   static constexpr int KEEP_MSGS = 5;
-  std::lock_guard<wpi::mutex> lock(msgMutex);
+  std::scoped_lock lock(msgMutex);
   static std::string prevMsg[KEEP_MSGS];
   static std::chrono::time_point<std::chrono::steady_clock>
       prevMsgTime[KEEP_MSGS];
@@ -219,7 +229,7 @@
   // worth the cycles to check.
   int currentCount = 0;
   {
-    std::unique_lock<wpi::mutex> lock(newDSDataAvailableMutex);
+    std::unique_lock lock(newDSDataAvailableMutex);
     currentCount = newDSDataAvailableCounter;
   }
   if (lastCount == currentCount) return false;
@@ -236,7 +246,7 @@
   auto timeoutTime =
       std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
 
-  std::unique_lock<wpi::mutex> lock(newDSDataAvailableMutex);
+  std::unique_lock lock(newDSDataAvailableMutex);
   int currentCount = newDSDataAvailableCounter;
   while (newDSDataAvailableCounter == currentCount) {
     if (timeout > 0) {
@@ -258,7 +268,7 @@
   // Since we could get other values, require our specific handle
   // to signal our threads
   if (refNum != refNumber) return 0;
-  std::lock_guard<wpi::mutex> lock(newDSDataAvailableMutex);
+  std::scoped_lock lock(newDSDataAvailableMutex);
   // Nofify all threads
   newDSDataAvailableCounter++;
   newDSDataAvailableCond->notify_all();
@@ -272,7 +282,7 @@
   // Initial check, as if it's true initialization has finished
   if (initialized) return;
 
-  std::lock_guard<wpi::mutex> lock(initializeMutex);
+  std::scoped_lock lock(initializeMutex);
   // Second check in case another thread was waiting
   if (initialized) return;
 
diff --git a/hal/src/main/native/sim/Encoder.cpp b/hal/src/main/native/sim/Encoder.cpp
index 3f197a2..36122bf 100644
--- a/hal/src/main/native/sim/Encoder.cpp
+++ b/hal/src/main/native/sim/Encoder.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -82,8 +82,10 @@
   }
   int16_t index = getHandleIndex(handle);
   SimEncoderData[index].digitalChannelA = getHandleIndex(digitalSourceHandleA);
+  SimEncoderData[index].digitalChannelB = getHandleIndex(digitalSourceHandleB);
   SimEncoderData[index].initialized = true;
   SimEncoderData[index].reverseDirection = reverseDirection;
+  SimEncoderData[index].simDevice = 0;
   // TODO: Add encoding type to Sim data
   encoder->index = index;
   encoder->nativeHandle = nativeHandle;
@@ -104,6 +106,13 @@
   SimEncoderData[encoder->index].initialized = false;
 }
 
+void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
+                             HAL_SimDeviceHandle device) {
+  auto encoder = encoderHandles->Get(handle);
+  if (encoder == nullptr) return;
+  SimEncoderData[encoder->index].simDevice = device;
+}
+
 static inline int EncodingScaleFactor(Encoder* encoder) {
   switch (encoder->encodingType) {
     case HAL_Encoder_k1X:
diff --git a/hal/src/main/native/sim/Extensions.cpp b/hal/src/main/native/sim/Extensions.cpp
index 6ef7903..e84c354 100644
--- a/hal/src/main/native/sim/Extensions.cpp
+++ b/hal/src/main/native/sim/Extensions.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,10 @@
 
 #include "hal/Extensions.h"
 
+#include <wpi/Path.h>
 #include <wpi/SmallString.h>
 #include <wpi/StringRef.h>
+#include <wpi/raw_ostream.h>
 
 #include "hal/HAL.h"
 
@@ -43,6 +45,9 @@
 
 int HAL_LoadOneExtension(const char* library) {
   int rc = 1;  // It is expected and reasonable not to find an extra simulation
+  wpi::outs() << "HAL Extensions: Attempting to load: "
+              << wpi::sys::path::stem(library) << "\n";
+  wpi::outs().flush();
   HTYPE handle = DLOPEN(library);
 #if !defined(WIN32) && !defined(_WIN32)
   if (!handle) {
@@ -53,17 +58,31 @@
 #else
     libraryName += ".so";
 #endif
+    wpi::outs() << "HAL Extensions: Trying modified name: "
+                << wpi::sys::path::stem(libraryName);
+    wpi::outs().flush();
     handle = DLOPEN(libraryName.c_str());
   }
 #endif
-  if (!handle) return rc;
+  if (!handle) {
+    wpi::outs() << "HAL Extensions: Failed to load library\n";
+    wpi::outs().flush();
+    return rc;
+  }
 
   auto init = reinterpret_cast<halsim_extension_init_func_t*>(
       DLSYM(handle, "HALSIM_InitExtension"));
 
   if (init) rc = (*init)();
 
-  if (rc != 0) DLCLOSE(handle);
+  if (rc != 0) {
+    wpi::outs() << "HAL Extensions: Failed to load extension\n";
+    wpi::outs().flush();
+    DLCLOSE(handle);
+  } else {
+    wpi::outs() << "HAL Extensions: Successfully loaded extension\n";
+    wpi::outs().flush();
+  }
   return rc;
 }
 
@@ -71,7 +90,11 @@
   int rc = 1;
   wpi::SmallVector<wpi::StringRef, 2> libraries;
   const char* e = std::getenv("HALSIM_EXTENSIONS");
-  if (!e) return rc;
+  if (!e) {
+    wpi::outs() << "HAL Extensions: No extensions found\n";
+    wpi::outs().flush();
+    return rc;
+  }
   wpi::StringRef env{e};
   env.split(libraries, DELIM, -1, false);
   for (auto& libref : libraries) {
diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp
index d058c1a..cf019cf 100644
--- a/hal/src/main/native/sim/HAL.cpp
+++ b/hal/src/main/native/sim/HAL.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -41,6 +41,7 @@
   InitializePWMData();
   InitializeRelayData();
   InitializeRoboRioData();
+  InitializeSimDeviceData();
   InitializeSPIAccelerometerData();
   InitializeSPIData();
   InitializeAccelerometer();
@@ -60,6 +61,7 @@
   InitializeExtensions();
   InitializeI2C();
   InitializeInterrupts();
+  InitializeMain();
   InitializeMockHooks();
   InitializeNotifier();
   InitializePDP();
@@ -68,6 +70,7 @@
   InitializePWM();
   InitializeRelay();
   InitializeSerialPort();
+  InitializeSimDevice();
   InitializeSolenoid();
   InitializeSPI();
   InitializeThreads();
@@ -231,7 +234,7 @@
   // Initial check, as if it's true initialization has finished
   if (initialized) return true;
 
-  std::lock_guard<wpi::mutex> lock(initializeMutex);
+  std::scoped_lock lock(initializeMutex);
   // Second check in case another thread was waiting
   if (initialized) return true;
 
diff --git a/hal/src/main/native/sim/HALInitializer.h b/hal/src/main/native/sim/HALInitializer.h
index d369a3b..4c91b40 100644
--- a/hal/src/main/native/sim/HALInitializer.h
+++ b/hal/src/main/native/sim/HALInitializer.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -35,6 +35,7 @@
 extern void InitializePWMData();
 extern void InitializeRelayData();
 extern void InitializeRoboRioData();
+extern void InitializeSimDeviceData();
 extern void InitializeSPIAccelerometerData();
 extern void InitializeSPIData();
 extern void InitializeAccelerometer();
@@ -55,6 +56,7 @@
 extern void InitializeHAL();
 extern void InitializeI2C();
 extern void InitializeInterrupts();
+extern void InitializeMain();
 extern void InitializeMockHooks();
 extern void InitializeNotifier();
 extern void InitializePDP();
@@ -63,6 +65,7 @@
 extern void InitializePWM();
 extern void InitializeRelay();
 extern void InitializeSerialPort();
+extern void InitializeSimDevice();
 extern void InitializeSolenoid();
 extern void InitializeSPI();
 extern void InitializeThreads();
diff --git a/hal/src/main/native/sim/Interrupts.cpp b/hal/src/main/native/sim/Interrupts.cpp
index 75247ca..a7dd285 100644
--- a/hal/src/main/native/sim/Interrupts.cpp
+++ b/hal/src/main/native/sim/Interrupts.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -19,12 +19,16 @@
 #include "PortsInternal.h"
 #include "hal/AnalogTrigger.h"
 #include "hal/Errors.h"
+#include "hal/Value.h"
 #include "hal/handles/HandlesInternal.h"
 #include "hal/handles/LimitedHandleResource.h"
 #include "hal/handles/UnlimitedHandleResource.h"
 #include "mockdata/AnalogInDataInternal.h"
 #include "mockdata/DIODataInternal.h"
-#include "mockdata/HAL_Value.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4996 4018 6297 26451 4334)
+#endif
 
 using namespace hal;
 
@@ -54,9 +58,9 @@
 };
 
 struct SynchronousWaitData {
-  HAL_InterruptHandle interruptHandle;
+  HAL_InterruptHandle interruptHandle{HAL_kInvalidHandle};
   wpi::condition_variable waitCond;
-  HAL_Bool waitPredicate;
+  HAL_Bool waitPredicate{false};
 };
 }  // namespace
 
@@ -219,7 +223,7 @@
       std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
 
   {
-    std::unique_lock<wpi::mutex> lock(waitMutex);
+    std::unique_lock lock(waitMutex);
     while (!data->waitPredicate) {
       if (data->waitCond.wait_until(lock, timeoutTime) ==
           std::cv_status::timeout) {
@@ -231,7 +235,7 @@
 
   // Cancel our callback
   SimDIOData[digitalIndex].value.CancelCallback(uid);
-  synchronousInterruptHandles->Free(dataHandle);
+  (void)synchronousInterruptHandles->Free(dataHandle);
 
   // Check for what to return
   if (timedOut) return WaitResult::Timeout;
@@ -283,7 +287,7 @@
       std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
 
   {
-    std::unique_lock<wpi::mutex> lock(waitMutex);
+    std::unique_lock lock(waitMutex);
     while (!data->waitPredicate) {
       if (data->waitCond.wait_until(lock, timeoutTime) ==
           std::cv_status::timeout) {
@@ -295,7 +299,7 @@
 
   // Cancel our callback
   SimAnalogInData[analogIndex].voltage.CancelCallback(uid);
-  synchronousInterruptHandles->Free(dataHandle);
+  (void)synchronousInterruptHandles->Free(dataHandle);
 
   // Check for what to return
   if (timedOut) return WaitResult::Timeout;
diff --git a/hal/src/main/native/sim/Notifier.cpp b/hal/src/main/native/sim/Notifier.cpp
index 9f549d5..579540c 100644
--- a/hal/src/main/native/sim/Notifier.cpp
+++ b/hal/src/main/native/sim/Notifier.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -38,7 +38,7 @@
   ~NotifierHandleContainer() {
     ForEach([](HAL_NotifierHandle handle, Notifier* notifier) {
       {
-        std::lock_guard<wpi::mutex> lock(notifier->mutex);
+        std::scoped_lock lock(notifier->mutex);
         notifier->active = false;
         notifier->running = false;
       }
@@ -76,7 +76,7 @@
   if (!notifier) return;
 
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->active = false;
     notifier->running = false;
   }
@@ -89,7 +89,7 @@
 
   // Just in case HAL_StopNotifier() wasn't called...
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->active = false;
     notifier->running = false;
   }
@@ -102,7 +102,7 @@
   if (!notifier) return;
 
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->waitTime = triggerTime;
     notifier->running = true;
     notifier->updatedAlarm = true;
@@ -118,7 +118,7 @@
   if (!notifier) return;
 
   {
-    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    std::scoped_lock lock(notifier->mutex);
     notifier->running = false;
   }
 }
@@ -128,7 +128,7 @@
   auto notifier = notifierHandles->Get(notifierHandle);
   if (!notifier) return 0;
 
-  std::unique_lock<wpi::mutex> lock(notifier->mutex);
+  std::unique_lock lock(notifier->mutex);
   while (notifier->active) {
     double waitTime;
     if (!notifier->running) {
diff --git a/hal/src/main/native/sim/SerialPort.cpp b/hal/src/main/native/sim/SerialPort.cpp
index bc08566..2df2ebe 100644
--- a/hal/src/main/native/sim/SerialPort.cpp
+++ b/hal/src/main/native/sim/SerialPort.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -16,62 +16,72 @@
 }  // namespace hal
 
 extern "C" {
-void HAL_InitializeSerialPort(HAL_SerialPort port, int32_t* status) {
+HAL_SerialPortHandle HAL_InitializeSerialPort(HAL_SerialPort port,
+                                              int32_t* status) {
   hal::init::CheckInit();
+  return HAL_kInvalidHandle;
 }
 
-void HAL_InitializeSerialPortDirect(HAL_SerialPort port, const char* portName,
-                                    int32_t* status) {}
-
-void HAL_SetSerialBaudRate(HAL_SerialPort port, int32_t baud, int32_t* status) {
+HAL_SerialPortHandle HAL_InitializeSerialPortDirect(HAL_SerialPort port,
+                                                    const char* portName,
+                                                    int32_t* status) {
+  hal::init::CheckInit();
+  return HAL_kInvalidHandle;
 }
 
-void HAL_SetSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status) {
-}
+int HAL_GetSerialFD(HAL_SerialPortHandle handle, int32_t* status) { return -1; }
 
-void HAL_SetSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status) {
-}
-
-void HAL_SetSerialStopBits(HAL_SerialPort port, int32_t stopBits,
+void HAL_SetSerialBaudRate(HAL_SerialPortHandle handle, int32_t baud,
                            int32_t* status) {}
 
-void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode,
+void HAL_SetSerialDataBits(HAL_SerialPortHandle handle, int32_t bits,
+                           int32_t* status) {}
+
+void HAL_SetSerialParity(HAL_SerialPortHandle handle, int32_t parity,
+                         int32_t* status) {}
+
+void HAL_SetSerialStopBits(HAL_SerialPortHandle handle, int32_t stopBits,
+                           int32_t* status) {}
+
+void HAL_SetSerialWriteMode(HAL_SerialPortHandle handle, int32_t mode,
                             int32_t* status) {}
 
-void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
+void HAL_SetSerialFlowControl(HAL_SerialPortHandle handle, int32_t flow,
                               int32_t* status) {}
 
-void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout,
+void HAL_SetSerialTimeout(HAL_SerialPortHandle handle, double timeout,
                           int32_t* status) {}
 
-void HAL_EnableSerialTermination(HAL_SerialPort port, char terminator,
+void HAL_EnableSerialTermination(HAL_SerialPortHandle handle, char terminator,
                                  int32_t* status) {}
 
-void HAL_DisableSerialTermination(HAL_SerialPort port, int32_t* status) {}
-
-void HAL_SetSerialReadBufferSize(HAL_SerialPort port, int32_t size,
-                                 int32_t* status) {}
-
-void HAL_SetSerialWriteBufferSize(HAL_SerialPort port, int32_t size,
+void HAL_DisableSerialTermination(HAL_SerialPortHandle handle,
                                   int32_t* status) {}
 
-int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status) {
+void HAL_SetSerialReadBufferSize(HAL_SerialPortHandle handle, int32_t size,
+                                 int32_t* status) {}
+
+void HAL_SetSerialWriteBufferSize(HAL_SerialPortHandle handle, int32_t size,
+                                  int32_t* status) {}
+
+int32_t HAL_GetSerialBytesReceived(HAL_SerialPortHandle handle,
+                                   int32_t* status) {
   return 0;
 }
 
-int32_t HAL_ReadSerial(HAL_SerialPort port, char* buffer, int32_t count,
+int32_t HAL_ReadSerial(HAL_SerialPortHandle handle, char* buffer, int32_t count,
                        int32_t* status) {
   return 0;
 }
 
-int32_t HAL_WriteSerial(HAL_SerialPort port, const char* buffer, int32_t count,
-                        int32_t* status) {
+int32_t HAL_WriteSerial(HAL_SerialPortHandle handle, const char* buffer,
+                        int32_t count, int32_t* status) {
   return 0;
 }
 
-void HAL_FlushSerial(HAL_SerialPort port, int32_t* status) {}
+void HAL_FlushSerial(HAL_SerialPortHandle handle, int32_t* status) {}
 
-void HAL_ClearSerial(HAL_SerialPort port, int32_t* status) {}
+void HAL_ClearSerial(HAL_SerialPortHandle handle, int32_t* status) {}
 
-void HAL_CloseSerial(HAL_SerialPort port, int32_t* status) {}
+void HAL_CloseSerial(HAL_SerialPortHandle handle, int32_t* status) {}
 }  // extern "C"
diff --git a/hal/src/main/native/sim/SimDevice.cpp b/hal/src/main/native/sim/SimDevice.cpp
new file mode 100644
index 0000000..a8f8f80
--- /dev/null
+++ b/hal/src/main/native/sim/SimDevice.cpp
@@ -0,0 +1,75 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/SimDevice.h"
+
+#include <wpi/SmallString.h>
+#include <wpi/raw_ostream.h>
+
+#include "HALInitializer.h"
+#include "mockdata/SimDeviceDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeSimDevice() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name) {
+  hal::init::CheckInit();
+  return SimSimDeviceData->CreateDevice(name);
+}
+
+void HAL_FreeSimDevice(HAL_SimDeviceHandle handle) {
+  SimSimDeviceData->FreeDevice(handle);
+}
+
+HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
+                                      const char* name, HAL_Bool readonly,
+                                      const struct HAL_Value* initialValue) {
+  return SimSimDeviceData->CreateValue(device, name, readonly, 0, nullptr,
+                                       *initialValue);
+}
+
+HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
+                                          const char* name, HAL_Bool readonly,
+                                          int32_t numOptions,
+                                          const char** options,
+                                          int32_t initialValue) {
+  return SimSimDeviceData->CreateValue(device, name, readonly, numOptions,
+                                       options, HAL_MakeEnum(initialValue));
+}
+
+void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
+  *value = SimSimDeviceData->GetValue(handle);
+}
+
+void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value) {
+  SimSimDeviceData->SetValue(handle, *value);
+}
+
+hal::SimDevice::SimDevice(const char* name, int index) {
+  wpi::SmallString<128> fullname;
+  wpi::raw_svector_ostream os(fullname);
+  os << name << '[' << index << ']';
+
+  m_handle = HAL_CreateSimDevice(fullname.c_str());
+}
+
+hal::SimDevice::SimDevice(const char* name, int index, int channel) {
+  wpi::SmallString<128> fullname;
+  wpi::raw_svector_ostream os(fullname);
+  os << name << '[' << index << ',' << channel << ']';
+
+  m_handle = HAL_CreateSimDevice(fullname.c_str());
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/BufferCallbackStore.cpp b/hal/src/main/native/sim/jni/BufferCallbackStore.cpp
index fbf3adc..3c9941e 100644
--- a/hal/src/main/native/sim/jni/BufferCallbackStore.cpp
+++ b/hal/src/main/native/sim/jni/BufferCallbackStore.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 
 using namespace wpi::java;
diff --git a/hal/src/main/native/sim/jni/BufferCallbackStore.h b/hal/src/main/native/sim/jni/BufferCallbackStore.h
index b9d49ac..6b472ac 100644
--- a/hal/src/main/native/sim/jni/BufferCallbackStore.h
+++ b/hal/src/main/native/sim/jni/BufferCallbackStore.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 
 namespace sim {
diff --git a/hal/src/main/native/sim/jni/CallbackStore.cpp b/hal/src/main/native/sim/jni/CallbackStore.cpp
index abef9b0..318ab1e 100644
--- a/hal/src/main/native/sim/jni/CallbackStore.cpp
+++ b/hal/src/main/native/sim/jni/CallbackStore.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 
 using namespace wpi::java;
diff --git a/hal/src/main/native/sim/jni/CallbackStore.h b/hal/src/main/native/sim/jni/CallbackStore.h
index 94454b0..eacf314 100644
--- a/hal/src/main/native/sim/jni/CallbackStore.h
+++ b/hal/src/main/native/sim/jni/CallbackStore.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 
 namespace sim {
diff --git a/hal/src/main/native/sim/jni/ConstBufferCallbackStore.cpp b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.cpp
index 781725b..d681983 100644
--- a/hal/src/main/native/sim/jni/ConstBufferCallbackStore.cpp
+++ b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 
 using namespace wpi::java;
diff --git a/hal/src/main/native/sim/jni/ConstBufferCallbackStore.h b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.h
index 1b0f54e..2164a74 100644
--- a/hal/src/main/native/sim/jni/ConstBufferCallbackStore.h
+++ b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 
 namespace sim {
diff --git a/hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp b/hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp
new file mode 100644
index 0000000..f6cd05e
--- /dev/null
+++ b/hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp
@@ -0,0 +1,573 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "SimDeviceDataJNI.h"
+
+#include <jni.h>
+
+#include <functional>
+#include <string>
+#include <utility>
+
+#include <wpi/UidVector.h>
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI.h"
+#include "mockdata/SimDeviceData.h"
+
+using namespace wpi::java;
+
+static JClass simDeviceInfoCls;
+static JClass simValueInfoCls;
+static JClass simDeviceCallbackCls;
+static JClass simValueCallbackCls;
+static jmethodID simDeviceCallbackCallback;
+static jmethodID simValueCallbackCallback;
+
+namespace {
+
+struct DeviceInfo {
+  DeviceInfo(const char* name_, HAL_SimDeviceHandle handle_)
+      : name{name_}, handle{handle_} {}
+  std::string name;
+  HAL_SimValueHandle handle;
+
+  jobject MakeJava(JNIEnv* env) const;
+  void CallJava(JNIEnv* env, jobject callobj) const;
+};
+
+struct ValueInfo {
+  ValueInfo(const char* name_, HAL_SimValueHandle handle_, bool readonly_,
+            const HAL_Value& value_)
+      : name{name_}, handle{handle_}, readonly{readonly_}, value{value_} {}
+  std::string name;
+  HAL_SimValueHandle handle;
+  bool readonly;
+  HAL_Value value;
+
+  jobject MakeJava(JNIEnv* env) const;
+  void CallJava(JNIEnv* env, jobject callobj) const;
+
+ private:
+  std::pair<jlong, jdouble> ToValue12() const;
+};
+
+}  // namespace
+
+jobject DeviceInfo::MakeJava(JNIEnv* env) const {
+  static jmethodID func =
+      env->GetMethodID(simDeviceInfoCls, "<init>", "(Ljava/lang/String;I)V");
+  return env->NewObject(simDeviceInfoCls, func, MakeJString(env, name),
+                        (jint)handle);
+}
+
+void DeviceInfo::CallJava(JNIEnv* env, jobject callobj) const {
+  env->CallVoidMethod(callobj, simDeviceCallbackCallback,
+                      MakeJString(env, name), (jint)handle);
+}
+
+std::pair<jlong, jdouble> ValueInfo::ToValue12() const {
+  jlong value1 = 0;
+  jdouble value2 = 0.0;
+  switch (value.type) {
+    case HAL_BOOLEAN:
+      value1 = value.data.v_boolean;
+      break;
+    case HAL_DOUBLE:
+      value2 = value.data.v_double;
+      break;
+    case HAL_ENUM:
+      value1 = value.data.v_enum;
+      break;
+    case HAL_INT:
+      value1 = value.data.v_int;
+      break;
+    case HAL_LONG:
+      value1 = value.data.v_long;
+      break;
+    default:
+      break;
+  }
+  return std::pair(value1, value2);
+}
+
+jobject ValueInfo::MakeJava(JNIEnv* env) const {
+  static jmethodID func =
+      env->GetMethodID(simValueInfoCls, "<init>", "(Ljava/lang/String;IZIJD)V");
+  auto [value1, value2] = ToValue12();
+  return env->NewObject(simValueInfoCls, func, MakeJString(env, name),
+                        (jint)handle, (jboolean)readonly, (jint)value.type,
+                        value1, value2);
+}
+
+void ValueInfo::CallJava(JNIEnv* env, jobject callobj) const {
+  auto [value1, value2] = ToValue12();
+  env->CallVoidMethod(callobj, simValueCallbackCallback, MakeJString(env, name),
+                      (jint)handle, (jboolean)readonly, (jint)value.type,
+                      value1, value2);
+}
+
+namespace {
+
+class CallbackStore {
+ public:
+  explicit CallbackStore(JNIEnv* env, jobject obj) : m_call{env, obj} {}
+  ~CallbackStore() {
+    if (m_cancelCallback) m_cancelCallback();
+  }
+
+  void SetCancel(std::function<void()> cancelCallback) {
+    m_cancelCallback = std::move(cancelCallback);
+  }
+  void Free(JNIEnv* env) { m_call.free(env); }
+  jobject Get() const { return m_call; }
+
+ private:
+  wpi::java::JGlobal<jobject> m_call;
+  std::function<void()> m_cancelCallback;
+};
+
+class CallbackThreadJNI : public wpi::SafeThread {
+ public:
+  void Main();
+
+  using DeviceCalls =
+      std::vector<std::pair<std::weak_ptr<CallbackStore>, DeviceInfo>>;
+  DeviceCalls m_deviceCalls;
+  using ValueCalls =
+      std::vector<std::pair<std::weak_ptr<CallbackStore>, ValueInfo>>;
+  ValueCalls m_valueCalls;
+
+  wpi::UidVector<std::shared_ptr<CallbackStore>, 4> m_callbacks;
+};
+
+class CallbackJNI {
+ public:
+  static CallbackJNI& GetInstance() {
+    static CallbackJNI inst;
+    return inst;
+  }
+  void SendDevice(int32_t callback, DeviceInfo info);
+  void SendValue(int32_t callback, ValueInfo info);
+
+  std::pair<int32_t, std::shared_ptr<CallbackStore>> AllocateCallback(
+      JNIEnv* env, jobject obj);
+
+  void FreeCallback(JNIEnv* env, int32_t uid);
+
+ private:
+  CallbackJNI() { m_owner.Start(); }
+
+  wpi::SafeThreadOwner<CallbackThreadJNI> m_owner;
+};
+
+}  // namespace
+
+void CallbackThreadJNI::Main() {
+  JNIEnv* env;
+  JavaVMAttachArgs args;
+  args.version = JNI_VERSION_1_2;
+  args.name = const_cast<char*>("SimDeviceCallback");
+  args.group = nullptr;
+  jint rs = sim::GetJVM()->AttachCurrentThreadAsDaemon(
+      reinterpret_cast<void**>(&env), &args);
+  if (rs != JNI_OK) return;
+
+  DeviceCalls deviceCalls;
+  ValueCalls valueCalls;
+
+  std::unique_lock lock(m_mutex);
+  while (m_active) {
+    m_cond.wait(lock, [&] { return !m_active; });
+    if (!m_active) break;
+
+    deviceCalls.swap(m_deviceCalls);
+    valueCalls.swap(m_valueCalls);
+
+    lock.unlock();  // don't hold mutex during callback execution
+
+    for (auto&& call : deviceCalls) {
+      if (auto store = call.first.lock()) {
+        if (jobject callobj = store->Get()) {
+          call.second.CallJava(env, callobj);
+          if (env->ExceptionCheck()) {
+            env->ExceptionDescribe();
+            env->ExceptionClear();
+          }
+        }
+      }
+    }
+
+    for (auto&& call : valueCalls) {
+      if (auto store = call.first.lock()) {
+        if (jobject callobj = store->Get()) {
+          call.second.CallJava(env, callobj);
+          if (env->ExceptionCheck()) {
+            env->ExceptionDescribe();
+            env->ExceptionClear();
+          }
+        }
+      }
+    }
+
+    deviceCalls.clear();
+    valueCalls.clear();
+
+    lock.lock();
+  }
+
+  // free global references
+  for (auto&& callback : m_callbacks) callback->Free(env);
+
+  sim::GetJVM()->DetachCurrentThread();
+}
+
+void CallbackJNI::SendDevice(int32_t callback, DeviceInfo info) {
+  auto thr = m_owner.GetThread();
+  if (!thr) return;
+  thr->m_deviceCalls.emplace_back(thr->m_callbacks[callback], std::move(info));
+  thr->m_cond.notify_one();
+}
+
+void CallbackJNI::SendValue(int32_t callback, ValueInfo info) {
+  auto thr = m_owner.GetThread();
+  if (!thr) return;
+  thr->m_valueCalls.emplace_back(thr->m_callbacks[callback], std::move(info));
+  thr->m_cond.notify_one();
+}
+
+std::pair<int32_t, std::shared_ptr<CallbackStore>>
+CallbackJNI::AllocateCallback(JNIEnv* env, jobject obj) {
+  auto thr = m_owner.GetThread();
+  if (!thr) return std::pair(0, nullptr);
+  auto store = std::make_shared<CallbackStore>(env, obj);
+  return std::pair(thr->m_callbacks.emplace_back(store) + 1, store);
+}
+
+void CallbackJNI::FreeCallback(JNIEnv* env, int32_t uid) {
+  auto thr = m_owner.GetThread();
+  if (!thr) return;
+  if (uid <= 0 || static_cast<uint32_t>(uid) >= thr->m_callbacks.size()) return;
+  --uid;
+  auto store = std::move(thr->m_callbacks[uid]);
+  thr->m_callbacks.erase(uid);
+  store->Free(env);
+}
+
+namespace sim {
+
+bool InitializeSimDeviceDataJNI(JNIEnv* env) {
+  simDeviceInfoCls = JClass(
+      env, "edu/wpi/first/hal/sim/mockdata/SimDeviceDataJNI$SimDeviceInfo");
+  if (!simDeviceInfoCls) return false;
+
+  simValueInfoCls = JClass(
+      env, "edu/wpi/first/hal/sim/mockdata/SimDeviceDataJNI$SimValueInfo");
+  if (!simValueInfoCls) return false;
+
+  simDeviceCallbackCls = JClass(env, "edu/wpi/first/hal/sim/SimDeviceCallback");
+  if (!simDeviceCallbackCls) return false;
+
+  simDeviceCallbackCallback = env->GetMethodID(simDeviceCallbackCls, "callback",
+                                               "(Ljava/lang/String;I)V");
+  if (!simDeviceCallbackCallback) return false;
+
+  simValueCallbackCls = JClass(env, "edu/wpi/first/hal/sim/SimValueCallback");
+  if (!simValueCallbackCls) return false;
+
+  simValueCallbackCallback = env->GetMethodID(
+      simValueCallbackCls, "callbackNative", "(Ljava/lang/String;IZIJD)V");
+  if (!simValueCallbackCallback) return false;
+
+  return true;
+}
+
+void FreeSimDeviceDataJNI(JNIEnv* env) {
+  simDeviceInfoCls.free(env);
+  simValueInfoCls.free(env);
+  simDeviceCallbackCls.free(env);
+  simValueCallbackCls.free(env);
+}
+
+}  // namespace sim
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    registerSimDeviceCreatedCallback
+ * Signature: (Ljava/lang/String;Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimDeviceCreatedCallback
+  (JNIEnv* env, jclass, jstring prefix, jobject callback,
+   jboolean initialNotify)
+{
+  auto [uid, store] =
+      CallbackJNI::GetInstance().AllocateCallback(env, callback);
+  int32_t cuid = HALSIM_RegisterSimDeviceCreatedCallback(
+      JStringRef{env, prefix}.c_str(),
+      reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
+      [](const char* name, void* param, HAL_SimDeviceHandle handle) {
+        int32_t uid = reinterpret_cast<intptr_t>(param);
+        CallbackJNI::GetInstance().SendDevice(uid, DeviceInfo{name, handle});
+      },
+      initialNotify);
+  store->SetCancel([cuid] { HALSIM_CancelSimDeviceCreatedCallback(cuid); });
+  return uid;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    cancelSimDeviceCreatedCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimDeviceCreatedCallback
+  (JNIEnv* env, jclass, jint uid)
+{
+  CallbackJNI::GetInstance().FreeCallback(env, uid);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    registerSimDeviceFreedCallback
+ * Signature: (Ljava/lang/String;Ljava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimDeviceFreedCallback
+  (JNIEnv* env, jclass, jstring prefix, jobject callback)
+{
+  auto [uid, store] =
+      CallbackJNI::GetInstance().AllocateCallback(env, callback);
+  int32_t cuid = HALSIM_RegisterSimDeviceFreedCallback(
+      JStringRef{env, prefix}.c_str(),
+      reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
+      [](const char* name, void* param, HAL_SimDeviceHandle handle) {
+        int32_t uid = reinterpret_cast<intptr_t>(param);
+        CallbackJNI::GetInstance().SendDevice(uid, DeviceInfo{name, handle});
+      });
+  store->SetCancel([cuid] { HALSIM_CancelSimDeviceFreedCallback(cuid); });
+  return uid;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    cancelSimDeviceFreedCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimDeviceFreedCallback
+  (JNIEnv* env, jclass, jint uid)
+{
+  CallbackJNI::GetInstance().FreeCallback(env, uid);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    getSimDeviceHandle
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimDeviceHandle
+  (JNIEnv* env, jclass, jstring name)
+{
+  return HALSIM_GetSimDeviceHandle(JStringRef{env, name}.c_str());
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    getSimValueDeviceHandle
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimValueDeviceHandle
+  (JNIEnv*, jclass, jint handle)
+{
+  return HALSIM_GetSimValueDeviceHandle(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    enumerateSimDevices
+ * Signature: (Ljava/lang/String;)[Ljava/lang/Object;
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_enumerateSimDevices
+  (JNIEnv* env, jclass, jstring prefix)
+{
+  // get values
+  std::vector<DeviceInfo> arr;
+  HALSIM_EnumerateSimDevices(
+      JStringRef{env, prefix}.c_str(), &arr,
+      [](const char* name, void* param, HAL_SimDeviceHandle handle) {
+        auto arr = static_cast<std::vector<DeviceInfo>*>(param);
+        arr->emplace_back(name, handle);
+      });
+
+  // convert to java
+  size_t numElems = arr.size();
+  jobjectArray jarr =
+      env->NewObjectArray(arr.size(), simDeviceInfoCls, nullptr);
+  if (!jarr) return nullptr;
+  for (size_t i = 0; i < numElems; ++i) {
+    JLocal<jobject> elem{env, arr[i].MakeJava(env)};
+    env->SetObjectArrayElement(jarr, i, elem.obj());
+  }
+  return jarr;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    registerSimValueCreatedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimValueCreatedCallback
+  (JNIEnv* env, jclass, jint device, jobject callback, jboolean initialNotify)
+{
+  auto [uid, store] =
+      CallbackJNI::GetInstance().AllocateCallback(env, callback);
+  int32_t cuid = HALSIM_RegisterSimValueCreatedCallback(
+      device, reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
+      [](const char* name, void* param, HAL_SimValueHandle handle,
+         HAL_Bool readonly, const HAL_Value* value) {
+        int32_t uid = reinterpret_cast<intptr_t>(param);
+        CallbackJNI::GetInstance().SendValue(
+            uid, ValueInfo{name, handle, static_cast<bool>(readonly), *value});
+      },
+      initialNotify);
+  store->SetCancel([cuid] { HALSIM_CancelSimValueCreatedCallback(cuid); });
+  return uid;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    cancelSimValueCreatedCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimValueCreatedCallback
+  (JNIEnv* env, jclass, jint uid)
+{
+  CallbackJNI::GetInstance().FreeCallback(env, uid);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    registerSimValueChangedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_registerSimValueChangedCallback
+  (JNIEnv* env, jclass, jint handle, jobject callback, jboolean initialNotify)
+{
+  auto [uid, store] =
+      CallbackJNI::GetInstance().AllocateCallback(env, callback);
+  int32_t cuid = HALSIM_RegisterSimValueChangedCallback(
+      handle, reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
+      [](const char* name, void* param, HAL_SimValueHandle handle,
+         HAL_Bool readonly, const HAL_Value* value) {
+        int32_t uid = reinterpret_cast<intptr_t>(param);
+        CallbackJNI::GetInstance().SendValue(
+            uid, ValueInfo{name, handle, static_cast<bool>(readonly), *value});
+      },
+      initialNotify);
+  store->SetCancel([cuid] { HALSIM_CancelSimValueChangedCallback(cuid); });
+  return uid;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    cancelSimValueChangedCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_cancelSimValueChangedCallback
+  (JNIEnv* env, jclass, jint uid)
+{
+  CallbackJNI::GetInstance().FreeCallback(env, uid);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    getSimValueHandle
+ * Signature: (ILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimValueHandle
+  (JNIEnv* env, jclass, jint device, jstring name)
+{
+  return HALSIM_GetSimValueHandle(device, JStringRef{env, name}.c_str());
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    enumerateSimValues
+ * Signature: (I)[Ljava/lang/Object;
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_enumerateSimValues
+  (JNIEnv* env, jclass, jint device)
+{
+  // get values
+  std::vector<ValueInfo> arr;
+  HALSIM_EnumerateSimValues(
+      device, &arr,
+      [](const char* name, void* param, HAL_SimValueHandle handle,
+         HAL_Bool readonly, const HAL_Value* value) {
+        auto arr = static_cast<std::vector<ValueInfo>*>(param);
+        arr->emplace_back(name, handle, readonly, *value);
+      });
+
+  // convert to java
+  size_t numElems = arr.size();
+  jobjectArray jarr = env->NewObjectArray(arr.size(), simValueInfoCls, nullptr);
+  if (!jarr) return nullptr;
+  for (size_t i = 0; i < numElems; ++i) {
+    JLocal<jobject> elem{env, arr[i].MakeJava(env)};
+    env->SetObjectArrayElement(jarr, i, elem.obj());
+  }
+  return jarr;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    getSimValueEnumOptions
+ * Signature: (I)[Ljava/lang/Object;
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_getSimValueEnumOptions
+  (JNIEnv* env, jclass, jint handle)
+{
+  static JClass stringCls{env, "java/lang/String"};
+  if (!stringCls) return nullptr;
+  int32_t numElems = 0;
+  const char** elems = HALSIM_GetSimValueEnumOptions(handle, &numElems);
+  jobjectArray jarr = env->NewObjectArray(numElems, stringCls, nullptr);
+  if (!jarr) return nullptr;
+  for (int32_t i = 0; i < numElems; ++i) {
+    JLocal<jstring> elem{env, MakeJString(env, elems[i])};
+    env->SetObjectArrayElement(jarr, i, elem.obj());
+  }
+  return jarr;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI
+ * Method:    resetSimDeviceData
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimDeviceDataJNI_resetSimDeviceData
+  (JNIEnv*, jclass)
+{
+  HALSIM_ResetSimDeviceData();
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/include/hal/labview/HAL.h b/hal/src/main/native/sim/jni/SimDeviceDataJNI.h
similarity index 67%
rename from hal/src/main/native/include/hal/labview/HAL.h
rename to hal/src/main/native/sim/jni/SimDeviceDataJNI.h
index db9f20f..56f6d9b 100644
--- a/hal/src/main/native/include/hal/labview/HAL.h
+++ b/hal/src/main/native/sim/jni/SimDeviceDataJNI.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,8 +7,9 @@
 
 #pragma once
 
-#define HAL_USE_LABVIEW
+#include <jni.h>
 
-#include "hal/DriverStation.h"
-#include "hal/HAL.h"
-#include "hal/Types.h"
+namespace sim {
+bool InitializeSimDeviceDataJNI(JNIEnv* env);
+void FreeSimDeviceDataJNI(JNIEnv* env);
+}  // namespace sim
diff --git a/hal/src/main/native/sim/jni/SimulatorJNI.cpp b/hal/src/main/native/sim/jni/SimulatorJNI.cpp
index d1e0f7d..bba8f01 100644
--- a/hal/src/main/native/sim/jni/SimulatorJNI.cpp
+++ b/hal/src/main/native/sim/jni/SimulatorJNI.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,20 +7,21 @@
 
 #include "SimulatorJNI.h"
 
+#include <wpi/jni_util.h>
+
 #include "BufferCallbackStore.h"
 #include "CallbackStore.h"
 #include "ConstBufferCallbackStore.h"
+#include "SimDeviceDataJNI.h"
 #include "SpiReadAutoReceiveBufferCallbackStore.h"
 #include "edu_wpi_first_hal_sim_mockdata_SimulatorJNI.h"
 #include "hal/HAL.h"
-#include "hal/cpp/Log.h"
 #include "hal/handles/HandlesInternal.h"
 #include "mockdata/MockHooks.h"
 
 using namespace wpi::java;
 
 static JavaVM* jvm = nullptr;
-static JClass simValueCls;
 static JClass notifyCallbackCls;
 static JClass bufferCallbackCls;
 static JClass constBufferCallbackCls;
@@ -38,9 +39,6 @@
   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
     return JNI_ERR;
 
-  simValueCls = JClass(env, "edu/wpi/first/hal/sim/SimValue");
-  if (!simValueCls) return JNI_ERR;
-
   notifyCallbackCls = JClass(env, "edu/wpi/first/hal/sim/NotifyCallback");
   if (!notifyCallbackCls) return JNI_ERR;
 
@@ -76,6 +74,7 @@
   InitializeBufferStore();
   InitializeConstBufferStore();
   InitializeSpiBufferStore();
+  if (!InitializeSimDeviceDataJNI(env)) return JNI_ERR;
 
   return JNI_VERSION_1_6;
 }
@@ -85,11 +84,11 @@
   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
     return;
 
-  simValueCls.free(env);
   notifyCallbackCls.free(env);
   bufferCallbackCls.free(env);
   constBufferCallbackCls.free(env);
   spiReadAutoReceiveBufferCallbackCls.free(env);
+  FreeSimDeviceDataJNI(env);
   jvm = nullptr;
 }
 
diff --git a/hal/src/main/native/sim/jni/SimulatorJNI.h b/hal/src/main/native/sim/jni/SimulatorJNI.h
index 60d0ca3..8680396 100644
--- a/hal/src/main/native/sim/jni/SimulatorJNI.h
+++ b/hal/src/main/native/sim/jni/SimulatorJNI.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -7,11 +7,8 @@
 
 #pragma once
 
-#include <wpi/jni_util.h>
-
 #include "hal/Types.h"
 #include "jni.h"
-#include "mockdata/HAL_Value.h"
 
 typedef HAL_Handle SIM_JniHandle;
 
diff --git a/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.cpp b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.cpp
index 935c8bf..b75bb1e 100644
--- a/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.cpp
+++ b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 
 using namespace wpi::java;
diff --git a/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.h b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.h
index 643a874..1a03f59 100644
--- a/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.h
+++ b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -13,8 +13,8 @@
 
 #include "SimulatorJNI.h"
 #include "hal/Types.h"
+#include "hal/Value.h"
 #include "hal/handles/UnlimitedHandleResource.h"
-#include "mockdata/HAL_Value.h"
 #include "mockdata/NotifyListener.h"
 #include "mockdata/SPIData.h"
 
diff --git a/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h b/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h
index 15e55ac..9db0875 100644
--- a/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -19,16 +19,16 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(Z)
 
   static inline HAL_Value MakeRangeValue(HAL_AccelerometerRange value) {
-    return MakeEnum(value);
+    return HAL_MakeEnum(value);
   }
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetActiveName> active{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetActiveName> active{false};
   SimDataValue<HAL_AccelerometerRange, MakeRangeValue, GetRangeName> range{
       static_cast<HAL_AccelerometerRange>(0)};
-  SimDataValue<double, MakeDouble, GetXName> x{0.0};
-  SimDataValue<double, MakeDouble, GetYName> y{0.0};
-  SimDataValue<double, MakeDouble, GetZName> z{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetXName> x{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetYName> y{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetZName> z{0.0};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h
index 8dfcb52..427d2fb 100644
--- a/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -17,9 +17,10 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
 
  public:
-  SimDataValue<double, MakeDouble, GetAngleName> angle{0.0};
-  SimDataValue<double, MakeDouble, GetRateName> rate{0.0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
+  SimDataValue<double, HAL_MakeDouble, GetAngleName> angle{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetRateName> rate{0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/AnalogInData.cpp b/hal/src/main/native/sim/mockdata/AnalogInData.cpp
index 1efdf50..a2a871c 100644
--- a/hal/src/main/native/sim/mockdata/AnalogInData.cpp
+++ b/hal/src/main/native/sim/mockdata/AnalogInData.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -22,6 +22,7 @@
 AnalogInData* hal::SimAnalogInData;
 void AnalogInData::ResetData() {
   initialized.Reset(false);
+  simDevice = 0;
   averageBits.Reset(7);
   oversampleBits.Reset(0);
   voltage.Reset(0.0);
@@ -37,6 +38,10 @@
   SimAnalogInData[index].ResetData();
 }
 
+HAL_SimDeviceHandle HALSIM_GetAnalogInSimDevice(int32_t index) {
+  return SimAnalogInData[index].simDevice;
+}
+
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                   \
   HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, AnalogIn##CAPINAME, \
                                SimAnalogInData, LOWERNAME)
diff --git a/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h
index 94121ca..cd8348d 100644
--- a/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -23,16 +23,21 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(AccumulatorDeadband)
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
-  SimDataValue<int32_t, MakeInt, GetAverageBitsName> averageBits{7};
-  SimDataValue<int32_t, MakeInt, GetOversampleBitsName> oversampleBits{0};
-  SimDataValue<double, MakeDouble, GetVoltageName> voltage{0.0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetAccumulatorInitializedName>
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  std::atomic<HAL_SimDeviceHandle> simDevice;
+  SimDataValue<int32_t, HAL_MakeInt, GetAverageBitsName> averageBits{7};
+  SimDataValue<int32_t, HAL_MakeInt, GetOversampleBitsName> oversampleBits{0};
+  SimDataValue<double, HAL_MakeDouble, GetVoltageName> voltage{0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetAccumulatorInitializedName>
       accumulatorInitialized{false};
-  SimDataValue<int64_t, MakeLong, GetAccumulatorValueName> accumulatorValue{0};
-  SimDataValue<int64_t, MakeLong, GetAccumulatorCountName> accumulatorCount{0};
-  SimDataValue<int32_t, MakeInt, GetAccumulatorCenterName> accumulatorCenter{0};
-  SimDataValue<int32_t, MakeInt, GetAccumulatorDeadbandName>
+  SimDataValue<int64_t, HAL_MakeLong, GetAccumulatorValueName> accumulatorValue{
+      0};
+  SimDataValue<int64_t, HAL_MakeLong, GetAccumulatorCountName> accumulatorCount{
+      0};
+  SimDataValue<int32_t, HAL_MakeInt, GetAccumulatorCenterName>
+      accumulatorCenter{0};
+  SimDataValue<int32_t, HAL_MakeInt, GetAccumulatorDeadbandName>
       accumulatorDeadband{0};
 
   virtual void ResetData();
diff --git a/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h
index 84af837..da7d49f 100644
--- a/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -16,8 +16,8 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
 
  public:
-  SimDataValue<double, MakeDouble, GetVoltageName> voltage{0.0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{0};
+  SimDataValue<double, HAL_MakeDouble, GetVoltageName> voltage{0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{0};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h
index 131ba7a..61b3c19 100644
--- a/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -19,15 +19,15 @@
 
   static LLVM_ATTRIBUTE_ALWAYS_INLINE HAL_Value
   MakeTriggerModeValue(HALSIM_AnalogTriggerMode value) {
-    return MakeEnum(value);
+    return HAL_MakeEnum(value);
   }
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{0};
-  SimDataValue<double, MakeDouble, GetTriggerLowerBoundName> triggerLowerBound{
-      0};
-  SimDataValue<double, MakeDouble, GetTriggerUpperBoundName> triggerUpperBound{
-      0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{0};
+  SimDataValue<double, HAL_MakeDouble, GetTriggerLowerBoundName>
+      triggerLowerBound{0};
+  SimDataValue<double, HAL_MakeDouble, GetTriggerUpperBoundName>
+      triggerUpperBound{0};
   SimDataValue<HALSIM_AnalogTriggerMode, MakeTriggerModeValue,
                GetTriggerModeName>
       triggerMode{static_cast<HALSIM_AnalogTriggerMode>(0)};
diff --git a/hal/src/main/native/sim/mockdata/DIOData.cpp b/hal/src/main/native/sim/mockdata/DIOData.cpp
index ea66de3..a9c61fd 100644
--- a/hal/src/main/native/sim/mockdata/DIOData.cpp
+++ b/hal/src/main/native/sim/mockdata/DIOData.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -22,6 +22,7 @@
 DIOData* hal::SimDIOData;
 void DIOData::ResetData() {
   initialized.Reset(false);
+  simDevice = 0;
   value.Reset(true);
   pulseLength.Reset(0.0);
   isInput.Reset(true);
@@ -31,6 +32,10 @@
 extern "C" {
 void HALSIM_ResetDIOData(int32_t index) { SimDIOData[index].ResetData(); }
 
+HAL_SimDeviceHandle HALSIM_GetDIOSimDevice(int32_t index) {
+  return SimDIOData[index].simDevice;
+}
+
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
   HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, DIO##CAPINAME, SimDIOData, \
                                LOWERNAME)
diff --git a/hal/src/main/native/sim/mockdata/DIODataInternal.h b/hal/src/main/native/sim/mockdata/DIODataInternal.h
index 0b022f9..49e0f75 100644
--- a/hal/src/main/native/sim/mockdata/DIODataInternal.h
+++ b/hal/src/main/native/sim/mockdata/DIODataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -19,11 +19,13 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(FilterIndex)
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetValueName> value{true};
-  SimDataValue<double, MakeDouble, GetPulseLengthName> pulseLength{0.0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetIsInputName> isInput{true};
-  SimDataValue<int32_t, MakeInt, GetFilterIndexName> filterIndex{-1};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  std::atomic<HAL_SimDeviceHandle> simDevice;
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetValueName> value{true};
+  SimDataValue<double, HAL_MakeDouble, GetPulseLengthName> pulseLength{0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetIsInputName> isInput{true};
+  SimDataValue<int32_t, HAL_MakeInt, GetFilterIndexName> filterIndex{-1};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h b/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h
index 00d8b4a..09d5903 100644
--- a/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -17,9 +17,10 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(Pin)
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
-  SimDataValue<double, MakeDouble, GetDutyCycleName> dutyCycle{0.0};
-  SimDataValue<int32_t, MakeInt, GetPinName> pin{0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  SimDataValue<double, HAL_MakeDouble, GetDutyCycleName> dutyCycle{0.0};
+  SimDataValue<int32_t, HAL_MakeInt, GetPinName> pin{0};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/DriverStationData.cpp b/hal/src/main/native/sim/mockdata/DriverStationData.cpp
index d72d6b3..ece98c8 100644
--- a/hal/src/main/native/sim/mockdata/DriverStationData.cpp
+++ b/hal/src/main/native/sim/mockdata/DriverStationData.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -46,7 +46,7 @@
   matchTime.Reset(0.0);
 
   {
-    std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+    std::scoped_lock lock(m_joystickDataMutex);
     m_joystickAxes = std::make_unique<HAL_JoystickAxes[]>(6);
     m_joystickPOVs = std::make_unique<HAL_JoystickPOVs[]>(6);
     m_joystickButtons = std::make_unique<HAL_JoystickButtons[]>(6);
@@ -63,7 +63,7 @@
     }
   }
   {
-    std::lock_guard<wpi::spinlock> lock(m_matchInfoMutex);
+    std::scoped_lock lock(m_matchInfoMutex);
 
     m_matchInfo = std::make_unique<HAL_MatchInfo>();
   }
@@ -71,22 +71,22 @@
 
 void DriverStationData::GetJoystickAxes(int32_t joystickNum,
                                         HAL_JoystickAxes* axes) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   *axes = m_joystickAxes[joystickNum];
 }
 void DriverStationData::GetJoystickPOVs(int32_t joystickNum,
                                         HAL_JoystickPOVs* povs) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   *povs = m_joystickPOVs[joystickNum];
 }
 void DriverStationData::GetJoystickButtons(int32_t joystickNum,
                                            HAL_JoystickButtons* buttons) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   *buttons = m_joystickButtons[joystickNum];
 }
 void DriverStationData::GetJoystickDescriptor(
     int32_t joystickNum, HAL_JoystickDescriptor* descriptor) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   *descriptor = m_joystickDescriptor[joystickNum];
   // Always ensure name is null terminated
   descriptor->name[255] = '\0';
@@ -95,49 +95,49 @@
                                            int64_t* outputs,
                                            int32_t* leftRumble,
                                            int32_t* rightRumble) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   *leftRumble = m_joystickOutputs[joystickNum].leftRumble;
   *outputs = m_joystickOutputs[joystickNum].outputs;
   *rightRumble = m_joystickOutputs[joystickNum].rightRumble;
 }
 void DriverStationData::GetMatchInfo(HAL_MatchInfo* info) {
-  std::lock_guard<wpi::spinlock> lock(m_matchInfoMutex);
+  std::scoped_lock lock(m_matchInfoMutex);
   *info = *m_matchInfo;
 }
 
 void DriverStationData::SetJoystickAxes(int32_t joystickNum,
                                         const HAL_JoystickAxes* axes) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   m_joystickAxes[joystickNum] = *axes;
 }
 void DriverStationData::SetJoystickPOVs(int32_t joystickNum,
                                         const HAL_JoystickPOVs* povs) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   m_joystickPOVs[joystickNum] = *povs;
 }
 void DriverStationData::SetJoystickButtons(int32_t joystickNum,
                                            const HAL_JoystickButtons* buttons) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   m_joystickButtons[joystickNum] = *buttons;
 }
 
 void DriverStationData::SetJoystickDescriptor(
     int32_t joystickNum, const HAL_JoystickDescriptor* descriptor) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   m_joystickDescriptor[joystickNum] = *descriptor;
 }
 
 void DriverStationData::SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
                                            int32_t leftRumble,
                                            int32_t rightRumble) {
-  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  std::scoped_lock lock(m_joystickDataMutex);
   m_joystickOutputs[joystickNum].leftRumble = leftRumble;
   m_joystickOutputs[joystickNum].outputs = outputs;
   m_joystickOutputs[joystickNum].rightRumble = rightRumble;
 }
 
 void DriverStationData::SetMatchInfo(const HAL_MatchInfo* info) {
-  std::lock_guard<wpi::spinlock> lock(m_matchInfoMutex);
+  std::scoped_lock lock(m_matchInfoMutex);
   *m_matchInfo = *info;
   *(std::end(m_matchInfo->eventName) - 1) = '\0';
 }
diff --git a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h
index f7eb132..fdeb3c6 100644
--- a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -29,7 +29,7 @@
 
   static LLVM_ATTRIBUTE_ALWAYS_INLINE HAL_Value
   MakeAllianceStationIdValue(HAL_AllianceStationID value) {
-    return MakeEnum(value);
+    return HAL_MakeEnum(value);
   }
 
  public:
@@ -58,16 +58,17 @@
 
   void NotifyNewData();
 
-  SimDataValue<HAL_Bool, MakeBoolean, GetEnabledName> enabled{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetAutonomousName> autonomous{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetTestName> test{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetEStopName> eStop{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetFmsAttachedName> fmsAttached{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetDsAttachedName> dsAttached{true};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetEnabledName> enabled{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetAutonomousName> autonomous{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetTestName> test{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetEStopName> eStop{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetFmsAttachedName> fmsAttached{
+      false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetDsAttachedName> dsAttached{true};
   SimDataValue<HAL_AllianceStationID, MakeAllianceStationIdValue,
                GetAllianceStationIdName>
       allianceStationId{static_cast<HAL_AllianceStationID>(0)};
-  SimDataValue<double, MakeDouble, GetMatchTimeName> matchTime{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetMatchTimeName> matchTime{0.0};
 
  private:
   wpi::spinlock m_joystickDataMutex;
diff --git a/hal/src/main/native/sim/mockdata/EncoderData.cpp b/hal/src/main/native/sim/mockdata/EncoderData.cpp
index 59ba48f..33bd073 100644
--- a/hal/src/main/native/sim/mockdata/EncoderData.cpp
+++ b/hal/src/main/native/sim/mockdata/EncoderData.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -22,7 +22,9 @@
 EncoderData* hal::SimEncoderData;
 void EncoderData::ResetData() {
   digitalChannelA = 0;
+  digitalChannelB = 0;
   initialized.Reset(false);
+  simDevice = 0;
   count.Reset(0);
   period.Reset(std::numeric_limits<double>::max());
   reset.Reset(false);
@@ -38,10 +40,18 @@
   SimEncoderData[index].ResetData();
 }
 
-int16_t HALSIM_GetDigitalChannelA(int32_t index) {
+int32_t HALSIM_GetEncoderDigitalChannelA(int32_t index) {
   return SimEncoderData[index].digitalChannelA;
 }
 
+int32_t HALSIM_GetEncoderDigitalChannelB(int32_t index) {
+  return SimEncoderData[index].digitalChannelB;
+}
+
+HAL_SimDeviceHandle HALSIM_GetEncoderSimDevice(int32_t index) {
+  return SimEncoderData[index].simDevice;
+}
+
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                  \
   HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, Encoder##CAPINAME, \
                                SimEncoderData, LOWERNAME)
diff --git a/hal/src/main/native/sim/mockdata/EncoderDataInternal.h b/hal/src/main/native/sim/mockdata/EncoderDataInternal.h
index 657d977..389289c 100644
--- a/hal/src/main/native/sim/mockdata/EncoderDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/EncoderDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -26,18 +26,23 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(DistancePerPulse)
 
  public:
-  std::atomic<int16_t> digitalChannelA{0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
-  SimDataValue<int32_t, MakeInt, GetCountName> count{0};
-  SimDataValue<double, MakeDouble, GetPeriodName> period{
-      std::numeric_limits<double>::max()};
-  SimDataValue<HAL_Bool, MakeBoolean, GetResetName> reset{false};
-  SimDataValue<double, MakeDouble, GetMaxPeriodName> maxPeriod{0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetDirectionName> direction{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetReverseDirectionName> reverseDirection{
+  std::atomic<int32_t> digitalChannelA{0};
+  std::atomic<int32_t> digitalChannelB{0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
       false};
-  SimDataValue<int32_t, MakeInt, GetSamplesToAverageName> samplesToAverage{0};
-  SimDataValue<double, MakeDouble, GetDistancePerPulseName> distancePerPulse{1};
+  std::atomic<HAL_SimDeviceHandle> simDevice;
+  SimDataValue<int32_t, HAL_MakeInt, GetCountName> count{0};
+  SimDataValue<double, HAL_MakeDouble, GetPeriodName> period{
+      (std::numeric_limits<double>::max)()};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetResetName> reset{false};
+  SimDataValue<double, HAL_MakeDouble, GetMaxPeriodName> maxPeriod{0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetDirectionName> direction{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetReverseDirectionName>
+      reverseDirection{false};
+  SimDataValue<int32_t, HAL_MakeInt, GetSamplesToAverageName> samplesToAverage{
+      0};
+  SimDataValue<double, HAL_MakeDouble, GetDistancePerPulseName>
+      distancePerPulse{1};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/HALValueInternal.h b/hal/src/main/native/sim/mockdata/HALValueInternal.h
deleted file mode 100644
index f659403..0000000
--- a/hal/src/main/native/sim/mockdata/HALValueInternal.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include "mockdata/HALValue.h"
-#include "mockdata/wpi/StringRef.h"
-
-namespace hal {
-
-class Value;
-
-void ConvertToC(const Value& in, HAL_Value* out);
-std::shared_ptr<Value> ConvertFromC(const HAL_Value& value);
-void ConvertToC(wpi::StringRef in, HALString* out);
-inline wpi::StringRef ConvertFromC(const HALString& str) {
-  return wpi::StringRef(str.str, str.len);
-}
-
-}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/I2CDataInternal.h b/hal/src/main/native/sim/mockdata/I2CDataInternal.h
index 1c2df0e..c799bb7 100644
--- a/hal/src/main/native/sim/mockdata/I2CDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/I2CDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -22,7 +22,8 @@
              int32_t sendSize);
   void Read(int32_t deviceAddress, uint8_t* buffer, int32_t count);
 
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
   SimCallbackRegistry<HAL_BufferCallback, GetReadName> read;
   SimCallbackRegistry<HAL_ConstBufferCallback, GetWriteName> write;
 
diff --git a/hal/src/main/native/sim/mockdata/PCMDataInternal.h b/hal/src/main/native/sim/mockdata/PCMDataInternal.h
index 4144987..0c7b99b 100644
--- a/hal/src/main/native/sim/mockdata/PCMDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/PCMDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -31,21 +31,22 @@
   }
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetSolenoidInitializedName,
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetSolenoidInitializedName,
                GetSolenoidInitializedDefault>
       solenoidInitialized[kNumSolenoidChannels];
-  SimDataValue<HAL_Bool, MakeBoolean, GetSolenoidOutputName,
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetSolenoidOutputName,
                GetSolenoidOutputDefault>
       solenoidOutput[kNumSolenoidChannels];
-  SimDataValue<HAL_Bool, MakeBoolean, GetCompressorInitializedName>
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetCompressorInitializedName>
       compressorInitialized{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetCompressorOnName> compressorOn{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetClosedLoopEnabledName>
-      closedLoopEnabled{true};
-  SimDataValue<HAL_Bool, MakeBoolean, GetPressureSwitchName> pressureSwitch{
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetCompressorOnName> compressorOn{
       false};
-  SimDataValue<double, MakeDouble, GetCompressorCurrentName> compressorCurrent{
-      0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetClosedLoopEnabledName>
+      closedLoopEnabled{true};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetPressureSwitchName> pressureSwitch{
+      false};
+  SimDataValue<double, HAL_MakeDouble, GetCompressorCurrentName>
+      compressorCurrent{0.0};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/PDPDataInternal.h b/hal/src/main/native/sim/mockdata/PDPDataInternal.h
index a7170c7..8d45416 100644
--- a/hal/src/main/native/sim/mockdata/PDPDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/PDPDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -23,10 +23,11 @@
   }
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
-  SimDataValue<double, MakeDouble, GetTemperatureName> temperature{0.0};
-  SimDataValue<double, MakeDouble, GetVoltageName> voltage{12.0};
-  SimDataValue<double, MakeDouble, GetCurrentName, GetCurrentDefault>
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  SimDataValue<double, HAL_MakeDouble, GetTemperatureName> temperature{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetVoltageName> voltage{12.0};
+  SimDataValue<double, HAL_MakeDouble, GetCurrentName, GetCurrentDefault>
       current[kNumPDPChannels];
 
   virtual void ResetData();
diff --git a/hal/src/main/native/sim/mockdata/PWMDataInternal.h b/hal/src/main/native/sim/mockdata/PWMDataInternal.h
index 85eae44..248b7b3 100644
--- a/hal/src/main/native/sim/mockdata/PWMDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/PWMDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -20,12 +20,13 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(ZeroLatch)
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
-  SimDataValue<int32_t, MakeInt, GetRawValueName> rawValue{0};
-  SimDataValue<double, MakeDouble, GetSpeedName> speed{0};
-  SimDataValue<double, MakeDouble, GetPositionName> position{0};
-  SimDataValue<int32_t, MakeInt, GetPeriodScaleName> periodScale{0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetZeroLatchName> zeroLatch{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  SimDataValue<int32_t, HAL_MakeInt, GetRawValueName> rawValue{0};
+  SimDataValue<double, HAL_MakeDouble, GetSpeedName> speed{0};
+  SimDataValue<double, HAL_MakeDouble, GetPositionName> position{0};
+  SimDataValue<int32_t, HAL_MakeInt, GetPeriodScaleName> periodScale{0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetZeroLatchName> zeroLatch{false};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/RelayDataInternal.h b/hal/src/main/native/sim/mockdata/RelayDataInternal.h
index 88e79ff..cb38388 100644
--- a/hal/src/main/native/sim/mockdata/RelayDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/RelayDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -18,12 +18,12 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(Reverse)
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedForwardName>
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedForwardName>
       initializedForward{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedReverseName>
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedReverseName>
       initializedReverse{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetForwardName> forward{false};
-  SimDataValue<HAL_Bool, MakeBoolean, GetReverseName> reverse{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetForwardName> forward{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetReverseName> reverse{false};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h
index 92aa0c8..cc74fa2 100644
--- a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -29,22 +29,26 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(UserFaults3V3)
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetFPGAButtonName> fpgaButton{false};
-  SimDataValue<double, MakeDouble, GetVInVoltageName> vInVoltage{0.0};
-  SimDataValue<double, MakeDouble, GetVInCurrentName> vInCurrent{0.0};
-  SimDataValue<double, MakeDouble, GetUserVoltage6VName> userVoltage6V{6.0};
-  SimDataValue<double, MakeDouble, GetUserCurrent6VName> userCurrent6V{0.0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetUserActive6VName> userActive6V{false};
-  SimDataValue<double, MakeDouble, GetUserVoltage5VName> userVoltage5V{5.0};
-  SimDataValue<double, MakeDouble, GetUserCurrent5VName> userCurrent5V{0.0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetUserActive5VName> userActive5V{false};
-  SimDataValue<double, MakeDouble, GetUserVoltage3V3Name> userVoltage3V3{3.3};
-  SimDataValue<double, MakeDouble, GetUserCurrent3V3Name> userCurrent3V3{0.0};
-  SimDataValue<HAL_Bool, MakeBoolean, GetUserActive3V3Name> userActive3V3{
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetFPGAButtonName> fpgaButton{false};
+  SimDataValue<double, HAL_MakeDouble, GetVInVoltageName> vInVoltage{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetVInCurrentName> vInCurrent{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetUserVoltage6VName> userVoltage6V{6.0};
+  SimDataValue<double, HAL_MakeDouble, GetUserCurrent6VName> userCurrent6V{0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetUserActive6VName> userActive6V{
       false};
-  SimDataValue<int32_t, MakeInt, GetUserFaults6VName> userFaults6V{0};
-  SimDataValue<int32_t, MakeInt, GetUserFaults5VName> userFaults5V{0};
-  SimDataValue<int32_t, MakeInt, GetUserFaults3V3Name> userFaults3V3{0};
+  SimDataValue<double, HAL_MakeDouble, GetUserVoltage5VName> userVoltage5V{5.0};
+  SimDataValue<double, HAL_MakeDouble, GetUserCurrent5VName> userCurrent5V{0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetUserActive5VName> userActive5V{
+      false};
+  SimDataValue<double, HAL_MakeDouble, GetUserVoltage3V3Name> userVoltage3V3{
+      3.3};
+  SimDataValue<double, HAL_MakeDouble, GetUserCurrent3V3Name> userCurrent3V3{
+      0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetUserActive3V3Name> userActive3V3{
+      false};
+  SimDataValue<int32_t, HAL_MakeInt, GetUserFaults6VName> userFaults6V{0};
+  SimDataValue<int32_t, HAL_MakeInt, GetUserFaults5VName> userFaults5V{0};
+  SimDataValue<int32_t, HAL_MakeInt, GetUserFaults3V3Name> userFaults3V3{0};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h b/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h
index ee9f79d..661e01b 100644
--- a/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -19,11 +19,11 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(Z)
 
  public:
-  SimDataValue<HAL_Bool, MakeBoolean, GetActiveName> active{false};
-  SimDataValue<int32_t, MakeInt, GetRangeName> range{0};
-  SimDataValue<double, MakeDouble, GetXName> x{0.0};
-  SimDataValue<double, MakeDouble, GetYName> y{0.0};
-  SimDataValue<double, MakeDouble, GetZName> z{0.0};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetActiveName> active{false};
+  SimDataValue<int32_t, HAL_MakeInt, GetRangeName> range{0};
+  SimDataValue<double, HAL_MakeDouble, GetXName> x{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetYName> y{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetZName> z{0.0};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/SPIDataInternal.h b/hal/src/main/native/sim/mockdata/SPIDataInternal.h
index b10e741..44868d2 100644
--- a/hal/src/main/native/sim/mockdata/SPIDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/SPIDataInternal.h
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -27,7 +27,8 @@
   int32_t ReadAutoReceivedData(uint32_t* buffer, int32_t numToRead,
                                double timeout, int32_t* status);
 
-  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
   SimCallbackRegistry<HAL_BufferCallback, GetReadName> read;
   SimCallbackRegistry<HAL_ConstBufferCallback, GetWriteName> write;
   SimCallbackRegistry<HAL_SpiReadAutoReceiveBufferCallback, GetAutoReceiveName>
diff --git a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp
new file mode 100644
index 0000000..a703257
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp
@@ -0,0 +1,414 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "mockdata/SimDeviceData.h"  // NOLINT(build/include_order)
+
+#include <algorithm>
+
+#include "SimDeviceDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeSimDeviceData() {
+  static SimDeviceData sdd;
+  ::hal::SimSimDeviceData = &sdd;
+}
+}  // namespace init
+}  // namespace hal
+
+SimDeviceData* hal::SimSimDeviceData;
+
+SimDeviceData::Device* SimDeviceData::LookupDevice(HAL_SimDeviceHandle handle) {
+  if (handle <= 0) return nullptr;
+  --handle;
+  if (static_cast<uint32_t>(handle) >= m_devices.size() || !m_devices[handle])
+    return nullptr;
+  return m_devices[handle].get();
+}
+
+SimDeviceData::Value* SimDeviceData::LookupValue(HAL_SimValueHandle handle) {
+  if (handle <= 0) return nullptr;
+
+  // look up device
+  Device* deviceImpl = LookupDevice(handle >> 16);
+  if (!deviceImpl) return nullptr;
+
+  // look up value
+  handle &= 0xffff;
+  --handle;
+  if (static_cast<uint32_t>(handle) >= deviceImpl->values.size() ||
+      !deviceImpl->values[handle])
+    return nullptr;
+
+  return deviceImpl->values[handle].get();
+}
+
+HAL_SimDeviceHandle SimDeviceData::CreateDevice(const char* name) {
+  std::scoped_lock lock(m_mutex);
+
+  // check for duplicates and don't overwrite them
+  auto it = m_deviceMap.find(name);
+  if (it != m_deviceMap.end()) return 0;
+
+  // don't allow more than 4096 devices (limit driven by 12-bit allocation in
+  // value changed callback uid)
+  if (m_devices.size() >= 4095) return 0;
+
+  // create and save
+  auto deviceImpl = std::make_shared<Device>(name);
+  HAL_SimDeviceHandle deviceHandle = m_devices.emplace_back(deviceImpl) + 1;
+  deviceImpl->handle = deviceHandle;
+  m_deviceMap[name] = deviceImpl;
+
+  // notify callbacks
+  m_deviceCreated(name, deviceHandle);
+
+  return deviceHandle;
+}
+
+void SimDeviceData::FreeDevice(HAL_SimDeviceHandle handle) {
+  std::scoped_lock lock(m_mutex);
+  --handle;
+
+  // see if it exists
+  if (handle < 0 || static_cast<uint32_t>(handle) >= m_devices.size()) return;
+  auto deviceImpl = std::move(m_devices[handle]);
+  if (!deviceImpl) return;
+
+  // remove from map
+  m_deviceMap.erase(deviceImpl->name);
+
+  // remove from vector
+  m_devices.erase(handle);
+
+  // notify callbacks
+  m_deviceFreed(deviceImpl->name.c_str(), handle + 1);
+}
+
+HAL_SimValueHandle SimDeviceData::CreateValue(HAL_SimDeviceHandle device,
+                                              const char* name, bool readonly,
+                                              int32_t numOptions,
+                                              const char** options,
+                                              const HAL_Value& initialValue) {
+  std::scoped_lock lock(m_mutex);
+
+  // look up device
+  Device* deviceImpl = LookupDevice(device);
+  if (!deviceImpl) return 0;
+
+  // check for duplicates and don't overwrite them
+  auto it = deviceImpl->valueMap.find(name);
+  if (it != deviceImpl->valueMap.end()) return 0;
+
+  // don't allow more than 4096 values per device (limit driven by 12-bit
+  // allocation in value changed callback uid)
+  if (deviceImpl->values.size() >= 4095) return 0;
+
+  // create and save; encode device into handle
+  auto valueImplPtr = std::make_unique<Value>(name, readonly, initialValue);
+  Value* valueImpl = valueImplPtr.get();
+  HAL_SimValueHandle valueHandle =
+      (device << 16) |
+      (deviceImpl->values.emplace_back(std::move(valueImplPtr)) + 1);
+  valueImpl->handle = valueHandle;
+  // copy options (if any provided)
+  if (numOptions > 0 && options) {
+    valueImpl->enumOptions.reserve(numOptions);
+    valueImpl->cstrEnumOptions.reserve(numOptions);
+    for (int32_t i = 0; i < numOptions; ++i) {
+      valueImpl->enumOptions.emplace_back(options[i]);
+      // point to our copy of the string, not the passed-in one
+      valueImpl->cstrEnumOptions.emplace_back(
+          valueImpl->enumOptions.back().c_str());
+    }
+  }
+  deviceImpl->valueMap[name] = valueImpl;
+
+  // notify callbacks
+  deviceImpl->valueCreated(name, valueHandle, readonly, &initialValue);
+
+  return valueHandle;
+}
+
+HAL_Value SimDeviceData::GetValue(HAL_SimValueHandle handle) {
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(handle);
+
+  if (!valueImpl) {
+    HAL_Value value;
+    value.data.v_int = 0;
+    value.type = HAL_UNASSIGNED;
+    return value;
+  }
+
+  return valueImpl->value;
+}
+
+void SimDeviceData::SetValue(HAL_SimValueHandle handle,
+                             const HAL_Value& value) {
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(handle);
+  if (!valueImpl) return;
+
+  valueImpl->value = value;
+
+  // notify callbacks
+  valueImpl->changed(valueImpl->name.c_str(), valueImpl->handle,
+                     valueImpl->readonly, &value);
+}
+
+int32_t SimDeviceData::RegisterDeviceCreatedCallback(
+    const char* prefix, void* param, HALSIM_SimDeviceCallback callback,
+    bool initialNotify) {
+  std::scoped_lock lock(m_mutex);
+
+  // register callback
+  int32_t index = m_deviceCreated.Register(prefix, param, callback);
+
+  // initial notifications
+  if (initialNotify) {
+    for (auto&& device : m_devices)
+      callback(device->name.c_str(), param, device->handle);
+  }
+
+  return index;
+}
+
+void SimDeviceData::CancelDeviceCreatedCallback(int32_t uid) {
+  if (uid <= 0) return;
+  std::scoped_lock lock(m_mutex);
+  m_deviceCreated.Cancel(uid);
+}
+
+int32_t SimDeviceData::RegisterDeviceFreedCallback(
+    const char* prefix, void* param, HALSIM_SimDeviceCallback callback) {
+  std::scoped_lock lock(m_mutex);
+  return m_deviceFreed.Register(prefix, param, callback);
+}
+
+void SimDeviceData::CancelDeviceFreedCallback(int32_t uid) {
+  if (uid <= 0) return;
+  std::scoped_lock lock(m_mutex);
+  m_deviceFreed.Cancel(uid);
+}
+
+HAL_SimDeviceHandle SimDeviceData::GetDeviceHandle(const char* name) {
+  std::scoped_lock lock(m_mutex);
+  auto it = m_deviceMap.find(name);
+  if (it == m_deviceMap.end()) return 0;
+  if (auto deviceImpl = it->getValue().lock())
+    return deviceImpl->handle;
+  else
+    return 0;
+}
+
+const char* SimDeviceData::GetDeviceName(HAL_SimDeviceHandle handle) {
+  std::scoped_lock lock(m_mutex);
+
+  // look up device
+  Device* deviceImpl = LookupDevice(handle);
+  if (!deviceImpl) return nullptr;
+
+  return deviceImpl->name.c_str();
+}
+
+void SimDeviceData::EnumerateDevices(const char* prefix, void* param,
+                                     HALSIM_SimDeviceCallback callback) {
+  std::scoped_lock lock(m_mutex);
+  for (auto&& device : m_devices) {
+    if (wpi::StringRef{device->name}.startswith(prefix))
+      callback(device->name.c_str(), param, device->handle);
+  }
+}
+
+int32_t SimDeviceData::RegisterValueCreatedCallback(
+    HAL_SimDeviceHandle device, void* param, HALSIM_SimValueCallback callback,
+    bool initialNotify) {
+  std::scoped_lock lock(m_mutex);
+  Device* deviceImpl = LookupDevice(device);
+  if (!deviceImpl) return -1;
+
+  // register callback
+  int32_t index = deviceImpl->valueCreated.Register(callback, param);
+
+  // initial notifications
+  if (initialNotify) {
+    for (auto&& value : deviceImpl->values)
+      callback(value->name.c_str(), param, value->handle, value->readonly,
+               &value->value);
+  }
+
+  // encode device into uid
+  return (device << 16) | (index & 0xffff);
+}
+
+void SimDeviceData::CancelValueCreatedCallback(int32_t uid) {
+  if (uid <= 0) return;
+  std::scoped_lock lock(m_mutex);
+  Device* deviceImpl = LookupDevice(uid >> 16);
+  if (!deviceImpl) return;
+  deviceImpl->valueCreated.Cancel(uid & 0xffff);
+}
+
+int32_t SimDeviceData::RegisterValueChangedCallback(
+    HAL_SimValueHandle handle, void* param, HALSIM_SimValueCallback callback,
+    bool initialNotify) {
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(handle);
+  if (!valueImpl) return -1;
+
+  // register callback
+  int32_t index = valueImpl->changed.Register(callback, param);
+
+  // initial notification
+  if (initialNotify)
+    callback(valueImpl->name.c_str(), param, valueImpl->handle,
+             valueImpl->readonly, &valueImpl->value);
+
+  // encode device and value into uid
+  return (((handle >> 16) & 0xfff) << 19) | ((handle & 0xfff) << 7) |
+         (index & 0x7f);
+}
+
+void SimDeviceData::CancelValueChangedCallback(int32_t uid) {
+  if (uid <= 0) return;
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(((uid >> 19) << 16) | ((uid >> 7) & 0xfff));
+  if (!valueImpl) return;
+  valueImpl->changed.Cancel(uid & 0x7f);
+}
+
+HAL_SimValueHandle SimDeviceData::GetValueHandle(HAL_SimDeviceHandle device,
+                                                 const char* name) {
+  std::scoped_lock lock(m_mutex);
+  Device* deviceImpl = LookupDevice(device);
+  if (!deviceImpl) return 0;
+
+  // lookup value
+  auto it = deviceImpl->valueMap.find(name);
+  if (it == deviceImpl->valueMap.end()) return 0;
+  if (!it->getValue()) return 0;
+  return it->getValue()->handle;
+}
+
+void SimDeviceData::EnumerateValues(HAL_SimDeviceHandle device, void* param,
+                                    HALSIM_SimValueCallback callback) {
+  std::scoped_lock lock(m_mutex);
+  Device* deviceImpl = LookupDevice(device);
+  if (!deviceImpl) return;
+
+  for (auto&& value : deviceImpl->values)
+    callback(value->name.c_str(), param, value->handle, value->readonly,
+             &value->value);
+}
+
+const char** SimDeviceData::GetValueEnumOptions(HAL_SimValueHandle handle,
+                                                int32_t* numOptions) {
+  *numOptions = 0;
+
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(handle);
+  if (!valueImpl) return nullptr;
+
+  // get list of options (safe to return as they never change)
+  auto& options = valueImpl->cstrEnumOptions;
+  *numOptions = options.size();
+  return options.data();
+}
+
+void SimDeviceData::ResetData() {
+  std::scoped_lock lock(m_mutex);
+  m_devices.clear();
+  m_deviceMap.clear();
+  m_deviceCreated.Reset();
+  m_deviceFreed.Reset();
+}
+
+extern "C" {
+
+int32_t HALSIM_RegisterSimDeviceCreatedCallback(
+    const char* prefix, void* param, HALSIM_SimDeviceCallback callback,
+    HAL_Bool initialNotify) {
+  return SimSimDeviceData->RegisterDeviceCreatedCallback(
+      prefix, param, callback, initialNotify);
+}
+
+void HALSIM_CancelSimDeviceCreatedCallback(int32_t uid) {
+  SimSimDeviceData->CancelDeviceCreatedCallback(uid);
+}
+
+int32_t HALSIM_RegisterSimDeviceFreedCallback(
+    const char* prefix, void* param, HALSIM_SimDeviceCallback callback) {
+  return SimSimDeviceData->RegisterDeviceFreedCallback(prefix, param, callback);
+}
+
+void HALSIM_CancelSimDeviceFreedCallback(int32_t uid) {
+  SimSimDeviceData->CancelDeviceFreedCallback(uid);
+}
+
+HAL_SimDeviceHandle HALSIM_GetSimDeviceHandle(const char* name) {
+  return SimSimDeviceData->GetDeviceHandle(name);
+}
+
+const char* HALSIM_GetSimDeviceName(HAL_SimDeviceHandle handle) {
+  return SimSimDeviceData->GetDeviceName(handle);
+}
+
+HAL_SimDeviceHandle HALSIM_GetSimValueDeviceHandle(HAL_SimValueHandle handle) {
+  if (handle <= 0) return 0;
+  return handle >> 16;
+}
+
+void HALSIM_EnumerateSimDevices(const char* prefix, void* param,
+                                HALSIM_SimDeviceCallback callback) {
+  SimSimDeviceData->EnumerateDevices(prefix, param, callback);
+}
+
+int32_t HALSIM_RegisterSimValueCreatedCallback(HAL_SimDeviceHandle device,
+                                               void* param,
+                                               HALSIM_SimValueCallback callback,
+                                               HAL_Bool initialNotify) {
+  return SimSimDeviceData->RegisterValueCreatedCallback(device, param, callback,
+                                                        initialNotify);
+}
+
+void HALSIM_CancelSimValueCreatedCallback(int32_t uid) {
+  SimSimDeviceData->CancelValueCreatedCallback(uid);
+}
+
+int32_t HALSIM_RegisterSimValueChangedCallback(HAL_SimValueHandle handle,
+                                               void* param,
+                                               HALSIM_SimValueCallback callback,
+                                               HAL_Bool initialNotify) {
+  return SimSimDeviceData->RegisterValueChangedCallback(handle, param, callback,
+                                                        initialNotify);
+}
+
+void HALSIM_CancelSimValueChangedCallback(int32_t uid) {
+  SimSimDeviceData->CancelValueChangedCallback(uid);
+}
+
+HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device,
+                                            const char* name) {
+  return SimSimDeviceData->GetValueHandle(device, name);
+}
+
+void HALSIM_EnumerateSimValues(HAL_SimDeviceHandle device, void* param,
+                               HALSIM_SimValueCallback callback) {
+  SimSimDeviceData->EnumerateValues(device, param, callback);
+}
+
+const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
+                                           int32_t* numOptions) {
+  return SimSimDeviceData->GetValueEnumOptions(handle, numOptions);
+}
+
+void HALSIM_ResetSimDeviceData(void) { SimSimDeviceData->ResetData(); }
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h b/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h
new file mode 100644
index 0000000..2582eca
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h
@@ -0,0 +1,214 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <wpi/StringMap.h>
+#include <wpi/UidVector.h>
+#include <wpi/spinlock.h>
+
+#include "hal/Value.h"
+#include "mockdata/SimCallbackRegistry.h"
+#include "mockdata/SimDeviceData.h"
+
+namespace hal {
+
+namespace impl {
+
+template <typename CallbackFunction>
+class SimUnnamedCallbackRegistry {
+ public:
+  using RawFunctor = void (*)();
+
+ protected:
+  using CallbackVector = wpi::UidVector<HalCallbackListener<RawFunctor>, 4>;
+
+ public:
+  void Cancel(int32_t uid) {
+    if (m_callbacks) m_callbacks->erase(uid - 1);
+  }
+
+  void Reset() {
+    if (m_callbacks) m_callbacks->clear();
+  }
+
+  int32_t Register(CallbackFunction callback, void* param) {
+    // Must return -1 on a null callback for error handling
+    if (callback == nullptr) return -1;
+    if (!m_callbacks) m_callbacks = std::make_unique<CallbackVector>();
+    return m_callbacks->emplace_back(param,
+                                     reinterpret_cast<RawFunctor>(callback)) +
+           1;
+  }
+
+  template <typename... U>
+  void Invoke(const char* name, U&&... u) const {
+    if (m_callbacks) {
+      for (auto&& cb : *m_callbacks) {
+        reinterpret_cast<CallbackFunction>(cb.callback)(name, cb.param,
+                                                        std::forward<U>(u)...);
+      }
+    }
+  }
+
+  template <typename... U>
+  LLVM_ATTRIBUTE_ALWAYS_INLINE void operator()(U&&... u) const {
+    return Invoke(std::forward<U>(u)...);
+  }
+
+ private:
+  std::unique_ptr<CallbackVector> m_callbacks;
+};
+
+template <typename CallbackFunction>
+class SimPrefixCallbackRegistry {
+  struct CallbackData {
+    CallbackData() = default;
+    CallbackData(const char* prefix_, void* param_, CallbackFunction callback_)
+        : prefix{prefix_}, callback{callback_}, param{param_} {}
+    std::string prefix;
+    CallbackFunction callback;
+    void* param;
+
+    explicit operator bool() const { return callback != nullptr; }
+  };
+  using CallbackVector = wpi::UidVector<CallbackData, 4>;
+
+ public:
+  void Cancel(int32_t uid) {
+    if (m_callbacks) m_callbacks->erase(uid - 1);
+  }
+
+  void Reset() {
+    if (m_callbacks) m_callbacks->clear();
+  }
+
+  int32_t Register(const char* prefix, void* param, CallbackFunction callback) {
+    // Must return -1 on a null callback for error handling
+    if (callback == nullptr) return -1;
+    if (!m_callbacks) m_callbacks = std::make_unique<CallbackVector>();
+    return m_callbacks->emplace_back(prefix, param, callback) + 1;
+  }
+
+  template <typename... U>
+  void Invoke(const char* name, U&&... u) const {
+    if (m_callbacks) {
+      for (auto&& cb : *m_callbacks) {
+        if (wpi::StringRef{name}.startswith(cb.prefix)) {
+          cb.callback(name, cb.param, std::forward<U>(u)...);
+        }
+      }
+    }
+  }
+
+  template <typename... U>
+  LLVM_ATTRIBUTE_ALWAYS_INLINE void operator()(U&&... u) const {
+    return Invoke(std::forward<U>(u)...);
+  }
+
+ private:
+  std::unique_ptr<CallbackVector> m_callbacks;
+};
+
+}  // namespace impl
+
+class SimDeviceData {
+ private:
+  struct Value {
+    Value(const char* name_, bool readonly_, const HAL_Value& value_)
+        : name{name_}, readonly{readonly_}, value{value_} {}
+
+    HAL_SimValueHandle handle{0};
+    std::string name;
+    bool readonly;
+    HAL_Value value;
+    std::vector<std::string> enumOptions;
+    std::vector<const char*> cstrEnumOptions;
+    impl::SimUnnamedCallbackRegistry<HALSIM_SimValueCallback> changed;
+  };
+
+  struct Device {
+    explicit Device(const char* name_) : name{name_} {}
+
+    HAL_SimDeviceHandle handle{0};
+    std::string name;
+    wpi::UidVector<std::unique_ptr<Value>, 16> values;
+    wpi::StringMap<Value*> valueMap;
+    impl::SimUnnamedCallbackRegistry<HALSIM_SimValueCallback> valueCreated;
+  };
+
+  wpi::UidVector<std::shared_ptr<Device>, 4> m_devices;
+  wpi::StringMap<std::weak_ptr<Device>> m_deviceMap;
+
+  wpi::recursive_spinlock m_mutex;
+
+  impl::SimPrefixCallbackRegistry<HALSIM_SimDeviceCallback> m_deviceCreated;
+  impl::SimPrefixCallbackRegistry<HALSIM_SimDeviceCallback> m_deviceFreed;
+
+  // call with lock held, returns null if does not exist
+  Device* LookupDevice(HAL_SimDeviceHandle handle);
+  Value* LookupValue(HAL_SimValueHandle handle);
+
+ public:
+  HAL_SimDeviceHandle CreateDevice(const char* name);
+  void FreeDevice(HAL_SimDeviceHandle handle);
+  HAL_SimValueHandle CreateValue(HAL_SimDeviceHandle device, const char* name,
+                                 bool readonly, int32_t numOptions,
+                                 const char** options,
+                                 const HAL_Value& initialValue);
+  HAL_Value GetValue(HAL_SimValueHandle handle);
+  void SetValue(HAL_SimValueHandle handle, const HAL_Value& value);
+
+  int32_t RegisterDeviceCreatedCallback(const char* prefix, void* param,
+                                        HALSIM_SimDeviceCallback callback,
+                                        bool initialNotify);
+
+  void CancelDeviceCreatedCallback(int32_t uid);
+
+  int32_t RegisterDeviceFreedCallback(const char* prefix, void* param,
+                                      HALSIM_SimDeviceCallback callback);
+
+  void CancelDeviceFreedCallback(int32_t uid);
+
+  HAL_SimDeviceHandle GetDeviceHandle(const char* name);
+  const char* GetDeviceName(HAL_SimDeviceHandle handle);
+
+  void EnumerateDevices(const char* prefix, void* param,
+                        HALSIM_SimDeviceCallback callback);
+
+  int32_t RegisterValueCreatedCallback(HAL_SimDeviceHandle device, void* param,
+                                       HALSIM_SimValueCallback callback,
+                                       bool initialNotify);
+
+  void CancelValueCreatedCallback(int32_t uid);
+
+  int32_t RegisterValueChangedCallback(HAL_SimValueHandle handle, void* param,
+                                       HALSIM_SimValueCallback callback,
+                                       bool initialNotify);
+
+  void CancelValueChangedCallback(int32_t uid);
+
+  HAL_SimValueHandle GetValueHandle(HAL_SimDeviceHandle device,
+                                    const char* name);
+
+  void EnumerateValues(HAL_SimDeviceHandle device, void* param,
+                       HALSIM_SimValueCallback callback);
+
+  const char** GetValueEnumOptions(HAL_SimValueHandle handle,
+                                   int32_t* numOptions);
+
+  void ResetData();
+};
+extern SimDeviceData* SimSimDeviceData;
+}  // namespace hal