Squashed 'third_party/allwpilib_2019/' content from commit bd05dfa1c

Change-Id: I2b1c2250cdb9b055133780c33593292098c375b7
git-subtree-dir: third_party/allwpilib_2019
git-subtree-split: bd05dfa1c7cca74c4fac451e7b9d6a37e7b53447
diff --git a/hal/src/dev/java/DevMain.java b/hal/src/dev/java/DevMain.java
new file mode 100644
index 0000000..8cdb8ba
--- /dev/null
+++ b/hal/src/dev/java/DevMain.java
@@ -0,0 +1,15 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+public final class DevMain {
+  public static void main(String[] args) {
+
+  }
+
+  private DevMain() {
+  }
+}
diff --git a/hal/src/dev/native/cpp/main.cpp b/hal/src/dev/native/cpp/main.cpp
new file mode 100644
index 0000000..6bfa3df
--- /dev/null
+++ b/hal/src/dev/native/cpp/main.cpp
@@ -0,0 +1,15 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <iostream>
+
+#include "hal/HAL.h"
+
+int main() {
+  std::cout << "Hello World" << std::endl;
+  std::cout << HAL_GetRuntimeType() << std::endl;
+}
diff --git a/hal/src/generate/FRCNetComm.java.in b/hal/src/generate/FRCNetComm.java.in
new file mode 100644
index 0000000..af49407
--- /dev/null
+++ b/hal/src/generate/FRCNetComm.java.in
@@ -0,0 +1,33 @@
+/*

+ * Autogenerated file! Do not manually edit this file.

+ */

+

+package edu.wpi.first.hal;

+

+/**

+ * JNI wrapper for library <b>FRC_NetworkCommunication</b><br>.

+ */

+@SuppressWarnings({"MethodName", "LineLength"})

+public class FRCNetComm {

+  /**

+   * Resource type from UsageReporting.

+   */

+  @SuppressWarnings({"TypeName", "PMD.ConstantsInInterface"})

+  public static final class tResourceType {

+    private tResourceType() {

+    }

+

+${usage_reporting_types}

+  }

+

+  /**

+   * Instances from UsageReporting.

+   */

+  @SuppressWarnings({"TypeName", "PMD.ConstantsInInterface"})

+  public static final class tInstances {

+    private tInstances() {

+    }

+

+${usage_reporting_instances}

+  }

+}

diff --git a/hal/src/generate/FRCUsageReporting.h.in b/hal/src/generate/FRCUsageReporting.h.in
new file mode 100644
index 0000000..7cf8128
--- /dev/null
+++ b/hal/src/generate/FRCUsageReporting.h.in
@@ -0,0 +1,14 @@
+#pragma once

+

+/*

+ * Autogenerated file! Do not manually edit this file.

+ */

+

+namespace HALUsageReporting {

+  typedef enum {

+${usage_reporting_types_cpp}

+  } tResourceType;

+  typedef enum {

+${usage_reporting_instances_cpp}

+  } tInstances;

+}

diff --git a/hal/src/generate/Instances.txt b/hal/src/generate/Instances.txt
new file mode 100644
index 0000000..25fc463
--- /dev/null
+++ b/hal/src/generate/Instances.txt
@@ -0,0 +1,44 @@
+kLanguage_LabVIEW = 1

+kLanguage_CPlusPlus = 2

+kLanguage_Java = 3

+kLanguage_Python = 4

+kLanguage_DotNet = 5

+kCANPlugin_BlackJagBridge = 1

+kCANPlugin_2CAN = 2

+kFramework_Iterative = 1

+kFramework_Simple = 2

+kFramework_CommandControl = 3

+kFramework_Timed = 4

+kFramework_ROS = 5

+kFramework_RobotBuilder = 6

+kRobotDrive_ArcadeStandard = 1

+kRobotDrive_ArcadeButtonSpin = 2

+kRobotDrive_ArcadeRatioCurve = 3

+kRobotDrive_Tank = 4

+kRobotDrive_MecanumPolar = 5

+kRobotDrive_MecanumCartesian = 6

+kRobotDrive2_DifferentialArcade = 7

+kRobotDrive2_DifferentialTank = 8

+kRobotDrive2_DifferentialCurvature = 9

+kRobotDrive2_MecanumCartesian = 10

+kRobotDrive2_MecanumPolar = 11

+kRobotDrive2_KilloughCartesian = 12

+kRobotDrive2_KilloughPolar = 13

+kDriverStationCIO_Analog = 1

+kDriverStationCIO_DigitalIn = 2

+kDriverStationCIO_DigitalOut = 3

+kDriverStationEIO_Acceleration = 1

+kDriverStationEIO_AnalogIn = 2

+kDriverStationEIO_AnalogOut = 3

+kDriverStationEIO_Button = 4

+kDriverStationEIO_LED = 5

+kDriverStationEIO_DigitalIn = 6

+kDriverStationEIO_DigitalOut = 7

+kDriverStationEIO_FixedDigitalOut = 8

+kDriverStationEIO_PWM = 9

+kDriverStationEIO_Encoder = 10

+kDriverStationEIO_TouchSlider = 11

+kADXL345_SPI = 1

+kADXL345_I2C = 2

+kCommand_Scheduler = 1

+kSmartDashboard_Instance = 1

diff --git a/hal/src/generate/ResourceType.txt b/hal/src/generate/ResourceType.txt
new file mode 100644
index 0000000..b8699b0
--- /dev/null
+++ b/hal/src/generate/ResourceType.txt
@@ -0,0 +1,85 @@
+kResourceType_Controller = 0

+kResourceType_Module = 1

+kResourceType_Language = 2

+kResourceType_CANPlugin = 3

+kResourceType_Accelerometer = 4

+kResourceType_ADXL345 = 5

+kResourceType_AnalogChannel = 6

+kResourceType_AnalogTrigger = 7

+kResourceType_AnalogTriggerOutput = 8

+kResourceType_CANJaguar = 9

+kResourceType_Compressor = 10

+kResourceType_Counter = 11

+kResourceType_Dashboard = 12

+kResourceType_DigitalInput = 13

+kResourceType_DigitalOutput = 14

+kResourceType_DriverStationCIO = 15

+kResourceType_DriverStationEIO = 16

+kResourceType_DriverStationLCD = 17

+kResourceType_Encoder = 18

+kResourceType_GearTooth = 19

+kResourceType_Gyro = 20

+kResourceType_I2C = 21

+kResourceType_Framework = 22

+kResourceType_Jaguar = 23

+kResourceType_Joystick = 24

+kResourceType_Kinect = 25

+kResourceType_KinectStick = 26

+kResourceType_PIDController = 27

+kResourceType_Preferences = 28

+kResourceType_PWM = 29

+kResourceType_Relay = 30

+kResourceType_RobotDrive = 31

+kResourceType_SerialPort = 32

+kResourceType_Servo = 33

+kResourceType_Solenoid = 34

+kResourceType_SPI = 35

+kResourceType_Task = 36

+kResourceType_Ultrasonic = 37

+kResourceType_Victor = 38

+kResourceType_Button = 39

+kResourceType_Command = 40

+kResourceType_AxisCamera = 41

+kResourceType_PCVideoServer = 42

+kResourceType_SmartDashboard = 43

+kResourceType_Talon = 44

+kResourceType_HiTechnicColorSensor = 45

+kResourceType_HiTechnicAccel = 46

+kResourceType_HiTechnicCompass = 47

+kResourceType_SRF08 = 48

+kResourceType_AnalogOutput = 49

+kResourceType_VictorSP = 50

+kResourceType_PWMTalonSRX = 51

+kResourceType_CANTalonSRX = 52

+kResourceType_ADXL362 = 53

+kResourceType_ADXRS450 = 54

+kResourceType_RevSPARK = 55

+kResourceType_MindsensorsSD540 = 56

+kResourceType_DigitalGlitchFilter = 57

+kResourceType_ADIS16448 = 58

+kResourceType_PDP = 59

+kResourceType_PCM = 60

+kResourceType_PigeonIMU = 61

+kResourceType_NidecBrushless = 62

+kResourceType_CANifier = 63

+kResourceType_CTRE_future0 = 64

+kResourceType_CTRE_future1 = 65

+kResourceType_CTRE_future2 = 66

+kResourceType_CTRE_future3 = 67

+kResourceType_CTRE_future4 = 68

+kResourceType_CTRE_future5 = 69

+kResourceType_CTRE_future6 = 70

+kResourceType_LinearFilter = 71

+kResourceType_XboxController = 72

+kResourceType_UsbCamera = 73

+kResourceType_NavX = 74

+kResourceType_Pixy = 75

+kResourceType_Pixy2 = 76

+kResourceType_ScanseSweep = 77

+kResourceType_Shuffleboard = 78

+kResourceType_CAN = 79

+kResourceType_DigilentDMC60 = 80

+kResourceType_PWMVictorSPX = 81

+kResourceType_RevSparkMaxPWM = 82

+kResourceType_RevSparkMaxCAN = 83

+kResourceType_ADIS16470 = 84

diff --git a/hal/src/main/java/edu/wpi/first/hal/AccelerometerJNI.java b/hal/src/main/java/edu/wpi/first/hal/AccelerometerJNI.java
new file mode 100644
index 0000000..e1e3750
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/AccelerometerJNI.java
@@ -0,0 +1,20 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class AccelerometerJNI extends JNIWrapper {
+  public static native void setAccelerometerActive(boolean active);
+
+  public static native void setAccelerometerRange(int range);
+
+  public static native double getAccelerometerX();
+
+  public static native double getAccelerometerY();
+
+  public static native double getAccelerometerZ();
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/AccumulatorResult.java b/hal/src/main/java/edu/wpi/first/hal/AccumulatorResult.java
new file mode 100644
index 0000000..d3aa8c8
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/AccumulatorResult.java
@@ -0,0 +1,32 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+/**
+ * Structure for holding the values stored in an accumulator.
+ */
+public class AccumulatorResult {
+  /**
+   * The total value accumulated.
+   */
+  @SuppressWarnings("MemberName")
+  public long value;
+  /**
+   * The number of sample value was accumulated over.
+   */
+  @SuppressWarnings("MemberName")
+  public long count;
+
+  /**
+   * Set the value and count.
+   */
+  public void set(long value, long count) {
+    this.value = value;
+    this.count = count;
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/AllianceStationID.java b/hal/src/main/java/edu/wpi/first/hal/AllianceStationID.java
new file mode 100644
index 0000000..148dd76
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/AllianceStationID.java
@@ -0,0 +1,12 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public enum AllianceStationID {
+  Red1, Red2, Red3, Blue1, Blue2, Blue3
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/AnalogGyroJNI.java b/hal/src/main/java/edu/wpi/first/hal/AnalogGyroJNI.java
new file mode 100644
index 0000000..332be79
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/AnalogGyroJNI.java
@@ -0,0 +1,37 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class AnalogGyroJNI extends JNIWrapper {
+  public static native int initializeAnalogGyro(int halAnalogInputHandle);
+
+  public static native void setupAnalogGyro(int handle);
+
+  public static native void freeAnalogGyro(int handle);
+
+  public static native void setAnalogGyroParameters(int handle,
+                                                    double voltsPerDegreePerSecond,
+                                                    double offset, int center);
+
+  public static native void setAnalogGyroVoltsPerDegreePerSecond(int handle,
+                                                                 double voltsPerDegreePerSecond);
+
+  public static native void resetAnalogGyro(int handle);
+
+  public static native void calibrateAnalogGyro(int handle);
+
+  public static native void setAnalogGyroDeadband(int handle, double volts);
+
+  public static native double getAnalogGyroAngle(int handle);
+
+  public static native double getAnalogGyroRate(int handle);
+
+  public static native double getAnalogGyroOffset(int handle);
+
+  public static native int getAnalogGyroCenter(int handle);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/AnalogJNI.java b/hal/src/main/java/edu/wpi/first/hal/AnalogJNI.java
new file mode 100644
index 0000000..3e78039
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/AnalogJNI.java
@@ -0,0 +1,116 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+import java.nio.IntBuffer;
+
+public class AnalogJNI extends JNIWrapper {
+  /**
+   * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:58</i><br> enum values
+   */
+  public interface AnalogTriggerType {
+    /**
+     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:54</i>
+     */
+    int kInWindow = 0;
+    /**
+     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:55</i>
+     */
+    int kState = 1;
+    /**
+     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:56</i>
+     */
+    int kRisingPulse = 2;
+    /**
+     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:57</i>
+     */
+    int kFallingPulse = 3;
+  }
+
+  public static native int initializeAnalogInputPort(int halPortHandle);
+
+  public static native void freeAnalogInputPort(int portHandle);
+
+  public static native int initializeAnalogOutputPort(int halPortHandle);
+
+  public static native void freeAnalogOutputPort(int portHandle);
+
+  public static native boolean checkAnalogModule(byte module);
+
+  public static native boolean checkAnalogInputChannel(int channel);
+
+  public static native boolean checkAnalogOutputChannel(int channel);
+
+  public static native void setAnalogOutput(int portHandle, double voltage);
+
+  public static native double getAnalogOutput(int portHandle);
+
+  public static native void setAnalogSampleRate(double samplesPerSecond);
+
+  public static native double getAnalogSampleRate();
+
+  public static native void setAnalogAverageBits(int analogPortHandle, int bits);
+
+  public static native int getAnalogAverageBits(int analogPortHandle);
+
+  public static native void setAnalogOversampleBits(int analogPortHandle, int bits);
+
+  public static native int getAnalogOversampleBits(int analogPortHandle);
+
+  public static native short getAnalogValue(int analogPortHandle);
+
+  public static native int getAnalogAverageValue(int analogPortHandle);
+
+  public static native int getAnalogVoltsToValue(int analogPortHandle, double voltage);
+
+  public static native double getAnalogVoltage(int analogPortHandle);
+
+  public static native double getAnalogAverageVoltage(int analogPortHandle);
+
+  public static native int getAnalogLSBWeight(int analogPortHandle);
+
+  public static native int getAnalogOffset(int analogPortHandle);
+
+  public static native boolean isAccumulatorChannel(int analogPortHandle);
+
+  public static native void initAccumulator(int analogPortHandle);
+
+  public static native void resetAccumulator(int analogPortHandle);
+
+  public static native void setAccumulatorCenter(int analogPortHandle, int center);
+
+  public static native void setAccumulatorDeadband(int analogPortHandle, int deadband);
+
+  public static native long getAccumulatorValue(int analogPortHandle);
+
+  public static native int getAccumulatorCount(int analogPortHandle);
+
+  public static native void getAccumulatorOutput(int analogPortHandle, AccumulatorResult result);
+
+  public static native int initializeAnalogTrigger(int analogInputHandle, IntBuffer index);
+
+  public static native void cleanAnalogTrigger(int analogTriggerHandle);
+
+  public static native void setAnalogTriggerLimitsRaw(int analogTriggerHandle, int lower,
+                                                      int upper);
+
+  public static native void setAnalogTriggerLimitsVoltage(int analogTriggerHandle,
+                                                          double lower, double upper);
+
+  public static native void setAnalogTriggerAveraged(int analogTriggerHandle,
+                                                     boolean useAveragedValue);
+
+  public static native void setAnalogTriggerFiltered(int analogTriggerHandle,
+                                                     boolean useFilteredValue);
+
+  public static native boolean getAnalogTriggerInWindow(int analogTriggerHandle);
+
+  public static native boolean getAnalogTriggerTriggerState(int analogTriggerHandle);
+
+  public static native boolean getAnalogTriggerOutput(int analogTriggerHandle, int type);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java b/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java
new file mode 100644
index 0000000..1ac3ca7
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java
@@ -0,0 +1,32 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class CANAPIJNI extends JNIWrapper {
+  public static native int initializeCAN(int manufacturer, int deviceId, int deviceType);
+
+  public static native void cleanCAN(int handle);
+
+  public static native void writeCANPacket(int handle, byte[] data, int apiId);
+
+  public static native void writeCANPacketRepeating(int handle, byte[] data, int apiId,
+                                                    int repeatMs);
+
+  public static native void stopCANPacketRepeating(int handle, int apiId);
+
+  public static native boolean readCANPacketNew(int handle, int apiId, CANData data);
+
+  public static native boolean readCANPacketLatest(int handle, int apiId, CANData data);
+
+  public static native boolean readCANPacketTimeout(int handle, int apiId, int timeoutMs,
+                                                 CANData data);
+
+  public static native boolean readCANPeriodicPacket(int handle, int apiId, int timeoutMs,
+                                                  int periodMs, CANData data);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/CANData.java b/hal/src/main/java/edu/wpi/first/hal/CANData.java
new file mode 100644
index 0000000..23d37c9
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/CANData.java
@@ -0,0 +1,27 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class CANData {
+  @SuppressWarnings("MemberName")
+  public final byte[] data = new byte[8];
+  @SuppressWarnings("MemberName")
+  public int length;
+  @SuppressWarnings("MemberName")
+  public long timestamp;
+
+  /**
+   * API used from JNI to set the data.
+   */
+  @SuppressWarnings("PMD.MethodReturnsInternalArray")
+  public byte[] setData(int length, long timestamp) {
+    this.length = length;
+    this.timestamp = timestamp;
+    return data;
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/CompressorJNI.java b/hal/src/main/java/edu/wpi/first/hal/CompressorJNI.java
new file mode 100644
index 0000000..64e9e1d
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/CompressorJNI.java
@@ -0,0 +1,38 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class CompressorJNI extends JNIWrapper {
+  public static native int initializeCompressor(byte module);
+
+  public static native boolean checkCompressorModule(byte module);
+
+  public static native boolean getCompressor(int compressorHandle);
+
+  public static native void setCompressorClosedLoopControl(int compressorHandle, boolean value);
+
+  public static native boolean getCompressorClosedLoopControl(int compressorHandle);
+
+  public static native boolean getCompressorPressureSwitch(int compressorHandle);
+
+  public static native double getCompressorCurrent(int compressorHandle);
+
+  public static native boolean getCompressorCurrentTooHighFault(int compressorHandle);
+
+  public static native boolean getCompressorCurrentTooHighStickyFault(int compressorHandle);
+
+  public static native boolean getCompressorShortedStickyFault(int compressorHandle);
+
+  public static native boolean getCompressorShortedFault(int compressorHandle);
+
+  public static native boolean getCompressorNotConnectedStickyFault(int compressorHandle);
+
+  public static native boolean getCompressorNotConnectedFault(int compressorHandle);
+
+  public static native void clearAllPCMStickyFaults(byte compressorModule);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/ConstantsJNI.java b/hal/src/main/java/edu/wpi/first/hal/ConstantsJNI.java
new file mode 100644
index 0000000..3db75f5
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/ConstantsJNI.java
@@ -0,0 +1,12 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class ConstantsJNI extends JNIWrapper {
+  public static native int getSystemClockTicksPerMicrosecond();
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/ControlWord.java b/hal/src/main/java/edu/wpi/first/hal/ControlWord.java
new file mode 100644
index 0000000..8353606
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/ControlWord.java
@@ -0,0 +1,54 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+/**
+ * A wrapper for the HALControlWord bitfield.
+ */
+public class ControlWord {
+  private boolean m_enabled;
+  private boolean m_autonomous;
+  private boolean m_test;
+  private boolean m_emergencyStop;
+  private boolean m_fmsAttached;
+  private boolean m_dsAttached;
+
+  void update(boolean enabled, boolean autonomous, boolean test, boolean emergencyStop,
+              boolean fmsAttached, boolean dsAttached) {
+    m_enabled = enabled;
+    m_autonomous = autonomous;
+    m_test = test;
+    m_emergencyStop = emergencyStop;
+    m_fmsAttached = fmsAttached;
+    m_dsAttached = dsAttached;
+  }
+
+  public boolean getEnabled() {
+    return m_enabled;
+  }
+
+  public boolean getAutonomous() {
+    return m_autonomous;
+  }
+
+  public boolean getTest() {
+    return m_test;
+  }
+
+  public boolean getEStop() {
+    return m_emergencyStop;
+  }
+
+  public boolean getFMSAttached() {
+    return m_fmsAttached;
+  }
+
+  public boolean getDSAttached() {
+    return m_dsAttached;
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/CounterJNI.java b/hal/src/main/java/edu/wpi/first/hal/CounterJNI.java
new file mode 100644
index 0000000..b7935d6
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/CounterJNI.java
@@ -0,0 +1,65 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+import java.nio.IntBuffer;
+
+public class CounterJNI extends JNIWrapper {
+  public static native int initializeCounter(int mode, IntBuffer index);
+
+  public static native void freeCounter(int counterHandle);
+
+  public static native void setCounterAverageSize(int counterHandle, int size);
+
+  public static native void setCounterUpSource(int counterHandle, int digitalSourceHandle,
+                                               int analogTriggerType);
+
+  public static native void setCounterUpSourceEdge(int counterHandle, boolean risingEdge,
+                                                   boolean fallingEdge);
+
+  public static native void clearCounterUpSource(int counterHandle);
+
+  public static native void setCounterDownSource(int counterHandle, int digitalSourceHandle,
+                                                 int analogTriggerType);
+
+  public static native void setCounterDownSourceEdge(int counterHandle, boolean risingEdge,
+                                                     boolean fallingEdge);
+
+  public static native void clearCounterDownSource(int counterHandle);
+
+  public static native void setCounterUpDownMode(int counterHandle);
+
+  public static native void setCounterExternalDirectionMode(int counterHandle);
+
+  public static native void setCounterSemiPeriodMode(int counterHandle,
+                                                     boolean highSemiPeriod);
+
+  public static native void setCounterPulseLengthMode(int counterHandle, double threshold);
+
+  public static native int getCounterSamplesToAverage(int counterHandle);
+
+  public static native void setCounterSamplesToAverage(int counterHandle,
+                                                       int samplesToAverage);
+
+  public static native void resetCounter(int counterHandle);
+
+  public static native int getCounter(int counterHandle);
+
+  public static native double getCounterPeriod(int counterHandle);
+
+  public static native void setCounterMaxPeriod(int counterHandle, double maxPeriod);
+
+  public static native void setCounterUpdateWhenEmpty(int counterHandle, boolean enabled);
+
+  public static native boolean getCounterStopped(int counterHandle);
+
+  public static native boolean getCounterDirection(int counterHandle);
+
+  public static native void setCounterReverseDirection(int counterHandle,
+                                                       boolean reverseDirection);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java b/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java
new file mode 100644
index 0000000..b9c11a5
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class DIOJNI extends JNIWrapper {
+  public static native int initializeDIOPort(int halPortHandle, boolean input);
+
+  public static native boolean checkDIOChannel(int channel);
+
+  public static native void freeDIOPort(int dioPortHandle);
+
+  // TODO(Thad): Switch this to use boolean
+  public static native void setDIO(int dioPortHandle, short value);
+
+  public static native void setDIODirection(int dioPortHandle, boolean input);
+
+  public static native boolean getDIO(int dioPortHandle);
+
+  public static native boolean getDIODirection(int dioPortHandle);
+
+  public static native void pulse(int dioPortHandle, double pulseLength);
+
+  public static native boolean isPulsing(int dioPortHandle);
+
+  public static native boolean isAnyPulsing();
+
+  public static native short getLoopTiming();
+
+  public static native int allocateDigitalPWM();
+
+  public static native void freeDigitalPWM(int pwmGenerator);
+
+  public static native void setDigitalPWMRate(double rate);
+
+  public static native void setDigitalPWMDutyCycle(int pwmGenerator, double dutyCycle);
+
+  public static native void setDigitalPWMOutputChannel(int pwmGenerator, int channel);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/DigitalGlitchFilterJNI.java b/hal/src/main/java/edu/wpi/first/hal/DigitalGlitchFilterJNI.java
new file mode 100644
index 0000000..aa818cf
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/DigitalGlitchFilterJNI.java
@@ -0,0 +1,18 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class DigitalGlitchFilterJNI extends JNIWrapper {
+  public static native void setFilterSelect(int digitalPortHandle, int filterIndex);
+
+  public static native int getFilterSelect(int digitalPortHandle);
+
+  public static native void setFilterPeriod(int filterIndex, int fpgaCycles);
+
+  public static native int getFilterPeriod(int filterIndex);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/EncoderJNI.java b/hal/src/main/java/edu/wpi/first/hal/EncoderJNI.java
new file mode 100644
index 0000000..082b6d9
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/EncoderJNI.java
@@ -0,0 +1,62 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class EncoderJNI extends JNIWrapper {
+  public static native int initializeEncoder(int digitalSourceHandleA, int analogTriggerTypeA,
+                                             int digitalSourceHandleB, int analogTriggerTypeB,
+                                             boolean reverseDirection, int encodingType);
+
+  public static native void freeEncoder(int encoderHandle);
+
+  public static native int getEncoder(int encoderHandle);
+
+  public static native int getEncoderRaw(int encoderHandle);
+
+  public static native int getEncodingScaleFactor(int encoderHandle);
+
+  public static native void resetEncoder(int encoderHandle);
+
+  public static native double getEncoderPeriod(int encoderHandle);
+
+  public static native void setEncoderMaxPeriod(int encoderHandle, double maxPeriod);
+
+  public static native boolean getEncoderStopped(int encoderHandle);
+
+  public static native boolean getEncoderDirection(int encoderHandle);
+
+  public static native double getEncoderDistance(int encoderHandle);
+
+  public static native double getEncoderRate(int encoderHandle);
+
+  public static native void setEncoderMinRate(int encoderHandle, double minRate);
+
+  public static native void setEncoderDistancePerPulse(int encoderHandle, double distancePerPulse);
+
+  public static native void setEncoderReverseDirection(int encoderHandle,
+                                                       boolean reverseDirection);
+
+  public static native void setEncoderSamplesToAverage(int encoderHandle,
+                                                       int samplesToAverage);
+
+  public static native int getEncoderSamplesToAverage(int encoderHandle);
+
+  public static native void setEncoderIndexSource(int encoderHandle, int digitalSourceHandle,
+                                                  int analogTriggerType, int indexingType);
+
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public static native int getEncoderFPGAIndex(int encoderHandle);
+
+  public static native int getEncoderEncodingScale(int encoderHandle);
+
+  public static native double getEncoderDecodingScaleFactor(int encoderHandle);
+
+  public static native double getEncoderDistancePerPulse(int encoderHandle);
+
+  public static native int getEncoderEncodingType(int encoderHandle);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/HAL.java b/hal/src/main/java/edu/wpi/first/hal/HAL.java
new file mode 100644
index 0000000..a298ff6
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/HAL.java
@@ -0,0 +1,134 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+import java.nio.ByteBuffer;
+
+/**
+ * JNI Wrapper for HAL<br>.
+ */
+@SuppressWarnings({"AbbreviationAsWordInName", "MethodName", "PMD.TooManyMethods"})
+public final class HAL extends JNIWrapper {
+  public static native void waitForDSData();
+
+  public static native boolean initialize(int timeout, int mode);
+
+  public static native void observeUserProgramStarting();
+
+  public static native void observeUserProgramDisabled();
+
+  public static native void observeUserProgramAutonomous();
+
+  public static native void observeUserProgramTeleop();
+
+  public static native void observeUserProgramTest();
+
+  public static void report(int resource, int instanceNumber) {
+    report(resource, instanceNumber, 0, "");
+  }
+
+  public static void report(int resource, int instanceNumber, int context) {
+    report(resource, instanceNumber, context, "");
+  }
+
+  /**
+   * Report the usage of a resource of interest. <br>
+   *
+   * <p>Original signature: <code>uint32_t report(tResourceType, uint8_t, uint8_t, const
+   * char*)</code>
+   *
+   * @param resource       one of the values in the tResourceType above (max value 51). <br>
+   * @param instanceNumber an index that identifies the resource instance. <br>
+   * @param context        an optional additional context number for some cases (such as module
+   *                       number). Set to 0 to omit. <br>
+   * @param feature        a string to be included describing features in use on a specific
+   *                       resource. Setting the same resource more than once allows you to change
+   *                       the feature string.
+   */
+  public static native int report(int resource, int instanceNumber, int context, String feature);
+
+  public static native int nativeGetControlWord();
+
+  @SuppressWarnings("JavadocMethod")
+  public static void getControlWord(ControlWord controlWord) {
+    int word = nativeGetControlWord();
+    controlWord.update((word & 1) != 0, ((word >> 1) & 1) != 0, ((word >> 2) & 1) != 0,
+        ((word >> 3) & 1) != 0, ((word >> 4) & 1) != 0, ((word >> 5) & 1) != 0);
+  }
+
+  private static native int nativeGetAllianceStation();
+
+  @SuppressWarnings("JavadocMethod")
+  public static AllianceStationID getAllianceStation() {
+    switch (nativeGetAllianceStation()) {
+      case 0:
+        return AllianceStationID.Red1;
+      case 1:
+        return AllianceStationID.Red2;
+      case 2:
+        return AllianceStationID.Red3;
+      case 3:
+        return AllianceStationID.Blue1;
+      case 4:
+        return AllianceStationID.Blue2;
+      case 5:
+        return AllianceStationID.Blue3;
+      default:
+        return null;
+    }
+  }
+
+  @SuppressWarnings("JavadocMethod")
+  public static native boolean isNewControlData();
+
+  @SuppressWarnings("JavadocMethod")
+  public static native void releaseDSMutex();
+
+  @SuppressWarnings("JavadocMethod")
+  public static native boolean waitForDSDataTimeout(double timeout);
+
+  public static int kMaxJoystickAxes = 12;
+  public static int kMaxJoystickPOVs = 12;
+
+  public static native short getJoystickAxes(byte joystickNum, float[] axesArray);
+
+  public static native short getJoystickPOVs(byte joystickNum, short[] povsArray);
+
+  public static native int getJoystickButtons(byte joystickNum, ByteBuffer count);
+
+  public static native int setJoystickOutputs(byte joystickNum, int outputs, short leftRumble,
+                                              short rightRumble);
+
+  public static native int getJoystickIsXbox(byte joystickNum);
+
+  public static native int getJoystickType(byte joystickNum);
+
+  public static native String getJoystickName(byte joystickNum);
+
+  public static native int getJoystickAxisType(byte joystickNum, byte axis);
+
+  public static native double getMatchTime();
+
+  public static native boolean getSystemActive();
+
+  public static native boolean getBrownedOut();
+
+  public static native int getMatchInfo(MatchInfoData info);
+
+  public static native int sendError(boolean isError, int errorCode, boolean isLVCode,
+                                     String details, String location, String callStack,
+                                     boolean printMsg);
+
+  public static native int getPortWithModule(byte module, byte channel);
+
+  public static native int getPort(byte channel);
+
+  private HAL() {
+
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/HALUtil.java b/hal/src/main/java/edu/wpi/first/hal/HALUtil.java
new file mode 100644
index 0000000..0e5fe21
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/HALUtil.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public final class HALUtil extends JNIWrapper {
+  public static final int NULL_PARAMETER = -1005;
+  public static final int SAMPLE_RATE_TOO_HIGH = 1001;
+  public static final int VOLTAGE_OUT_OF_RANGE = 1002;
+  public static final int LOOP_TIMING_ERROR = 1004;
+  public static final int INCOMPATIBLE_STATE = 1015;
+  public static final int ANALOG_TRIGGER_PULSE_OUTPUT_ERROR = -1011;
+  public static final int NO_AVAILABLE_RESOURCES = -104;
+  public static final int PARAMETER_OUT_OF_RANGE = -1028;
+
+  public static native short getFPGAVersion();
+
+  public static native int getFPGARevision();
+
+  public static native long getFPGATime();
+
+  public static native int getHALRuntimeType();
+
+  public static native boolean getFPGAButton();
+
+  public static native String getHALErrorMessage(int code);
+
+  public static native int getHALErrno();
+
+  public static native String getHALstrerror(int errno);
+
+  public static String getHALstrerror() {
+    return getHALstrerror(getHALErrno());
+  }
+
+  private HALUtil() {
+
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/I2CJNI.java b/hal/src/main/java/edu/wpi/first/hal/I2CJNI.java
new file mode 100644
index 0000000..12a9af0
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/I2CJNI.java
@@ -0,0 +1,33 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+import java.nio.ByteBuffer;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class I2CJNI extends JNIWrapper {
+  public static native void i2CInitialize(int port);
+
+  public static native int i2CTransaction(int port, byte address, ByteBuffer dataToSend,
+                                          byte sendSize, ByteBuffer dataReceived, byte receiveSize);
+
+  public static native int i2CTransactionB(int port, byte address, byte[] dataToSend,
+                                           byte sendSize, byte[] dataReceived, byte receiveSize);
+
+  public static native int i2CWrite(int port, byte address, ByteBuffer dataToSend, byte sendSize);
+
+  public static native int i2CWriteB(int port, byte address, byte[] dataToSend, byte sendSize);
+
+  public static native int i2CRead(int port, byte address, ByteBuffer dataReceived,
+                                   byte receiveSize);
+
+  public static native int i2CReadB(int port, byte address, byte[] dataReceived,
+                                    byte receiveSize);
+
+  public static native void i2CClose(int port);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java b/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java
new file mode 100644
index 0000000..8574a25
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class InterruptJNI extends JNIWrapper {
+  public static final int HalInvalidHandle = 0;
+
+  public interface InterruptJNIHandlerFunction {
+    void apply(int interruptAssertedMask, Object param);
+  }
+
+  public static native int initializeInterrupts(boolean watcher);
+
+  public static native void cleanInterrupts(int interruptHandle);
+
+  public static native int waitForInterrupt(int interruptHandle, double timeout,
+                                            boolean ignorePrevious);
+
+  public static native void enableInterrupts(int interruptHandle);
+
+  public static native void disableInterrupts(int interruptHandle);
+
+  public static native long readInterruptRisingTimestamp(int interruptHandle);
+
+  public static native long readInterruptFallingTimestamp(int interruptHandle);
+
+  public static native void requestInterrupts(int interruptHandle, int digitalSourceHandle,
+                                              int analogTriggerType);
+
+  public static native void attachInterruptHandler(int interruptHandle,
+                                                   InterruptJNIHandlerFunction handler,
+                                                   Object param);
+
+  public static native void setInterruptUpSourceEdge(int interruptHandle, boolean risingEdge,
+                                                     boolean fallingEdge);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java
new file mode 100644
index 0000000..21342bc
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java
@@ -0,0 +1,34 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+import java.io.IOException;
+
+import edu.wpi.first.wpiutil.RuntimeLoader;
+
+/**
+ * Base class for all JNI wrappers.
+ */
+public class JNIWrapper {
+  static boolean libraryLoaded = false;
+  static RuntimeLoader<JNIWrapper> loader = null;
+
+  static {
+    if (!libraryLoaded) {
+      try {
+        loader = new RuntimeLoader<>("wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
+        loader.loadLibrary();
+      } catch (IOException ex) {
+        ex.printStackTrace();
+        System.exit(1);
+      }
+      libraryLoaded = true;
+      libraryLoaded = true;
+    }
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/MatchInfoData.java b/hal/src/main/java/edu/wpi/first/hal/MatchInfoData.java
new file mode 100644
index 0000000..2f11515
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/MatchInfoData.java
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+/**
+ * Structure for holding the match info data request.
+ */
+public class MatchInfoData {
+  /**
+   * Stores the event name.
+   */
+  @SuppressWarnings("MemberName")
+  public String eventName = "";
+
+  /**
+   * Stores the game specific message.
+   */
+  @SuppressWarnings("MemberName")
+  public String gameSpecificMessage = "";
+
+  /**
+   * Stores the match number.
+   */
+  @SuppressWarnings("MemberName")
+  public int matchNumber;
+
+  /**
+   * Stores the replay number.
+   */
+  @SuppressWarnings("MemberName")
+  public int replayNumber;
+
+  /**
+   * Stores the match type.
+   */
+  @SuppressWarnings("MemberName")
+  public int matchType;
+
+  /**
+   * Called from JNI to set the structure data.
+   */
+  @SuppressWarnings("JavadocMethod")
+  public void setData(String eventName, String gameSpecificMessage,
+                      int matchNumber, int replayNumber, int matchType) {
+    this.eventName = eventName;
+    this.gameSpecificMessage = gameSpecificMessage;
+    this.matchNumber = matchNumber;
+    this.replayNumber = replayNumber;
+    this.matchType = matchType;
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/NotifierJNI.java b/hal/src/main/java/edu/wpi/first/hal/NotifierJNI.java
new file mode 100644
index 0000000..bf92c37
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/NotifierJNI.java
@@ -0,0 +1,49 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+/**
+ * The NotifierJNI class directly wraps the C++ HAL Notifier.
+ *
+ * <p>This class is not meant for direct use by teams. Instead, the edu.wpi.first.wpilibj.Notifier
+ * class, which corresponds to the C++ Notifier class, should be used.
+ */
+public class NotifierJNI extends JNIWrapper {
+  /**
+   * Initializes the notifier.
+   */
+  public static native int initializeNotifier();
+
+  /**
+   * Wakes up the waiter with time=0.  Note: after this function is called, all
+   * calls to waitForNotifierAlarm() will immediately start returning 0.
+   */
+  public static native void stopNotifier(int notifierHandle);
+
+  /**
+   * Deletes the notifier object when we are done with it.
+   */
+  public static native void cleanNotifier(int notifierHandle);
+
+  /**
+   * Sets the notifier to wakeup the waiter in another triggerTime microseconds.
+   */
+  public static native void updateNotifierAlarm(int notifierHandle, long triggerTime);
+
+  /**
+   * Cancels any pending wakeups set by updateNotifierAlarm().  Does NOT wake
+   * up any waiters.
+   */
+  public static native void cancelNotifierAlarm(int notifierHandle);
+
+  /**
+   * Block until woken up by an alarm (or stop).
+   * @return Time when woken up.
+   */
+  public static native long waitForNotifierAlarm(int notifierHandle);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/PDPJNI.java b/hal/src/main/java/edu/wpi/first/hal/PDPJNI.java
new file mode 100644
index 0000000..c45a053
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/PDPJNI.java
@@ -0,0 +1,33 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class PDPJNI extends JNIWrapper {
+  public static native int initializePDP(int module);
+
+  public static native boolean checkPDPModule(int module);
+
+  public static native boolean checkPDPChannel(int channel);
+
+  public static native double getPDPTemperature(int handle);
+
+  public static native double getPDPVoltage(int handle);
+
+  public static native double getPDPChannelCurrent(byte channel, int handle);
+
+  public static native double getPDPTotalCurrent(int handle);
+
+  public static native double getPDPTotalPower(int handle);
+
+  public static native double getPDPTotalEnergy(int handle);
+
+  public static native void resetPDPTotalEnergy(int handle);
+
+  public static native void clearPDPStickyFaults(int handle);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/PWMConfigDataResult.java b/hal/src/main/java/edu/wpi/first/hal/PWMConfigDataResult.java
new file mode 100644
index 0000000..d29b0df
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/PWMConfigDataResult.java
@@ -0,0 +1,51 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+/**
+ * Structure for holding the config data result for PWM.
+ */
+public class PWMConfigDataResult {
+  PWMConfigDataResult(int max, int deadbandMax, int center, int deadbandMin, int min) {
+    this.max = max;
+    this.deadbandMax = deadbandMax;
+    this.center = center;
+    this.deadbandMin = deadbandMin;
+    this.min = min;
+  }
+
+  /**
+   * The maximum PWM value.
+   */
+  @SuppressWarnings("MemberName")
+  public int max;
+
+  /**
+   * The deadband maximum PWM value.
+   */
+  @SuppressWarnings("MemberName")
+  public int deadbandMax;
+
+  /**
+   * The center PWM value.
+   */
+  @SuppressWarnings("MemberName")
+  public int center;
+
+  /**
+   * The deadband minimum PWM value.
+   */
+  @SuppressWarnings("MemberName")
+  public int deadbandMin;
+
+  /**
+   * The minimum PWM value.
+   */
+  @SuppressWarnings("MemberName")
+  public int min;
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/PWMJNI.java b/hal/src/main/java/edu/wpi/first/hal/PWMJNI.java
new file mode 100644
index 0000000..3af6f96
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/PWMJNI.java
@@ -0,0 +1,49 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class PWMJNI extends DIOJNI {
+  public static native int initializePWMPort(int halPortHandle);
+
+  public static native boolean checkPWMChannel(int channel);
+
+  public static native void freePWMPort(int pwmPortHandle);
+
+  public static native void setPWMConfigRaw(int pwmPortHandle, int maxPwm,
+                                            int deadbandMaxPwm, int centerPwm,
+                                            int deadbandMinPwm, int minPwm);
+
+  public static native void setPWMConfig(int pwmPortHandle, double maxPwm,
+                                         double deadbandMaxPwm, double centerPwm,
+                                         double deadbandMinPwm, double minPwm);
+
+  public static native PWMConfigDataResult getPWMConfigRaw(int pwmPortHandle);
+
+  public static native void setPWMEliminateDeadband(int pwmPortHandle, boolean eliminateDeadband);
+
+  public static native boolean getPWMEliminateDeadband(int pwmPortHandle);
+
+  public static native void setPWMRaw(int pwmPortHandle, short value);
+
+  public static native void setPWMSpeed(int pwmPortHandle, double speed);
+
+  public static native void setPWMPosition(int pwmPortHandle, double position);
+
+  public static native short getPWMRaw(int pwmPortHandle);
+
+  public static native double getPWMSpeed(int pwmPortHandle);
+
+  public static native double getPWMPosition(int pwmPortHandle);
+
+  public static native  void setPWMDisabled(int pwmPortHandle);
+
+  public static native void latchPWMZero(int pwmPortHandle);
+
+  public static native void setPWMPeriodScale(int pwmPortHandle, int squelchMask);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/PortsJNI.java b/hal/src/main/java/edu/wpi/first/hal/PortsJNI.java
new file mode 100644
index 0000000..a2ac60b
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/PortsJNI.java
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class PortsJNI extends JNIWrapper {
+  public static native int getNumAccumulators();
+
+  public static native int getNumAnalogTriggers();
+
+  public static native int getNumAnalogInputs();
+
+  public static native int getNumAnalogOutputs();
+
+  public static native int getNumCounters();
+
+  public static native int getNumDigitalHeaders();
+
+  public static native int getNumPWMHeaders();
+
+  public static native int getNumDigitalChannels();
+
+  public static native int getNumPWMChannels();
+
+  public static native int getNumDigitalPWMOutputs();
+
+  public static native int getNumEncoders();
+
+  public static native int getNumInterrupts();
+
+  public static native int getNumRelayChannels();
+
+  public static native int getNumRelayHeaders();
+
+  public static native int getNumPCMModules();
+
+  public static native int getNumSolenoidChannels();
+
+  public static native int getNumPDPModules();
+
+  public static native int getNumPDPChannels();
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/PowerJNI.java b/hal/src/main/java/edu/wpi/first/hal/PowerJNI.java
new file mode 100644
index 0000000..7a0a376
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/PowerJNI.java
@@ -0,0 +1,38 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class PowerJNI extends JNIWrapper {
+  public static native double getVinVoltage();
+
+  public static native double getVinCurrent();
+
+  public static native double getUserVoltage6V();
+
+  public static native double getUserCurrent6V();
+
+  public static native boolean getUserActive6V();
+
+  public static native int getUserCurrentFaults6V();
+
+  public static native double getUserVoltage5V();
+
+  public static native double getUserCurrent5V();
+
+  public static native boolean getUserActive5V();
+
+  public static native int getUserCurrentFaults5V();
+
+  public static native double getUserVoltage3V3();
+
+  public static native double getUserCurrent3V3();
+
+  public static native boolean getUserActive3V3();
+
+  public static native int getUserCurrentFaults3V3();
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/RelayJNI.java b/hal/src/main/java/edu/wpi/first/hal/RelayJNI.java
new file mode 100644
index 0000000..1b507dc
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/RelayJNI.java
@@ -0,0 +1,20 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class RelayJNI extends DIOJNI {
+  public static native int initializeRelayPort(int halPortHandle, boolean forward);
+
+  public static native void freeRelayPort(int relayPortHandle);
+
+  public static native boolean checkRelayChannel(int channel);
+
+  public static native void setRelay(int relayPortHandle, boolean on);
+
+  public static native boolean getRelay(int relayPortHandle);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java b/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java
new file mode 100644
index 0000000..c473181
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java
@@ -0,0 +1,64 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+import java.nio.ByteBuffer;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class SPIJNI extends JNIWrapper {
+  public static native void spiInitialize(int port);
+
+  public static native int spiTransaction(int port, ByteBuffer dataToSend,
+                                          ByteBuffer dataReceived, byte size);
+
+  public static native int spiTransactionB(int port, byte[] dataToSend,
+                                           byte[] dataReceived, byte size);
+
+  public static native int spiWrite(int port, ByteBuffer dataToSend, byte sendSize);
+
+  public static native int spiWriteB(int port, byte[] dataToSend, byte sendSize);
+
+  public static native int spiRead(int port, boolean initiate, ByteBuffer dataReceived, byte size);
+
+  public static native int spiReadB(int port, boolean initiate, byte[] dataReceived, byte size);
+
+  public static native void spiClose(int port);
+
+  public static native void spiSetSpeed(int port, int speed);
+
+  public static native void spiSetOpts(int port, int msbFirst, int sampleOnTrailing,
+                                       int clkIdleHigh);
+
+  public static native void spiSetChipSelectActiveHigh(int port);
+
+  public static native void spiSetChipSelectActiveLow(int port);
+
+  public static native void spiInitAuto(int port, int bufferSize);
+
+  public static native void spiFreeAuto(int port);
+
+  public static native void spiStartAutoRate(int port, double period);
+
+  public static native void spiStartAutoTrigger(int port, int digitalSourceHandle,
+                                                int analogTriggerType, boolean triggerRising,
+                                                boolean triggerFalling);
+
+  public static native void spiStopAuto(int port);
+
+  public static native void spiSetAutoTransmitData(int port, byte[] dataToSend, int zeroSize);
+
+  public static native void spiForceAutoRead(int port);
+
+  public static native int spiReadAutoReceivedData(int port, ByteBuffer buffer, int numToRead,
+                                                   double timeout);
+
+  public static native int spiReadAutoReceivedData(int port, int[] buffer, int numToRead,
+                                                   double timeout);
+
+  public static native int spiGetAutoDroppedCount(int port);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/SerialPortJNI.java b/hal/src/main/java/edu/wpi/first/hal/SerialPortJNI.java
new file mode 100644
index 0000000..db98b9c
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/SerialPortJNI.java
@@ -0,0 +1,48 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class SerialPortJNI extends JNIWrapper {
+  public static native void serialInitializePort(byte port);
+
+  public static native void serialInitializePortDirect(byte port, String portName);
+
+  public static native void serialSetBaudRate(byte port, int baud);
+
+  public static native void serialSetDataBits(byte port, byte bits);
+
+  public static native void serialSetParity(byte port, byte parity);
+
+  public static native void serialSetStopBits(byte port, byte stopBits);
+
+  public static native void serialSetWriteMode(byte port, byte mode);
+
+  public static native void serialSetFlowControl(byte port, byte flow);
+
+  public static native void serialSetTimeout(byte port, double timeout);
+
+  public static native void serialEnableTermination(byte port, char terminator);
+
+  public static native void serialDisableTermination(byte port);
+
+  public static native void serialSetReadBufferSize(byte port, int size);
+
+  public static native void serialSetWriteBufferSize(byte port, int size);
+
+  public static native int serialGetBytesReceived(byte port);
+
+  public static native int serialRead(byte port, byte[] buffer, int count);
+
+  public static native int serialWrite(byte port, byte[] buffer, int count);
+
+  public static native void serialFlush(byte port);
+
+  public static native void serialClear(byte port);
+
+  public static native void serialClose(byte port);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/SolenoidJNI.java b/hal/src/main/java/edu/wpi/first/hal/SolenoidJNI.java
new file mode 100644
index 0000000..66acbea
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/SolenoidJNI.java
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class SolenoidJNI extends JNIWrapper {
+  public static native int initializeSolenoidPort(int halPortHandle);
+
+  public static native boolean checkSolenoidModule(int module);
+
+  public static native boolean checkSolenoidChannel(int channel);
+
+  public static native void freeSolenoidPort(int portHandle);
+
+  public static native void setSolenoid(int portHandle, boolean on);
+
+  public static native boolean getSolenoid(int portHandle);
+
+  public static native int getAllSolenoids(int module);
+
+  public static native int getPCMSolenoidBlackList(int module);
+
+  public static native boolean getPCMSolenoidVoltageStickyFault(int module);
+
+  public static native boolean getPCMSolenoidVoltageFault(int module);
+
+  public static native void clearAllPCMStickyFaults(int module);
+
+  public static native void setOneShotDuration(int portHandle, long durationMS);
+
+  public static native void fireOneShot(int portHandle);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/ThreadsJNI.java b/hal/src/main/java/edu/wpi/first/hal/ThreadsJNI.java
new file mode 100644
index 0000000..e320eb5
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/ThreadsJNI.java
@@ -0,0 +1,16 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal;
+
+public class ThreadsJNI extends JNIWrapper {
+  public static native int getCurrentThreadPriority();
+
+  public static native boolean getCurrentThreadIsRealTime();
+
+  public static native boolean setCurrentThreadPriority(boolean realTime, int priority);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANExceptionFactory.java b/hal/src/main/java/edu/wpi/first/hal/can/CANExceptionFactory.java
new file mode 100644
index 0000000..132dae1
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANExceptionFactory.java
@@ -0,0 +1,48 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.can;
+
+import edu.wpi.first.hal.communication.NIRioStatus;
+import edu.wpi.first.hal.util.UncleanStatusException;
+
+public final class CANExceptionFactory {
+  // FRC Error codes
+  static final int ERR_CANSessionMux_InvalidBuffer = -44086;
+  static final int ERR_CANSessionMux_MessageNotFound = -44087;
+  static final int ERR_CANSessionMux_NotAllowed = -44088;
+  static final int ERR_CANSessionMux_NotInitialized = -44089;
+
+  @SuppressWarnings({"JavadocMethod", "PMD.CyclomaticComplexity"})
+  public static void checkStatus(int status, int messageID) throws CANInvalidBufferException,
+      CANMessageNotAllowedException, CANNotInitializedException, UncleanStatusException {
+    switch (status) {
+      case NIRioStatus.kRioStatusSuccess:
+        // Everything is ok... don't throw.
+        return;
+      case ERR_CANSessionMux_InvalidBuffer:
+      case NIRioStatus.kRIOStatusBufferInvalidSize:
+        throw new CANInvalidBufferException();
+      case ERR_CANSessionMux_MessageNotFound:
+      case NIRioStatus.kRIOStatusOperationTimedOut:
+        throw new CANMessageNotFoundException();
+      case ERR_CANSessionMux_NotAllowed:
+      case NIRioStatus.kRIOStatusFeatureNotSupported:
+        throw new CANMessageNotAllowedException("MessageID = " + Integer.toString(messageID));
+      case ERR_CANSessionMux_NotInitialized:
+      case NIRioStatus.kRIOStatusResourceNotInitialized:
+        throw new CANNotInitializedException();
+      default:
+        throw new UncleanStatusException("Fatal status code detected:  " + Integer.toString(
+            status));
+    }
+  }
+
+  private CANExceptionFactory() {
+
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANInvalidBufferException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANInvalidBufferException.java
new file mode 100644
index 0000000..8ea718b
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANInvalidBufferException.java
@@ -0,0 +1,24 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.can;
+
+/**
+ * Exception indicating that a CAN driver library entry-point was passed an invalid buffer.
+ * Typically, this is due to a buffer being too small to include the needed safety token.
+ */
+public class CANInvalidBufferException extends RuntimeException {
+  private static final long serialVersionUID = -7993785672956997939L;
+
+  public CANInvalidBufferException() {
+    super();
+  }
+
+  public CANInvalidBufferException(String msg) {
+    super(msg);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANJNI.java b/hal/src/main/java/edu/wpi/first/hal/can/CANJNI.java
new file mode 100644
index 0000000..754157b
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANJNI.java
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.can;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+import edu.wpi.first.hal.JNIWrapper;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class CANJNI extends JNIWrapper {
+  public static final int CAN_SEND_PERIOD_NO_REPEAT = 0;
+  public static final int CAN_SEND_PERIOD_STOP_REPEATING = -1;
+
+  /* Flags in the upper bits of the messageID */
+  public static final int CAN_IS_FRAME_REMOTE = 0x80000000;
+  public static final int CAN_IS_FRAME_11BIT = 0x40000000;
+
+  @SuppressWarnings("MethodName")
+  public static native void FRCNetCommCANSessionMuxSendMessage(int messageID,
+                                                               byte[] data,
+                                                               int periodMs);
+
+  @SuppressWarnings("MethodName")
+  public static native byte[] FRCNetCommCANSessionMuxReceiveMessage(
+      IntBuffer messageID, int messageIDMask, ByteBuffer timeStamp);
+
+
+  @SuppressWarnings("MethodName")
+  public static native void GetCANStatus(CANStatus status);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotAllowedException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotAllowedException.java
new file mode 100644
index 0000000..f4ba6a8
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotAllowedException.java
@@ -0,0 +1,20 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.can;
+
+/**
+ * Exception indicating that the Jaguar CAN Driver layer refused to send a restricted message ID to
+ * the CAN bus.
+ */
+public class CANMessageNotAllowedException extends RuntimeException {
+  private static final long serialVersionUID = -638450112427013494L;
+
+  public CANMessageNotAllowedException(String msg) {
+    super(msg);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotFoundException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotFoundException.java
new file mode 100644
index 0000000..0838691
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotFoundException.java
@@ -0,0 +1,24 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.can;
+
+/**
+ * Exception indicating that a can message is not available from Network Communications. This
+ * usually just means we already have the most recent value cached locally.
+ */
+public class CANMessageNotFoundException extends RuntimeException {
+  private static final long serialVersionUID = 8249780881928189975L;
+
+  public CANMessageNotFoundException() {
+    super();
+  }
+
+  public CANMessageNotFoundException(String msg) {
+    super(msg);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANNotInitializedException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANNotInitializedException.java
new file mode 100644
index 0000000..119b59d
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANNotInitializedException.java
@@ -0,0 +1,24 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.can;
+
+/**
+ * Exception indicating that the CAN driver layer has not been initialized. This happens when an
+ * entry-point is called before a CAN driver plugin has been installed.
+ */
+public class CANNotInitializedException extends RuntimeException {
+  private static final long serialVersionUID = -5982895147092686594L;
+
+  public CANNotInitializedException() {
+    super();
+  }
+
+  public CANNotInitializedException(String msg) {
+    super(msg);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANStatus.java b/hal/src/main/java/edu/wpi/first/hal/can/CANStatus.java
new file mode 100644
index 0000000..492d999
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANStatus.java
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.can;
+
+/**
+ * Structure for holding the result of a CAN Status request.
+ */
+public class CANStatus {
+  /**
+   * The utilization of the CAN Bus.
+   */
+  @SuppressWarnings("MemberName")
+  public double percentBusUtilization;
+
+  /**
+   * The CAN Bus off count.
+   */
+  @SuppressWarnings("MemberName")
+  public int busOffCount;
+
+  /**
+   * The CAN Bus TX full count.
+   */
+  @SuppressWarnings("MemberName")
+  public int txFullCount;
+
+  /**
+   * The CAN Bus receive error count.
+   */
+  @SuppressWarnings("MemberName")
+  public int receiveErrorCount;
+
+  /**
+   * The CAN Bus transmit error count.
+   */
+  @SuppressWarnings("MemberName")
+  public int transmitErrorCount;
+
+  @SuppressWarnings("JavadocMethod")
+  public void setStatus(double percentBusUtilization, int busOffCount, int txFullCount,
+                        int receiveErrorCount, int transmitErrorCount) {
+    this.percentBusUtilization = percentBusUtilization;
+    this.busOffCount = busOffCount;
+    this.txFullCount = txFullCount;
+    this.receiveErrorCount = receiveErrorCount;
+    this.transmitErrorCount = transmitErrorCount;
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java b/hal/src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java
new file mode 100644
index 0000000..f49f34e
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java
@@ -0,0 +1,18 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.communication;
+
+public class NIRioStatus {
+  public static final int kRioStatusOffset = -63000;
+
+  public static final int kRioStatusSuccess = 0;
+  public static final int kRIOStatusBufferInvalidSize = kRioStatusOffset - 80;
+  public static final int kRIOStatusOperationTimedOut = -52007;
+  public static final int kRIOStatusFeatureNotSupported = kRioStatusOffset - 193;
+  public static final int kRIOStatusResourceNotInitialized = -52010;
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/AccelerometerSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/AccelerometerSim.java
new file mode 100644
index 0000000..d9c95af
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/AccelerometerSim.java
@@ -0,0 +1,77 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.AccelerometerDataJNI;
+
+public class AccelerometerSim {
+  private final int m_index;
+
+  public AccelerometerSim() {
+    m_index = 0;
+  }
+
+  public CallbackStore registerActiveCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AccelerometerDataJNI.registerActiveCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelActiveCallback);
+  }
+  public boolean getActive() {
+    return AccelerometerDataJNI.getActive(m_index);
+  }
+  public void setActive(boolean active) {
+    AccelerometerDataJNI.setActive(m_index, active);
+  }
+
+  public CallbackStore registerRangeCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AccelerometerDataJNI.registerRangeCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelRangeCallback);
+  }
+  public int getRange() {
+    return AccelerometerDataJNI.getRange(m_index);
+  }
+  public void setRange(int range) {
+    AccelerometerDataJNI.setRange(m_index, range);
+  }
+
+  public CallbackStore registerXCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AccelerometerDataJNI.registerXCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelXCallback);
+  }
+  public double getX() {
+    return AccelerometerDataJNI.getX(m_index);
+  }
+  public void setX(double x) {
+    AccelerometerDataJNI.setX(m_index, x);
+  }
+
+  public CallbackStore registerYCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AccelerometerDataJNI.registerYCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelYCallback);
+  }
+  public double getY() {
+    return AccelerometerDataJNI.getY(m_index);
+  }
+  public void setY(double y) {
+    AccelerometerDataJNI.setY(m_index, y);
+  }
+
+  public CallbackStore registerZCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AccelerometerDataJNI.registerZCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelZCallback);
+  }
+  public double getZ() {
+    return AccelerometerDataJNI.getZ(m_index);
+  }
+  public void setZ(double z) {
+    AccelerometerDataJNI.setZ(m_index, z);
+  }
+
+  public void resetData() {
+    AccelerometerDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/AnalogGyroSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogGyroSim.java
new file mode 100644
index 0000000..ddaa0ce
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogGyroSim.java
@@ -0,0 +1,55 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.AnalogGyroDataJNI;
+
+public class AnalogGyroSim {
+  private final int m_index;
+
+  public AnalogGyroSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerAngleCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogGyroDataJNI.registerAngleCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogGyroDataJNI::cancelAngleCallback);
+  }
+  public double getAngle() {
+    return AnalogGyroDataJNI.getAngle(m_index);
+  }
+  public void setAngle(double angle) {
+    AnalogGyroDataJNI.setAngle(m_index, angle);
+  }
+
+  public CallbackStore registerRateCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogGyroDataJNI.registerRateCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogGyroDataJNI::cancelRateCallback);
+  }
+  public double getRate() {
+    return AnalogGyroDataJNI.getRate(m_index);
+  }
+  public void setRate(double rate) {
+    AnalogGyroDataJNI.setRate(m_index, rate);
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogGyroDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogGyroDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return AnalogGyroDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    AnalogGyroDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public void resetData() {
+    AnalogGyroDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/AnalogInSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogInSim.java
new file mode 100644
index 0000000..f7f86bb
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogInSim.java
@@ -0,0 +1,121 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.AnalogInDataJNI;
+
+public class AnalogInSim {
+  private final int m_index;
+
+  public AnalogInSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return AnalogInDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    AnalogInDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerAverageBitsCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerAverageBitsCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAverageBitsCallback);
+  }
+  public int getAverageBits() {
+    return AnalogInDataJNI.getAverageBits(m_index);
+  }
+  public void setAverageBits(int averageBits) {
+    AnalogInDataJNI.setAverageBits(m_index, averageBits);
+  }
+
+  public CallbackStore registerOversampleBitsCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerOversampleBitsCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelOversampleBitsCallback);
+  }
+  public int getOversampleBits() {
+    return AnalogInDataJNI.getOversampleBits(m_index);
+  }
+  public void setOversampleBits(int oversampleBits) {
+    AnalogInDataJNI.setOversampleBits(m_index, oversampleBits);
+  }
+
+  public CallbackStore registerVoltageCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerVoltageCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelVoltageCallback);
+  }
+  public double getVoltage() {
+    return AnalogInDataJNI.getVoltage(m_index);
+  }
+  public void setVoltage(double voltage) {
+    AnalogInDataJNI.setVoltage(m_index, voltage);
+  }
+
+  public CallbackStore registerAccumulatorInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerAccumulatorInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorInitializedCallback);
+  }
+  public boolean getAccumulatorInitialized() {
+    return AnalogInDataJNI.getAccumulatorInitialized(m_index);
+  }
+  public void setAccumulatorInitialized(boolean accumulatorInitialized) {
+    AnalogInDataJNI.setAccumulatorInitialized(m_index, accumulatorInitialized);
+  }
+
+  public CallbackStore registerAccumulatorValueCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerAccumulatorValueCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorValueCallback);
+  }
+  public long getAccumulatorValue() {
+    return AnalogInDataJNI.getAccumulatorValue(m_index);
+  }
+  public void setAccumulatorValue(long accumulatorValue) {
+    AnalogInDataJNI.setAccumulatorValue(m_index, accumulatorValue);
+  }
+
+  public CallbackStore registerAccumulatorCountCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerAccumulatorCountCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorCountCallback);
+  }
+  public long getAccumulatorCount() {
+    return AnalogInDataJNI.getAccumulatorCount(m_index);
+  }
+  public void setAccumulatorCount(long accumulatorCount) {
+    AnalogInDataJNI.setAccumulatorCount(m_index, accumulatorCount);
+  }
+
+  public CallbackStore registerAccumulatorCenterCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerAccumulatorCenterCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorCenterCallback);
+  }
+  public int getAccumulatorCenter() {
+    return AnalogInDataJNI.getAccumulatorCenter(m_index);
+  }
+  public void setAccumulatorCenter(int accumulatorCenter) {
+    AnalogInDataJNI.setAccumulatorCenter(m_index, accumulatorCenter);
+  }
+
+  public CallbackStore registerAccumulatorDeadbandCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogInDataJNI.registerAccumulatorDeadbandCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorDeadbandCallback);
+  }
+  public int getAccumulatorDeadband() {
+    return AnalogInDataJNI.getAccumulatorDeadband(m_index);
+  }
+  public void setAccumulatorDeadband(int accumulatorDeadband) {
+    AnalogInDataJNI.setAccumulatorDeadband(m_index, accumulatorDeadband);
+  }
+
+  public void resetData() {
+    AnalogInDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/AnalogOutSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogOutSim.java
new file mode 100644
index 0000000..4731b11
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogOutSim.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.AnalogOutDataJNI;
+
+public class AnalogOutSim {
+  private final int m_index;
+
+  public AnalogOutSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerVoltageCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogOutDataJNI.registerVoltageCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogOutDataJNI::cancelVoltageCallback);
+  }
+  public double getVoltage() {
+    return AnalogOutDataJNI.getVoltage(m_index);
+  }
+  public void setVoltage(double voltage) {
+    AnalogOutDataJNI.setVoltage(m_index, voltage);
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogOutDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogOutDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return AnalogOutDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    AnalogOutDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public void resetData() {
+    AnalogOutDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/AnalogTriggerSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogTriggerSim.java
new file mode 100644
index 0000000..fd88d5f
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/AnalogTriggerSim.java
@@ -0,0 +1,55 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.AnalogTriggerDataJNI;
+
+public class AnalogTriggerSim {
+  private final int m_index;
+
+  public AnalogTriggerSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogTriggerDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogTriggerDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return AnalogTriggerDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    AnalogTriggerDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerTriggerLowerBoundCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogTriggerDataJNI.registerTriggerLowerBoundCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogTriggerDataJNI::cancelTriggerLowerBoundCallback);
+  }
+  public double getTriggerLowerBound() {
+    return AnalogTriggerDataJNI.getTriggerLowerBound(m_index);
+  }
+  public void setTriggerLowerBound(double triggerLowerBound) {
+    AnalogTriggerDataJNI.setTriggerLowerBound(m_index, triggerLowerBound);
+  }
+
+  public CallbackStore registerTriggerUpperBoundCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = AnalogTriggerDataJNI.registerTriggerUpperBoundCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, AnalogTriggerDataJNI::cancelTriggerUpperBoundCallback);
+  }
+  public double getTriggerUpperBound() {
+    return AnalogTriggerDataJNI.getTriggerUpperBound(m_index);
+  }
+  public void setTriggerUpperBound(double triggerUpperBound) {
+    AnalogTriggerDataJNI.setTriggerUpperBound(m_index, triggerUpperBound);
+  }
+
+  public void resetData() {
+    AnalogTriggerDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/BufferCallback.java b/hal/src/main/java/edu/wpi/first/hal/sim/BufferCallback.java
new file mode 100644
index 0000000..0f7b2d9
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/BufferCallback.java
@@ -0,0 +1,12 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+public interface BufferCallback {
+  void callback(String name, byte[] buffer, int count);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/CallbackStore.java b/hal/src/main/java/edu/wpi/first/hal/sim/CallbackStore.java
new file mode 100644
index 0000000..7564104
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/CallbackStore.java
@@ -0,0 +1,84 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+public class CallbackStore implements AutoCloseable {
+  interface CancelCallbackFunc {
+    void cancel(int index, int uid);
+  }
+
+  interface CancelCallbackChannelFunc {
+    void cancel(int index, int channel, int uid);
+  }
+
+  interface CancelCallbackNoIndexFunc {
+    void cancel(int uid);
+  }
+
+  public CallbackStore(int index, int uid, CancelCallbackFunc ccf) {
+    this.m_cancelType = kNormalCancel;
+    this.m_index = index;
+    this.m_uid = uid;
+    this.m_cancelCallback = ccf;
+  }
+
+  public CallbackStore(int index, int channel, int uid, CancelCallbackChannelFunc ccf) {
+    this.m_cancelType = kChannelCancel;
+    this.m_index = index;
+    this.m_uid = uid;
+    this.m_channel = channel;
+    this.m_cancelCallbackChannel = ccf;
+  }
+
+  public CallbackStore(int uid, CancelCallbackNoIndexFunc ccf) {
+    this.m_cancelType = kNoIndexCancel;
+    this.m_uid = uid;
+    this.m_cancelCallbackNoIndex = ccf;
+  }
+
+  private int m_index;
+  private int m_channel;
+  private final int m_uid;
+  private CancelCallbackFunc m_cancelCallback;
+  private CancelCallbackChannelFunc m_cancelCallbackChannel;
+  private CancelCallbackNoIndexFunc m_cancelCallbackNoIndex;
+  private static final int kNormalCancel = 0;
+  private static final int kChannelCancel = 1;
+  private static final int kNoIndexCancel = 2;
+  private int m_cancelType;
+
+  @Override
+  public void close() {
+    switch (m_cancelType) {
+      case kNormalCancel:
+        m_cancelCallback.cancel(m_index, m_uid);
+        break;
+      case kChannelCancel:
+        m_cancelCallbackChannel.cancel(m_index, m_channel, m_uid);
+        break;
+      case kNoIndexCancel:
+        m_cancelCallbackNoIndex.cancel(m_uid);
+        break;
+      default:
+        assert false;
+        break;
+    }
+    m_cancelType = -1;
+  }
+
+  @Override
+  protected void finalize() throws Throwable {
+    try {
+      if (m_cancelType >= 0) {
+        close();        // close open files
+      }
+    } finally {
+      super.finalize();
+    }
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/ConstBufferCallback.java b/hal/src/main/java/edu/wpi/first/hal/sim/ConstBufferCallback.java
new file mode 100644
index 0000000..a4251c2
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/ConstBufferCallback.java
@@ -0,0 +1,12 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+public interface ConstBufferCallback {
+  void callback(String name, byte[] buffer, int count);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/DIOSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/DIOSim.java
new file mode 100644
index 0000000..cd75822
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/DIOSim.java
@@ -0,0 +1,77 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.DIODataJNI;
+
+public class DIOSim {
+  private final int m_index;
+
+  public DIOSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DIODataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DIODataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return DIODataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    DIODataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerValueCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DIODataJNI.registerValueCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DIODataJNI::cancelValueCallback);
+  }
+  public boolean getValue() {
+    return DIODataJNI.getValue(m_index);
+  }
+  public void setValue(boolean value) {
+    DIODataJNI.setValue(m_index, value);
+  }
+
+  public CallbackStore registerPulseLengthCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DIODataJNI.registerPulseLengthCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DIODataJNI::cancelPulseLengthCallback);
+  }
+  public double getPulseLength() {
+    return DIODataJNI.getPulseLength(m_index);
+  }
+  public void setPulseLength(double pulseLength) {
+    DIODataJNI.setPulseLength(m_index, pulseLength);
+  }
+
+  public CallbackStore registerIsInputCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DIODataJNI.registerIsInputCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DIODataJNI::cancelIsInputCallback);
+  }
+  public boolean getIsInput() {
+    return DIODataJNI.getIsInput(m_index);
+  }
+  public void setIsInput(boolean isInput) {
+    DIODataJNI.setIsInput(m_index, isInput);
+  }
+
+  public CallbackStore registerFilterIndexCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DIODataJNI.registerFilterIndexCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DIODataJNI::cancelFilterIndexCallback);
+  }
+  public int getFilterIndex() {
+    return DIODataJNI.getFilterIndex(m_index);
+  }
+  public void setFilterIndex(int filterIndex) {
+    DIODataJNI.setFilterIndex(m_index, filterIndex);
+  }
+
+  public void resetData() {
+    DIODataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/DigitalPWMSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/DigitalPWMSim.java
new file mode 100644
index 0000000..314d994
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/DigitalPWMSim.java
@@ -0,0 +1,55 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.DigitalPWMDataJNI;
+
+public class DigitalPWMSim {
+  private final int m_index;
+
+  public DigitalPWMSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DigitalPWMDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DigitalPWMDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return DigitalPWMDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    DigitalPWMDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerDutyCycleCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DigitalPWMDataJNI.registerDutyCycleCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DigitalPWMDataJNI::cancelDutyCycleCallback);
+  }
+  public double getDutyCycle() {
+    return DigitalPWMDataJNI.getDutyCycle(m_index);
+  }
+  public void setDutyCycle(double dutyCycle) {
+    DigitalPWMDataJNI.setDutyCycle(m_index, dutyCycle);
+  }
+
+  public CallbackStore registerPinCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DigitalPWMDataJNI.registerPinCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, DigitalPWMDataJNI::cancelPinCallback);
+  }
+  public int getPin() {
+    return DigitalPWMDataJNI.getPin(m_index);
+  }
+  public void setPin(int pin) {
+    DigitalPWMDataJNI.setPin(m_index, pin);
+  }
+
+  public void resetData() {
+    DigitalPWMDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/DriverStationSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/DriverStationSim.java
new file mode 100644
index 0000000..20fed0d
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/DriverStationSim.java
@@ -0,0 +1,85 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.DriverStationDataJNI;
+
+public class DriverStationSim {
+  public CallbackStore registerEnabledCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DriverStationDataJNI.registerEnabledCallback(callback, initialNotify);
+    return new CallbackStore(uid, DriverStationDataJNI::cancelEnabledCallback);
+  }
+  public boolean getEnabled() {
+    return DriverStationDataJNI.getEnabled();
+  }
+  public void setEnabled(boolean enabled) {
+    DriverStationDataJNI.setEnabled(enabled);
+  }
+
+  public CallbackStore registerAutonomousCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DriverStationDataJNI.registerAutonomousCallback(callback, initialNotify);
+    return new CallbackStore(uid, DriverStationDataJNI::cancelAutonomousCallback);
+  }
+  public boolean getAutonomous() {
+    return DriverStationDataJNI.getAutonomous();
+  }
+  public void setAutonomous(boolean autonomous) {
+    DriverStationDataJNI.setAutonomous(autonomous);
+  }
+
+  public CallbackStore registerTestCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DriverStationDataJNI.registerTestCallback(callback, initialNotify);
+    return new CallbackStore(uid, DriverStationDataJNI::cancelTestCallback);
+  }
+  public boolean getTest() {
+    return DriverStationDataJNI.getTest();
+  }
+  public void setTest(boolean test) {
+    DriverStationDataJNI.setTest(test);
+  }
+
+  public CallbackStore registerEStopCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DriverStationDataJNI.registerEStopCallback(callback, initialNotify);
+    return new CallbackStore(uid, DriverStationDataJNI::cancelEStopCallback);
+  }
+  public boolean getEStop() {
+    return DriverStationDataJNI.getEStop();
+  }
+  public void setEStop(boolean eStop) {
+    DriverStationDataJNI.setEStop(eStop);
+  }
+
+  public CallbackStore registerFmsAttachedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DriverStationDataJNI.registerFmsAttachedCallback(callback, initialNotify);
+    return new CallbackStore(uid, DriverStationDataJNI::cancelFmsAttachedCallback);
+  }
+  public boolean getFmsAttached() {
+    return DriverStationDataJNI.getFmsAttached();
+  }
+  public void setFmsAttached(boolean fmsAttached) {
+    DriverStationDataJNI.setFmsAttached(fmsAttached);
+  }
+
+  public CallbackStore registerDsAttachedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = DriverStationDataJNI.registerDsAttachedCallback(callback, initialNotify);
+    return new CallbackStore(uid, DriverStationDataJNI::cancelDsAttachedCallback);
+  }
+  public boolean getDsAttached() {
+    return DriverStationDataJNI.getDsAttached();
+  }
+  public void setDsAttached(boolean dsAttached) {
+    DriverStationDataJNI.setDsAttached(dsAttached);
+  }
+  public void notifyNewData() {
+    DriverStationDataJNI.notifyNewData();
+  }
+
+  public void resetData() {
+    DriverStationDataJNI.resetData();
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/EncoderSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/EncoderSim.java
new file mode 100644
index 0000000..408ca84
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/EncoderSim.java
@@ -0,0 +1,110 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.EncoderDataJNI;
+
+public class EncoderSim {
+  private final int m_index;
+
+  public EncoderSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return EncoderDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    EncoderDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerCountCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerCountCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelCountCallback);
+  }
+  public int getCount() {
+    return EncoderDataJNI.getCount(m_index);
+  }
+  public void setCount(int count) {
+    EncoderDataJNI.setCount(m_index, count);
+  }
+
+  public CallbackStore registerPeriodCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerPeriodCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelPeriodCallback);
+  }
+  public double getPeriod() {
+    return EncoderDataJNI.getPeriod(m_index);
+  }
+  public void setPeriod(double period) {
+    EncoderDataJNI.setPeriod(m_index, period);
+  }
+
+  public CallbackStore registerResetCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerResetCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelResetCallback);
+  }
+  public boolean getReset() {
+    return EncoderDataJNI.getReset(m_index);
+  }
+  public void setReset(boolean reset) {
+    EncoderDataJNI.setReset(m_index, reset);
+  }
+
+  public CallbackStore registerMaxPeriodCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerMaxPeriodCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelMaxPeriodCallback);
+  }
+  public double getMaxPeriod() {
+    return EncoderDataJNI.getMaxPeriod(m_index);
+  }
+  public void setMaxPeriod(double maxPeriod) {
+    EncoderDataJNI.setMaxPeriod(m_index, maxPeriod);
+  }
+
+  public CallbackStore registerDirectionCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerDirectionCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelDirectionCallback);
+  }
+  public boolean getDirection() {
+    return EncoderDataJNI.getDirection(m_index);
+  }
+  public void setDirection(boolean direction) {
+    EncoderDataJNI.setDirection(m_index, direction);
+  }
+
+  public CallbackStore registerReverseDirectionCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerReverseDirectionCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelReverseDirectionCallback);
+  }
+  public boolean getReverseDirection() {
+    return EncoderDataJNI.getReverseDirection(m_index);
+  }
+  public void setReverseDirection(boolean reverseDirection) {
+    EncoderDataJNI.setReverseDirection(m_index, reverseDirection);
+  }
+
+  public CallbackStore registerSamplesToAverageCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = EncoderDataJNI.registerSamplesToAverageCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, EncoderDataJNI::cancelSamplesToAverageCallback);
+  }
+  public int getSamplesToAverage() {
+    return EncoderDataJNI.getSamplesToAverage(m_index);
+  }
+  public void setSamplesToAverage(int samplesToAverage) {
+    EncoderDataJNI.setSamplesToAverage(m_index, samplesToAverage);
+  }
+
+  public void resetData() {
+    EncoderDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/I2CSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/I2CSim.java
new file mode 100644
index 0000000..3a9aa02
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/I2CSim.java
@@ -0,0 +1,43 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.I2CDataJNI;
+
+public class I2CSim {
+  private final int m_index;
+
+  public I2CSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = I2CDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, I2CDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return I2CDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    I2CDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerReadCallback(BufferCallback callback) {
+    int uid = I2CDataJNI.registerReadCallback(m_index, callback);
+    return new CallbackStore(m_index, uid, I2CDataJNI::cancelReadCallback);
+  }
+
+  public CallbackStore registerWriteCallback(ConstBufferCallback callback) {
+    int uid = I2CDataJNI.registerWriteCallback(m_index, callback);
+    return new CallbackStore(m_index, uid, I2CDataJNI::cancelWriteCallback);
+  }
+
+  public void resetData() {
+    I2CDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/NotifyCallback.java b/hal/src/main/java/edu/wpi/first/hal/sim/NotifyCallback.java
new file mode 100644
index 0000000..8781f75
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/NotifyCallback.java
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+public interface NotifyCallback {
+  void callback(String name, SimValue value);
+
+  default void callbackNative(String name, int type, long value1, double value2) {
+    switch (type) {
+      case 0x01:
+        callback(name, SimValue.makeBoolean(value1 != 0));
+        break;
+      case 0x02:
+        callback(name, SimValue.makeDouble(value2));
+        break;
+      case 0x16:
+        callback(name, SimValue.makeEnum((int) value1));
+        break;
+      case 0x32:
+        callback(name, SimValue.makeInt((int) value1));
+        break;
+      case 0x64:
+        callback(name, SimValue.makeLong(value1));
+        break;
+      default:
+        callback(name, SimValue.makeUnassigned());
+        break;
+    }
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/PCMSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/PCMSim.java
new file mode 100644
index 0000000..f8cc327
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/PCMSim.java
@@ -0,0 +1,99 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.PCMDataJNI;
+
+public class PCMSim {
+  private final int m_index;
+
+  public PCMSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerSolenoidInitializedCallback(int channel, NotifyCallback callback, boolean initialNotify) {
+    int uid = PCMDataJNI.registerSolenoidInitializedCallback(m_index, channel, callback, initialNotify);
+    return new CallbackStore(m_index, channel, uid, PCMDataJNI::cancelSolenoidInitializedCallback);
+  }
+  public boolean getSolenoidInitialized(int channel) {
+    return PCMDataJNI.getSolenoidInitialized(m_index, channel);
+  }
+  public void setSolenoidInitialized(int channel, boolean solenoidInitialized) {
+    PCMDataJNI.setSolenoidInitialized(m_index, channel, solenoidInitialized);
+  }
+
+  public CallbackStore registerSolenoidOutputCallback(int channel, NotifyCallback callback, boolean initialNotify) {
+    int uid = PCMDataJNI.registerSolenoidOutputCallback(m_index, channel, callback, initialNotify);
+    return new CallbackStore(m_index, channel, uid, PCMDataJNI::cancelSolenoidOutputCallback);
+  }
+  public boolean getSolenoidOutput(int channel) {
+    return PCMDataJNI.getSolenoidOutput(m_index, channel);
+  }
+  public void setSolenoidOutput(int channel, boolean solenoidOutput) {
+    PCMDataJNI.setSolenoidOutput(m_index, channel, solenoidOutput);
+  }
+
+  public CallbackStore registerCompressorInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PCMDataJNI.registerCompressorInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PCMDataJNI::cancelCompressorInitializedCallback);
+  }
+  public boolean getCompressorInitialized() {
+    return PCMDataJNI.getCompressorInitialized(m_index);
+  }
+  public void setCompressorInitialized(boolean compressorInitialized) {
+    PCMDataJNI.setCompressorInitialized(m_index, compressorInitialized);
+  }
+
+  public CallbackStore registerCompressorOnCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PCMDataJNI.registerCompressorOnCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PCMDataJNI::cancelCompressorOnCallback);
+  }
+  public boolean getCompressorOn() {
+    return PCMDataJNI.getCompressorOn(m_index);
+  }
+  public void setCompressorOn(boolean compressorOn) {
+    PCMDataJNI.setCompressorOn(m_index, compressorOn);
+  }
+
+  public CallbackStore registerClosedLoopEnabledCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PCMDataJNI.registerClosedLoopEnabledCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PCMDataJNI::cancelClosedLoopEnabledCallback);
+  }
+  public boolean getClosedLoopEnabled() {
+    return PCMDataJNI.getClosedLoopEnabled(m_index);
+  }
+  public void setClosedLoopEnabled(boolean closedLoopEnabled) {
+    PCMDataJNI.setClosedLoopEnabled(m_index, closedLoopEnabled);
+  }
+
+  public CallbackStore registerPressureSwitchCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PCMDataJNI.registerPressureSwitchCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PCMDataJNI::cancelPressureSwitchCallback);
+  }
+  public boolean getPressureSwitch() {
+    return PCMDataJNI.getPressureSwitch(m_index);
+  }
+  public void setPressureSwitch(boolean pressureSwitch) {
+    PCMDataJNI.setPressureSwitch(m_index, pressureSwitch);
+  }
+
+  public CallbackStore registerCompressorCurrentCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PCMDataJNI.registerCompressorCurrentCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PCMDataJNI::cancelCompressorCurrentCallback);
+  }
+  public double getCompressorCurrent() {
+    return PCMDataJNI.getCompressorCurrent(m_index);
+  }
+  public void setCompressorCurrent(double compressorCurrent) {
+    PCMDataJNI.setCompressorCurrent(m_index, compressorCurrent);
+  }
+
+  public void resetData() {
+    PCMDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/PDPSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/PDPSim.java
new file mode 100644
index 0000000..d44cf3a
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/PDPSim.java
@@ -0,0 +1,66 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.PDPDataJNI;
+
+public class PDPSim {
+  private final int m_index;
+
+  public PDPSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PDPDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PDPDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return PDPDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    PDPDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerTemperatureCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PDPDataJNI.registerTemperatureCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PDPDataJNI::cancelTemperatureCallback);
+  }
+  public double getTemperature() {
+    return PDPDataJNI.getTemperature(m_index);
+  }
+  public void setTemperature(double temperature) {
+    PDPDataJNI.setTemperature(m_index, temperature);
+  }
+
+  public CallbackStore registerVoltageCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PDPDataJNI.registerVoltageCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PDPDataJNI::cancelVoltageCallback);
+  }
+  public double getVoltage() {
+    return PDPDataJNI.getVoltage(m_index);
+  }
+  public void setVoltage(double voltage) {
+    PDPDataJNI.setVoltage(m_index, voltage);
+  }
+
+  public CallbackStore registerCurrentCallback(int channel, NotifyCallback callback, boolean initialNotify) {
+    int uid = PDPDataJNI.registerCurrentCallback(m_index, channel, callback, initialNotify);
+    return new CallbackStore(m_index, channel, uid, PDPDataJNI::cancelCurrentCallback);
+  }
+  public double getCurrent(int channel) {
+    return PDPDataJNI.getCurrent(m_index, channel);
+  }
+  public void setCurrent(int channel, double current) {
+    PDPDataJNI.setCurrent(m_index, channel, current);
+  }
+
+  public void resetData() {
+    PDPDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/PWMSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/PWMSim.java
new file mode 100644
index 0000000..dde38a4
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/PWMSim.java
@@ -0,0 +1,88 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.PWMDataJNI;
+
+public class PWMSim {
+  private final int m_index;
+
+  public PWMSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PWMDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PWMDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return PWMDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    PWMDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerRawValueCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PWMDataJNI.registerRawValueCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PWMDataJNI::cancelRawValueCallback);
+  }
+  public int getRawValue() {
+    return PWMDataJNI.getRawValue(m_index);
+  }
+  public void setRawValue(int rawValue) {
+    PWMDataJNI.setRawValue(m_index, rawValue);
+  }
+
+  public CallbackStore registerSpeedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PWMDataJNI.registerSpeedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PWMDataJNI::cancelSpeedCallback);
+  }
+  public double getSpeed() {
+    return PWMDataJNI.getSpeed(m_index);
+  }
+  public void setSpeed(double speed) {
+    PWMDataJNI.setSpeed(m_index, speed);
+  }
+
+  public CallbackStore registerPositionCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PWMDataJNI.registerPositionCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PWMDataJNI::cancelPositionCallback);
+  }
+  public double getPosition() {
+    return PWMDataJNI.getPosition(m_index);
+  }
+  public void setPosition(double position) {
+    PWMDataJNI.setPosition(m_index, position);
+  }
+
+  public CallbackStore registerPeriodScaleCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PWMDataJNI.registerPeriodScaleCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PWMDataJNI::cancelPeriodScaleCallback);
+  }
+  public int getPeriodScale() {
+    return PWMDataJNI.getPeriodScale(m_index);
+  }
+  public void setPeriodScale(int periodScale) {
+    PWMDataJNI.setPeriodScale(m_index, periodScale);
+  }
+
+  public CallbackStore registerZeroLatchCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = PWMDataJNI.registerZeroLatchCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, PWMDataJNI::cancelZeroLatchCallback);
+  }
+  public boolean getZeroLatch() {
+    return PWMDataJNI.getZeroLatch(m_index);
+  }
+  public void setZeroLatch(boolean zeroLatch) {
+    PWMDataJNI.setZeroLatch(m_index, zeroLatch);
+  }
+
+  public void resetData() {
+    PWMDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/RelaySim.java b/hal/src/main/java/edu/wpi/first/hal/sim/RelaySim.java
new file mode 100644
index 0000000..84059e8
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/RelaySim.java
@@ -0,0 +1,66 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.RelayDataJNI;
+
+public class RelaySim {
+  private final int m_index;
+
+  public RelaySim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedForwardCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RelayDataJNI.registerInitializedForwardCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RelayDataJNI::cancelInitializedForwardCallback);
+  }
+  public boolean getInitializedForward() {
+    return RelayDataJNI.getInitializedForward(m_index);
+  }
+  public void setInitializedForward(boolean initializedForward) {
+    RelayDataJNI.setInitializedForward(m_index, initializedForward);
+  }
+
+  public CallbackStore registerInitializedReverseCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RelayDataJNI.registerInitializedReverseCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RelayDataJNI::cancelInitializedReverseCallback);
+  }
+  public boolean getInitializedReverse() {
+    return RelayDataJNI.getInitializedReverse(m_index);
+  }
+  public void setInitializedReverse(boolean initializedReverse) {
+    RelayDataJNI.setInitializedReverse(m_index, initializedReverse);
+  }
+
+  public CallbackStore registerForwardCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RelayDataJNI.registerForwardCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RelayDataJNI::cancelForwardCallback);
+  }
+  public boolean getForward() {
+    return RelayDataJNI.getForward(m_index);
+  }
+  public void setForward(boolean forward) {
+    RelayDataJNI.setForward(m_index, forward);
+  }
+
+  public CallbackStore registerReverseCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RelayDataJNI.registerReverseCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RelayDataJNI::cancelReverseCallback);
+  }
+  public boolean getReverse() {
+    return RelayDataJNI.getReverse(m_index);
+  }
+  public void setReverse(boolean reverse) {
+    RelayDataJNI.setReverse(m_index, reverse);
+  }
+
+  public void resetData() {
+    RelayDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/RoboRioSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/RoboRioSim.java
new file mode 100644
index 0000000..082f712
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/RoboRioSim.java
@@ -0,0 +1,188 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.RoboRioDataJNI;
+
+@SuppressWarnings({"PMD.ExcessivePublicCount", "PMD.TooManyMethods"})
+public class RoboRioSim {
+  private final int m_index;
+
+  public RoboRioSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerFPGAButtonCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerFPGAButtonCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelFPGAButtonCallback);
+  }
+  public boolean getFPGAButton() {
+    return RoboRioDataJNI.getFPGAButton(m_index);
+  }
+  public void setFPGAButton(boolean fPGAButton) {
+    RoboRioDataJNI.setFPGAButton(m_index, fPGAButton);
+  }
+
+  public CallbackStore registerVInVoltageCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerVInVoltageCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelVInVoltageCallback);
+  }
+  public double getVInVoltage() {
+    return RoboRioDataJNI.getVInVoltage(m_index);
+  }
+  public void setVInVoltage(double vInVoltage) {
+    RoboRioDataJNI.setVInVoltage(m_index, vInVoltage);
+  }
+
+  public CallbackStore registerVInCurrentCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerVInCurrentCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelVInCurrentCallback);
+  }
+  public double getVInCurrent() {
+    return RoboRioDataJNI.getVInCurrent(m_index);
+  }
+  public void setVInCurrent(double vInCurrent) {
+    RoboRioDataJNI.setVInCurrent(m_index, vInCurrent);
+  }
+
+  public CallbackStore registerUserVoltage6VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserVoltage6VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserVoltage6VCallback);
+  }
+  public double getUserVoltage6V() {
+    return RoboRioDataJNI.getUserVoltage6V(m_index);
+  }
+  public void setUserVoltage6V(double userVoltage6V) {
+    RoboRioDataJNI.setUserVoltage6V(m_index, userVoltage6V);
+  }
+
+  public CallbackStore registerUserCurrent6VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserCurrent6VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserCurrent6VCallback);
+  }
+  public double getUserCurrent6V() {
+    return RoboRioDataJNI.getUserCurrent6V(m_index);
+  }
+  public void setUserCurrent6V(double userCurrent6V) {
+    RoboRioDataJNI.setUserCurrent6V(m_index, userCurrent6V);
+  }
+
+  public CallbackStore registerUserActive6VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserActive6VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserActive6VCallback);
+  }
+  public boolean getUserActive6V() {
+    return RoboRioDataJNI.getUserActive6V(m_index);
+  }
+  public void setUserActive6V(boolean userActive6V) {
+    RoboRioDataJNI.setUserActive6V(m_index, userActive6V);
+  }
+
+  public CallbackStore registerUserVoltage5VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserVoltage5VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserVoltage5VCallback);
+  }
+  public double getUserVoltage5V() {
+    return RoboRioDataJNI.getUserVoltage5V(m_index);
+  }
+  public void setUserVoltage5V(double userVoltage5V) {
+    RoboRioDataJNI.setUserVoltage5V(m_index, userVoltage5V);
+  }
+
+  public CallbackStore registerUserCurrent5VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserCurrent5VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserCurrent5VCallback);
+  }
+  public double getUserCurrent5V() {
+    return RoboRioDataJNI.getUserCurrent5V(m_index);
+  }
+  public void setUserCurrent5V(double userCurrent5V) {
+    RoboRioDataJNI.setUserCurrent5V(m_index, userCurrent5V);
+  }
+
+  public CallbackStore registerUserActive5VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserActive5VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserActive5VCallback);
+  }
+  public boolean getUserActive5V() {
+    return RoboRioDataJNI.getUserActive5V(m_index);
+  }
+  public void setUserActive5V(boolean userActive5V) {
+    RoboRioDataJNI.setUserActive5V(m_index, userActive5V);
+  }
+
+  public CallbackStore registerUserVoltage3V3Callback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserVoltage3V3Callback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserVoltage3V3Callback);
+  }
+  public double getUserVoltage3V3() {
+    return RoboRioDataJNI.getUserVoltage3V3(m_index);
+  }
+  public void setUserVoltage3V3(double userVoltage3V3) {
+    RoboRioDataJNI.setUserVoltage3V3(m_index, userVoltage3V3);
+  }
+
+  public CallbackStore registerUserCurrent3V3Callback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserCurrent3V3Callback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserCurrent3V3Callback);
+  }
+  public double getUserCurrent3V3() {
+    return RoboRioDataJNI.getUserCurrent3V3(m_index);
+  }
+  public void setUserCurrent3V3(double userCurrent3V3) {
+    RoboRioDataJNI.setUserCurrent3V3(m_index, userCurrent3V3);
+  }
+
+  public CallbackStore registerUserActive3V3Callback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserActive3V3Callback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserActive3V3Callback);
+  }
+  public boolean getUserActive3V3() {
+    return RoboRioDataJNI.getUserActive3V3(m_index);
+  }
+  public void setUserActive3V3(boolean userActive3V3) {
+    RoboRioDataJNI.setUserActive3V3(m_index, userActive3V3);
+  }
+
+  public CallbackStore registerUserFaults6VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserFaults6VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserFaults6VCallback);
+  }
+  public int getUserFaults6V() {
+    return RoboRioDataJNI.getUserFaults6V(m_index);
+  }
+  public void setUserFaults6V(int userFaults6V) {
+    RoboRioDataJNI.setUserFaults6V(m_index, userFaults6V);
+  }
+
+  public CallbackStore registerUserFaults5VCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserFaults5VCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserFaults5VCallback);
+  }
+  public int getUserFaults5V() {
+    return RoboRioDataJNI.getUserFaults5V(m_index);
+  }
+  public void setUserFaults5V(int userFaults5V) {
+    RoboRioDataJNI.setUserFaults5V(m_index, userFaults5V);
+  }
+
+  public CallbackStore registerUserFaults3V3Callback(NotifyCallback callback, boolean initialNotify) {
+    int uid = RoboRioDataJNI.registerUserFaults3V3Callback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, RoboRioDataJNI::cancelUserFaults3V3Callback);
+  }
+  public int getUserFaults3V3() {
+    return RoboRioDataJNI.getUserFaults3V3(m_index);
+  }
+  public void setUserFaults3V3(int userFaults3V3) {
+    RoboRioDataJNI.setUserFaults3V3(m_index, userFaults3V3);
+  }
+
+  public void resetData() {
+    RoboRioDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/SPIAccelerometerSim.java b/hal/src/main/java/edu/wpi/first/hal/sim/SPIAccelerometerSim.java
new file mode 100644
index 0000000..94577bd
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/SPIAccelerometerSim.java
@@ -0,0 +1,77 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.SPIAccelerometerDataJNI;
+
+public class SPIAccelerometerSim {
+  private final int m_index;
+
+  public SPIAccelerometerSim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerActiveCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = SPIAccelerometerDataJNI.registerActiveCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelActiveCallback);
+  }
+  public boolean getActive() {
+    return SPIAccelerometerDataJNI.getActive(m_index);
+  }
+  public void setActive(boolean active) {
+    SPIAccelerometerDataJNI.setActive(m_index, active);
+  }
+
+  public CallbackStore registerRangeCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = SPIAccelerometerDataJNI.registerRangeCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelRangeCallback);
+  }
+  public int getRange() {
+    return SPIAccelerometerDataJNI.getRange(m_index);
+  }
+  public void setRange(int range) {
+    SPIAccelerometerDataJNI.setRange(m_index, range);
+  }
+
+  public CallbackStore registerXCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = SPIAccelerometerDataJNI.registerXCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelXCallback);
+  }
+  public double getX() {
+    return SPIAccelerometerDataJNI.getX(m_index);
+  }
+  public void setX(double x) {
+    SPIAccelerometerDataJNI.setX(m_index, x);
+  }
+
+  public CallbackStore registerYCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = SPIAccelerometerDataJNI.registerYCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelYCallback);
+  }
+  public double getY() {
+    return SPIAccelerometerDataJNI.getY(m_index);
+  }
+  public void setY(double y) {
+    SPIAccelerometerDataJNI.setY(m_index, y);
+  }
+
+  public CallbackStore registerZCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = SPIAccelerometerDataJNI.registerZCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelZCallback);
+  }
+  public double getZ() {
+    return SPIAccelerometerDataJNI.getZ(m_index);
+  }
+  public void setZ(double z) {
+    SPIAccelerometerDataJNI.setZ(m_index, z);
+  }
+
+  public void resetData() {
+    SPIAccelerometerDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/SPISim.java b/hal/src/main/java/edu/wpi/first/hal/sim/SPISim.java
new file mode 100644
index 0000000..5f43bca
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/SPISim.java
@@ -0,0 +1,48 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.SPIDataJNI;
+
+public class SPISim {
+  private final int m_index;
+
+  public SPISim(int index) {
+    m_index = index;
+  }
+
+  public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+    int uid = SPIDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+    return new CallbackStore(m_index, uid, SPIDataJNI::cancelInitializedCallback);
+  }
+  public boolean getInitialized() {
+    return SPIDataJNI.getInitialized(m_index);
+  }
+  public void setInitialized(boolean initialized) {
+    SPIDataJNI.setInitialized(m_index, initialized);
+  }
+
+  public CallbackStore registerReadCallback(BufferCallback callback) {
+    int uid = SPIDataJNI.registerReadCallback(m_index, callback);
+    return new CallbackStore(m_index, uid, SPIDataJNI::cancelReadCallback);
+  }
+
+  public CallbackStore registerWriteCallback(ConstBufferCallback callback) {
+    int uid = SPIDataJNI.registerWriteCallback(m_index, callback);
+    return new CallbackStore(m_index, uid, SPIDataJNI::cancelWriteCallback);
+  }
+
+  public CallbackStore registerReadAutoReceiveBufferCallback(SpiReadAutoReceiveBufferCallback callback) {
+    int uid = SPIDataJNI.registerReadAutoReceiveBufferCallback(m_index, callback);
+    return new CallbackStore(m_index, uid, SPIDataJNI::cancelReadAutoReceiveBufferCallback);
+  }
+
+  public void resetData() {
+    SPIDataJNI.resetData(m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/SimHooks.java b/hal/src/main/java/edu/wpi/first/hal/sim/SimHooks.java
new file mode 100644
index 0000000..6c46111
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/SimHooks.java
@@ -0,0 +1,27 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import edu.wpi.first.hal.sim.mockdata.SimulatorJNI;
+
+public final class SimHooks {
+  private SimHooks() {
+  }
+
+  public static void waitForProgramStart() {
+    SimulatorJNI.waitForProgramStart();
+  }
+
+  public static void setProgramStarted() {
+    SimulatorJNI.setProgramStarted();
+  }
+
+  public static void restartTiming() {
+    SimulatorJNI.restartTiming();
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/SimValue.java b/hal/src/main/java/edu/wpi/first/hal/sim/SimValue.java
new file mode 100644
index 0000000..3dbb7c9
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/SimValue.java
@@ -0,0 +1,66 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+public final class SimValue {
+  private boolean m_boolean;
+  private long m_long;
+  private double m_double;
+
+  private SimValue(boolean b) {
+    m_boolean = b;
+  }
+
+  private SimValue(double v) {
+    m_double = v;
+  }
+
+  private SimValue(long v) {
+    m_long = v;
+  }
+
+  private SimValue() {
+
+  }
+
+  public boolean getBoolean() {
+    return m_boolean;
+  }
+
+  public long getLong() {
+    return m_long;
+  }
+
+  public double getDouble() {
+    return m_double;
+  }
+
+  public static SimValue makeBoolean(boolean value) {
+    return new SimValue(value);
+  }
+
+  public static SimValue makeEnum(int value) {
+    return new SimValue(value);
+  }
+
+  public static SimValue makeInt(int value) {
+    return new SimValue(value);
+  }
+
+  public static SimValue makeLong(long value) {
+    return new SimValue(value);
+  }
+
+  public static SimValue makeDouble(double value) {
+    return new SimValue(value);
+  }
+
+  public static SimValue makeUnassigned() {
+    return new SimValue();
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/SpiReadAutoReceiveBufferCallback.java b/hal/src/main/java/edu/wpi/first/hal/sim/SpiReadAutoReceiveBufferCallback.java
new file mode 100644
index 0000000..5083fab
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/SpiReadAutoReceiveBufferCallback.java
@@ -0,0 +1,12 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+public interface SpiReadAutoReceiveBufferCallback {
+  int callback(String name, int[] buffer, int numToRead);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AccelerometerDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AccelerometerDataJNI.java
new file mode 100644
index 0000000..22276d4
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AccelerometerDataJNI.java
@@ -0,0 +1,40 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class AccelerometerDataJNI extends JNIWrapper {
+  public static native int registerActiveCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelActiveCallback(int index, int uid);
+  public static native boolean getActive(int index);
+  public static native void setActive(int index, boolean active);
+
+  public static native int registerRangeCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelRangeCallback(int index, int uid);
+  public static native int getRange(int index);
+  public static native void setRange(int index, int range);
+
+  public static native int registerXCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelXCallback(int index, int uid);
+  public static native double getX(int index);
+  public static native void setX(int index, double x);
+
+  public static native int registerYCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelYCallback(int index, int uid);
+  public static native double getY(int index);
+  public static native void setY(int index, double y);
+
+  public static native int registerZCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelZCallback(int index, int uid);
+  public static native double getZ(int index);
+  public static native void setZ(int index, double z);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogGyroDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogGyroDataJNI.java
new file mode 100644
index 0000000..4995df2
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogGyroDataJNI.java
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class AnalogGyroDataJNI extends JNIWrapper {
+  public static native int registerAngleCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAngleCallback(int index, int uid);
+  public static native double getAngle(int index);
+  public static native void setAngle(int index, double angle);
+
+  public static native int registerRateCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelRateCallback(int index, int uid);
+  public static native double getRate(int index);
+  public static native void setRate(int index, double rate);
+
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogInDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogInDataJNI.java
new file mode 100644
index 0000000..ed4fbac
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogInDataJNI.java
@@ -0,0 +1,60 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class AnalogInDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerAverageBitsCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAverageBitsCallback(int index, int uid);
+  public static native int getAverageBits(int index);
+  public static native void setAverageBits(int index, int averageBits);
+
+  public static native int registerOversampleBitsCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelOversampleBitsCallback(int index, int uid);
+  public static native int getOversampleBits(int index);
+  public static native void setOversampleBits(int index, int oversampleBits);
+
+  public static native int registerVoltageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelVoltageCallback(int index, int uid);
+  public static native double getVoltage(int index);
+  public static native void setVoltage(int index, double voltage);
+
+  public static native int registerAccumulatorInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAccumulatorInitializedCallback(int index, int uid);
+  public static native boolean getAccumulatorInitialized(int index);
+  public static native void setAccumulatorInitialized(int index, boolean accumulatorInitialized);
+
+  public static native int registerAccumulatorValueCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAccumulatorValueCallback(int index, int uid);
+  public static native long getAccumulatorValue(int index);
+  public static native void setAccumulatorValue(int index, long accumulatorValue);
+
+  public static native int registerAccumulatorCountCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAccumulatorCountCallback(int index, int uid);
+  public static native long getAccumulatorCount(int index);
+  public static native void setAccumulatorCount(int index, long accumulatorCount);
+
+  public static native int registerAccumulatorCenterCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAccumulatorCenterCallback(int index, int uid);
+  public static native int getAccumulatorCenter(int index);
+  public static native void setAccumulatorCenter(int index, int AccumulatorCenter);
+
+  public static native int registerAccumulatorDeadbandCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAccumulatorDeadbandCallback(int index, int uid);
+  public static native int getAccumulatorDeadband(int index);
+  public static native void setAccumulatorDeadband(int index, int AccumulatorDeadband);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogOutDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogOutDataJNI.java
new file mode 100644
index 0000000..2f7596c
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogOutDataJNI.java
@@ -0,0 +1,25 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class AnalogOutDataJNI extends JNIWrapper {
+  public static native int registerVoltageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelVoltageCallback(int index, int uid);
+  public static native double getVoltage(int index);
+  public static native void setVoltage(int index, double voltage);
+
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogTriggerDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogTriggerDataJNI.java
new file mode 100644
index 0000000..cf4187f
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/AnalogTriggerDataJNI.java
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class AnalogTriggerDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerTriggerLowerBoundCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelTriggerLowerBoundCallback(int index, int uid);
+  public static native double getTriggerLowerBound(int index);
+  public static native void setTriggerLowerBound(int index, double triggerLowerBound);
+
+  public static native int registerTriggerUpperBoundCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelTriggerUpperBoundCallback(int index, int uid);
+  public static native double getTriggerUpperBound(int index);
+  public static native void setTriggerUpperBound(int index, double triggerUpperBound);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DIODataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DIODataJNI.java
new file mode 100644
index 0000000..55de7de
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DIODataJNI.java
@@ -0,0 +1,40 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class DIODataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerValueCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelValueCallback(int index, int uid);
+  public static native boolean getValue(int index);
+  public static native void setValue(int index, boolean value);
+
+  public static native int registerPulseLengthCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelPulseLengthCallback(int index, int uid);
+  public static native double getPulseLength(int index);
+  public static native void setPulseLength(int index, double pulseLength);
+
+  public static native int registerIsInputCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelIsInputCallback(int index, int uid);
+  public static native boolean getIsInput(int index);
+  public static native void setIsInput(int index, boolean isInput);
+
+  public static native int registerFilterIndexCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelFilterIndexCallback(int index, int uid);
+  public static native int getFilterIndex(int index);
+  public static native void setFilterIndex(int index, int filterIndex);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DigitalPWMDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DigitalPWMDataJNI.java
new file mode 100644
index 0000000..69bee07
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DigitalPWMDataJNI.java
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class DigitalPWMDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerDutyCycleCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelDutyCycleCallback(int index, int uid);
+  public static native double getDutyCycle(int index);
+  public static native void setDutyCycle(int index, double dutyCycle);
+
+  public static native int registerPinCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelPinCallback(int index, int uid);
+  public static native int getPin(int index);
+  public static native void setPin(int index, int pin);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DriverStationDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DriverStationDataJNI.java
new file mode 100644
index 0000000..2d41ca7
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/DriverStationDataJNI.java
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.JNIWrapper;
+import edu.wpi.first.hal.sim.NotifyCallback;
+
+public class DriverStationDataJNI extends JNIWrapper {
+  public static native int registerEnabledCallback(NotifyCallback callback, boolean initialNotify);
+  public static native void cancelEnabledCallback(int uid);
+  public static native boolean getEnabled();
+  public static native void setEnabled(boolean enabled);
+
+  public static native int registerAutonomousCallback(NotifyCallback callback, boolean initialNotify);
+  public static native void cancelAutonomousCallback(int uid);
+  public static native boolean getAutonomous();
+  public static native void setAutonomous(boolean autonomous);
+
+  public static native int registerTestCallback(NotifyCallback callback, boolean initialNotify);
+  public static native void cancelTestCallback(int uid);
+  public static native boolean getTest();
+  public static native void setTest(boolean test);
+
+  public static native int registerEStopCallback(NotifyCallback callback, boolean initialNotify);
+  public static native void cancelEStopCallback(int uid);
+  public static native boolean getEStop();
+  public static native void setEStop(boolean eStop);
+
+  public static native int registerFmsAttachedCallback(NotifyCallback callback, boolean initialNotify);
+  public static native void cancelFmsAttachedCallback(int uid);
+  public static native boolean getFmsAttached();
+  public static native void setFmsAttached(boolean fmsAttached);
+
+  public static native int registerDsAttachedCallback(NotifyCallback callback, boolean initialNotify);
+  public static native void cancelDsAttachedCallback(int uid);
+  public static native boolean getDsAttached();
+  public static native void setDsAttached(boolean dsAttached);
+
+  public static native void setJoystickAxes(byte joystickNum, float[] axesArray);
+  public static native void setJoystickPOVs(byte joystickNum, short[] povsArray);
+  public static native void setJoystickButtons(byte joystickNum, int buttons, int count);
+
+  public static native void setMatchInfo(String eventName, String gameSpecificMessage, int matchNumber, int replayNumber, int matchType);
+  public static native void registerAllCallbacks(NotifyCallback callback, boolean initialNotify);
+  public static native void notifyNewData();
+
+  public static native void resetData();
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/EncoderDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/EncoderDataJNI.java
new file mode 100644
index 0000000..17e242e
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/EncoderDataJNI.java
@@ -0,0 +1,55 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class EncoderDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerCountCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelCountCallback(int index, int uid);
+  public static native int getCount(int index);
+  public static native void setCount(int index, int count);
+
+  public static native int registerPeriodCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelPeriodCallback(int index, int uid);
+  public static native double getPeriod(int index);
+  public static native void setPeriod(int index, double period);
+
+  public static native int registerResetCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelResetCallback(int index, int uid);
+  public static native boolean getReset(int index);
+  public static native void setReset(int index, boolean reset);
+
+  public static native int registerMaxPeriodCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelMaxPeriodCallback(int index, int uid);
+  public static native double getMaxPeriod(int index);
+  public static native void setMaxPeriod(int index, double maxPeriod);
+
+  public static native int registerDirectionCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelDirectionCallback(int index, int uid);
+  public static native boolean getDirection(int index);
+  public static native void setDirection(int index, boolean direction);
+
+  public static native int registerReverseDirectionCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelReverseDirectionCallback(int index, int uid);
+  public static native boolean getReverseDirection(int index);
+  public static native void setReverseDirection(int index, boolean reverseDirection);
+
+  public static native int registerSamplesToAverageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelSamplesToAverageCallback(int index, int uid);
+  public static native int getSamplesToAverage(int index);
+  public static native void setSamplesToAverage(int index, int samplesToAverage);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/I2CDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/I2CDataJNI.java
new file mode 100644
index 0000000..33d78f8
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/I2CDataJNI.java
@@ -0,0 +1,28 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.BufferCallback;
+import edu.wpi.first.hal.sim.ConstBufferCallback;
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class I2CDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerReadCallback(int index, BufferCallback callback);
+  public static native void cancelReadCallback(int index, int uid);
+
+  public static native int registerWriteCallback(int index, ConstBufferCallback callback);
+  public static native void cancelWriteCallback(int index, int uid);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PCMDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PCMDataJNI.java
new file mode 100644
index 0000000..c5de287
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PCMDataJNI.java
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class PCMDataJNI extends JNIWrapper {
+  public static native int registerSolenoidInitializedCallback(int index, int channel, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelSolenoidInitializedCallback(int index, int channel, int uid);
+  public static native boolean getSolenoidInitialized(int index, int channel);
+  public static native void setSolenoidInitialized(int index, int channel, boolean solenoidInitialized);
+
+  public static native int registerSolenoidOutputCallback(int index, int channel, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelSolenoidOutputCallback(int index, int channel, int uid);
+  public static native boolean getSolenoidOutput(int index, int channel);
+  public static native void setSolenoidOutput(int index, int channel, boolean solenoidOutput);
+
+  public static native int registerCompressorInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelCompressorInitializedCallback(int index, int uid);
+  public static native boolean getCompressorInitialized(int index);
+  public static native void setCompressorInitialized(int index, boolean compressorInitialized);
+
+  public static native int registerCompressorOnCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelCompressorOnCallback(int index, int uid);
+  public static native boolean getCompressorOn(int index);
+  public static native void setCompressorOn(int index, boolean compressorOn);
+
+  public static native int registerClosedLoopEnabledCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelClosedLoopEnabledCallback(int index, int uid);
+  public static native boolean getClosedLoopEnabled(int index);
+  public static native void setClosedLoopEnabled(int index, boolean closeLoopEnabled);
+
+  public static native int registerPressureSwitchCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelPressureSwitchCallback(int index, int uid);
+  public static native boolean getPressureSwitch(int index);
+  public static native void setPressureSwitch(int index, boolean pressureSwitch);
+
+  public static native int registerCompressorCurrentCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelCompressorCurrentCallback(int index, int uid);
+  public static native double getCompressorCurrent(int index);
+  public static native void setCompressorCurrent(int index, double compressorCurrent);
+
+  public static native void registerAllNonSolenoidCallbacks(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void registerAllSolenoidCallbacks(int index, int channel, NotifyCallback callback, boolean initialNotify);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PDPDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PDPDataJNI.java
new file mode 100644
index 0000000..581a727
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PDPDataJNI.java
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class PDPDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerTemperatureCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelTemperatureCallback(int index, int uid);
+  public static native double getTemperature(int index);
+  public static native void setTemperature(int index, double temperature);
+
+  public static native int registerVoltageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelVoltageCallback(int index, int uid);
+  public static native double getVoltage(int index);
+  public static native void setVoltage(int index, double voltage);
+
+
+  public static native int registerCurrentCallback(int index, int channel, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelCurrentCallback(int index, int channel, int uid);
+  public static native double getCurrent(int index, int channel);
+  public static native void setCurrent(int index, int channel, double current);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PWMDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PWMDataJNI.java
new file mode 100644
index 0000000..e36990e
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/PWMDataJNI.java
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class PWMDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerRawValueCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelRawValueCallback(int index, int uid);
+  public static native int getRawValue(int index);
+  public static native void setRawValue(int index, int rawValue);
+
+  public static native int registerSpeedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelSpeedCallback(int index, int uid);
+  public static native double getSpeed(int index);
+  public static native void setSpeed(int index, double speed);
+
+  public static native int registerPositionCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelPositionCallback(int index, int uid);
+  public static native double getPosition(int index);
+  public static native void setPosition(int index, double position);
+
+  public static native int registerPeriodScaleCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelPeriodScaleCallback(int index, int uid);
+  public static native int getPeriodScale(int index);
+  public static native void setPeriodScale(int index, int periodScale);
+
+  public static native int registerZeroLatchCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelZeroLatchCallback(int index, int uid);
+  public static native boolean getZeroLatch(int index);
+  public static native void setZeroLatch(int index, boolean zeroLatch);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/RelayDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/RelayDataJNI.java
new file mode 100644
index 0000000..320a86d
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/RelayDataJNI.java
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class RelayDataJNI extends JNIWrapper {
+  public static native int registerInitializedForwardCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedForwardCallback(int index, int uid);
+  public static native boolean getInitializedForward(int index);
+  public static native void setInitializedForward(int index, boolean initializedForward);
+
+  public static native int registerInitializedReverseCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedReverseCallback(int index, int uid);
+  public static native boolean getInitializedReverse(int index);
+  public static native void setInitializedReverse(int index, boolean initializedReverse);
+
+  public static native int registerForwardCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelForwardCallback(int index, int uid);
+  public static native boolean getForward(int index);
+  public static native void setForward(int index, boolean forward);
+
+  public static native int registerReverseCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelReverseCallback(int index, int uid);
+  public static native boolean getReverse(int index);
+  public static native void setReverse(int index, boolean reverse);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/RoboRioDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/RoboRioDataJNI.java
new file mode 100644
index 0000000..a13845c
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/RoboRioDataJNI.java
@@ -0,0 +1,90 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class RoboRioDataJNI extends JNIWrapper {
+  public static native int registerFPGAButtonCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelFPGAButtonCallback(int index, int uid);
+  public static native boolean getFPGAButton(int index);
+  public static native void setFPGAButton(int index, boolean fPGAButton);
+
+  public static native int registerVInVoltageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelVInVoltageCallback(int index, int uid);
+  public static native double getVInVoltage(int index);
+  public static native void setVInVoltage(int index, double vInVoltage);
+
+  public static native int registerVInCurrentCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelVInCurrentCallback(int index, int uid);
+  public static native double getVInCurrent(int index);
+  public static native void setVInCurrent(int index, double vInCurrent);
+
+  public static native int registerUserVoltage6VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserVoltage6VCallback(int index, int uid);
+  public static native double getUserVoltage6V(int index);
+  public static native void setUserVoltage6V(int index, double userVoltage6V);
+
+  public static native int registerUserCurrent6VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserCurrent6VCallback(int index, int uid);
+  public static native double getUserCurrent6V(int index);
+  public static native void setUserCurrent6V(int index, double userCurrent6V);
+
+  public static native int registerUserActive6VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserActive6VCallback(int index, int uid);
+  public static native boolean getUserActive6V(int index);
+  public static native void setUserActive6V(int index, boolean userActive6V);
+
+  public static native int registerUserVoltage5VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserVoltage5VCallback(int index, int uid);
+  public static native double getUserVoltage5V(int index);
+  public static native void setUserVoltage5V(int index, double userVoltage5V);
+
+  public static native int registerUserCurrent5VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserCurrent5VCallback(int index, int uid);
+  public static native double getUserCurrent5V(int index);
+  public static native void setUserCurrent5V(int index, double userCurrent5V);
+
+  public static native int registerUserActive5VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserActive5VCallback(int index, int uid);
+  public static native boolean getUserActive5V(int index);
+  public static native void setUserActive5V(int index, boolean userActive5V);
+
+  public static native int registerUserVoltage3V3Callback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserVoltage3V3Callback(int index, int uid);
+  public static native double getUserVoltage3V3(int index);
+  public static native void setUserVoltage3V3(int index, double userVoltage3V3);
+
+  public static native int registerUserCurrent3V3Callback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserCurrent3V3Callback(int index, int uid);
+  public static native double getUserCurrent3V3(int index);
+  public static native void setUserCurrent3V3(int index, double userCurrent3V3);
+
+  public static native int registerUserActive3V3Callback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserActive3V3Callback(int index, int uid);
+  public static native boolean getUserActive3V3(int index);
+  public static native void setUserActive3V3(int index, boolean userActive3V3);
+
+  public static native int registerUserFaults6VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserFaults6VCallback(int index, int uid);
+  public static native int getUserFaults6V(int index);
+  public static native void setUserFaults6V(int index, int userFaults6V);
+
+  public static native int registerUserFaults5VCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserFaults5VCallback(int index, int uid);
+  public static native int getUserFaults5V(int index);
+  public static native void setUserFaults5V(int index, int userFaults5V);
+
+  public static native int registerUserFaults3V3Callback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelUserFaults3V3Callback(int index, int uid);
+  public static native int getUserFaults3V3(int index);
+  public static native void setUserFaults3V3(int index, int userFaults3V3);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SPIAccelerometerDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SPIAccelerometerDataJNI.java
new file mode 100644
index 0000000..d8e7353
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SPIAccelerometerDataJNI.java
@@ -0,0 +1,40 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class SPIAccelerometerDataJNI extends JNIWrapper {
+  public static native int registerActiveCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelActiveCallback(int index, int uid);
+  public static native boolean getActive(int index);
+  public static native void setActive(int index, boolean active);
+
+  public static native int registerRangeCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelRangeCallback(int index, int uid);
+  public static native int getRange(int index);
+  public static native void setRange(int index, int range);
+
+  public static native int registerXCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelXCallback(int index, int uid);
+  public static native double getX(int index);
+  public static native void setX(int index, double x);
+
+  public static native int registerYCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelYCallback(int index, int uid);
+  public static native double getY(int index);
+  public static native void setY(int index, double y);
+
+  public static native int registerZCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelZCallback(int index, int uid);
+  public static native double getZ(int index);
+  public static native void setZ(int index, double z);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SPIDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SPIDataJNI.java
new file mode 100644
index 0000000..a12ec66
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SPIDataJNI.java
@@ -0,0 +1,32 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.sim.BufferCallback;
+import edu.wpi.first.hal.sim.ConstBufferCallback;
+import edu.wpi.first.hal.sim.NotifyCallback;
+import edu.wpi.first.hal.sim.SpiReadAutoReceiveBufferCallback;
+import edu.wpi.first.hal.JNIWrapper;
+
+public class SPIDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native void cancelInitializedCallback(int index, int uid);
+  public static native boolean getInitialized(int index);
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerReadCallback(int index, BufferCallback callback);
+  public static native void cancelReadCallback(int index, int uid);
+
+  public static native int registerWriteCallback(int index, ConstBufferCallback callback);
+  public static native void cancelWriteCallback(int index, int uid);
+
+  public static native int registerReadAutoReceiveBufferCallback(int index, SpiReadAutoReceiveBufferCallback callback);
+  public static native void cancelReadAutoReceiveBufferCallback(int index, int uid);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SimulatorJNI.java b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SimulatorJNI.java
new file mode 100644
index 0000000..bb86005
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/sim/mockdata/SimulatorJNI.java
@@ -0,0 +1,17 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim.mockdata;
+
+import edu.wpi.first.hal.JNIWrapper;
+
+public class SimulatorJNI extends JNIWrapper {
+  public static native void waitForProgramStart();
+  public static native void setProgramStarted();
+  public static native void restartTiming();
+  public static native void resetHandles();
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/AllocationException.java b/hal/src/main/java/edu/wpi/first/hal/util/AllocationException.java
new file mode 100644
index 0000000..6f789d8
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/util/AllocationException.java
@@ -0,0 +1,22 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.util;
+
+/**
+ * Exception indicating that the resource is already allocated.
+ */
+public class AllocationException extends RuntimeException {
+  /**
+   * Create a new AllocationException.
+   *
+   * @param msg the message to attach to the exception
+   */
+  public AllocationException(String msg) {
+    super(msg);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/BoundaryException.java b/hal/src/main/java/edu/wpi/first/hal/util/BoundaryException.java
new file mode 100644
index 0000000..8f21e60
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/util/BoundaryException.java
@@ -0,0 +1,50 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.util;
+
+/**
+ * This exception represents an error in which a lower limit was set as higher than an upper limit.
+ */
+public class BoundaryException extends RuntimeException {
+  /**
+   * Create a new exception with the given message.
+   *
+   * @param message the message to attach to the exception
+   */
+  public BoundaryException(String message) {
+    super(message);
+  }
+
+  /**
+   * Make sure that the given value is between the upper and lower bounds, and throw an exception if
+   * they are not.
+   *
+   * @param value The value to check.
+   * @param lower The minimum acceptable value.
+   * @param upper The maximum acceptable value.
+   */
+  public static void assertWithinBounds(double value, double lower, double upper) {
+    if (value < lower || value > upper) {
+      throw new BoundaryException("Value must be between " + lower + " and " + upper + ", " + value
+          + " given");
+    }
+  }
+
+  /**
+   * Returns the message for a boundary exception. Used to keep the message consistent across all
+   * boundary exceptions.
+   *
+   * @param value The given value
+   * @param lower The lower limit
+   * @param upper The upper limit
+   * @return the message for a boundary exception
+   */
+  public static String getMessage(double value, double lower, double upper) {
+    return "Value must be between " + lower + " and " + upper + ", " + value + " given";
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/CheckedAllocationException.java b/hal/src/main/java/edu/wpi/first/hal/util/CheckedAllocationException.java
new file mode 100644
index 0000000..f17e381
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/util/CheckedAllocationException.java
@@ -0,0 +1,23 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.util;
+
+/**
+ * Exception indicating that the resource is already allocated This is meant to be thrown by the
+ * resource class.
+ */
+public class CheckedAllocationException extends Exception {
+  /**
+   * Create a new CheckedAllocationException.
+   *
+   * @param msg the message to attach to the exception
+   */
+  public CheckedAllocationException(String msg) {
+    super(msg);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/HalHandleException.java b/hal/src/main/java/edu/wpi/first/hal/util/HalHandleException.java
new file mode 100644
index 0000000..874b07a
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/util/HalHandleException.java
@@ -0,0 +1,22 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.util;
+
+/**
+ * Exception indicating that an error has occured with a HAL Handle.
+ */
+public class HalHandleException extends RuntimeException {
+  /**
+   * Create a new HalHandleException.
+   *
+   * @param msg the message to attach to the exception
+   */
+  public HalHandleException(String msg) {
+    super(msg);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/UncleanStatusException.java b/hal/src/main/java/edu/wpi/first/hal/util/UncleanStatusException.java
new file mode 100644
index 0000000..3a3e217
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/util/UncleanStatusException.java
@@ -0,0 +1,60 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.util;
+
+/**
+ * Exception for bad status codes from the chip object.
+ */
+public final class UncleanStatusException extends IllegalStateException {
+  private final int m_statusCode;
+
+  /**
+   * Create a new UncleanStatusException.
+   *
+   * @param status  the status code that caused the exception
+   * @param message A message describing the exception
+   */
+  public UncleanStatusException(int status, String message) {
+    super(message);
+    m_statusCode = status;
+  }
+
+  /**
+   * Create a new UncleanStatusException.
+   *
+   * @param status the status code that caused the exception
+   */
+  public UncleanStatusException(int status) {
+    this(status, "Status code was non-zero");
+  }
+
+  /**
+   * Create a new UncleanStatusException.
+   *
+   * @param message a message describing the exception
+   */
+  public UncleanStatusException(String message) {
+    this(-1, message);
+  }
+
+  /**
+   * Create a new UncleanStatusException.
+   */
+  public UncleanStatusException() {
+    this(-1, "Status code was non-zero");
+  }
+
+  /**
+   * Create a new UncleanStatusException.
+   *
+   * @return the status code that caused the exception
+   */
+  public int getStatus() {
+    return m_statusCode;
+  }
+}
diff --git a/hal/src/main/native/athena/Accelerometer.cpp b/hal/src/main/native/athena/Accelerometer.cpp
new file mode 100644
index 0000000..f83c06e
--- /dev/null
+++ b/hal/src/main/native/athena/Accelerometer.cpp
@@ -0,0 +1,243 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Accelerometer.h"
+
+#include <stdint.h>
+
+#include <cassert>
+#include <cstdio>
+#include <memory>
+
+#include "HALInitializer.h"
+#include "hal/ChipObject.h"
+#include "hal/HAL.h"
+
+using namespace hal;
+
+// The 7-bit I2C address with a 0 "send" bit
+static constexpr uint8_t kSendAddress = (0x1c << 1) | 0;
+
+// The 7-bit I2C address with a 1 "receive" bit
+static constexpr uint8_t kReceiveAddress = (0x1c << 1) | 1;
+
+static constexpr uint8_t kControlTxRx = 1;
+static constexpr uint8_t kControlStart = 2;
+static constexpr uint8_t kControlStop = 4;
+
+static std::unique_ptr<tAccel> accel;
+static HAL_AccelerometerRange accelerometerRange;
+
+// Register addresses
+enum Register {
+  kReg_Status = 0x00,
+  kReg_OutXMSB = 0x01,
+  kReg_OutXLSB = 0x02,
+  kReg_OutYMSB = 0x03,
+  kReg_OutYLSB = 0x04,
+  kReg_OutZMSB = 0x05,
+  kReg_OutZLSB = 0x06,
+  kReg_Sysmod = 0x0B,
+  kReg_IntSource = 0x0C,
+  kReg_WhoAmI = 0x0D,
+  kReg_XYZDataCfg = 0x0E,
+  kReg_HPFilterCutoff = 0x0F,
+  kReg_PLStatus = 0x10,
+  kReg_PLCfg = 0x11,
+  kReg_PLCount = 0x12,
+  kReg_PLBfZcomp = 0x13,
+  kReg_PLThsReg = 0x14,
+  kReg_FFMtCfg = 0x15,
+  kReg_FFMtSrc = 0x16,
+  kReg_FFMtThs = 0x17,
+  kReg_FFMtCount = 0x18,
+  kReg_TransientCfg = 0x1D,
+  kReg_TransientSrc = 0x1E,
+  kReg_TransientThs = 0x1F,
+  kReg_TransientCount = 0x20,
+  kReg_PulseCfg = 0x21,
+  kReg_PulseSrc = 0x22,
+  kReg_PulseThsx = 0x23,
+  kReg_PulseThsy = 0x24,
+  kReg_PulseThsz = 0x25,
+  kReg_PulseTmlt = 0x26,
+  kReg_PulseLtcy = 0x27,
+  kReg_PulseWind = 0x28,
+  kReg_ASlpCount = 0x29,
+  kReg_CtrlReg1 = 0x2A,
+  kReg_CtrlReg2 = 0x2B,
+  kReg_CtrlReg3 = 0x2C,
+  kReg_CtrlReg4 = 0x2D,
+  kReg_CtrlReg5 = 0x2E,
+  kReg_OffX = 0x2F,
+  kReg_OffY = 0x30,
+  kReg_OffZ = 0x31
+};
+
+namespace hal {
+namespace init {
+void InitializeAccelerometer() {}
+}  // namespace init
+}  // namespace hal
+
+namespace hal {
+
+static void writeRegister(Register reg, uint8_t data);
+static uint8_t readRegister(Register reg);
+
+/**
+ * Initialize the accelerometer.
+ */
+static void initializeAccelerometer() {
+  hal::init::CheckInit();
+  int32_t status;
+
+  if (!accel) {
+    accel.reset(tAccel::create(&status));
+
+    accelerometerRange = HAL_AccelerometerRange::HAL_AccelerometerRange_k2G;
+
+    // Enable I2C
+    accel->writeCNFG(1, &status);
+
+    // Set the counter to 100 kbps
+    accel->writeCNTR(213, &status);
+
+    // The device identification number should be 0x2a
+    assert(readRegister(kReg_WhoAmI) == 0x2a);
+  }
+}
+
+static void writeRegister(Register reg, uint8_t data) {
+  int32_t status = 0;
+  uint64_t initialTime;
+
+  accel->writeADDR(kSendAddress, &status);
+
+  // Send a start transmit/receive message with the register address
+  accel->writeCNTL(kControlStart | kControlTxRx, &status);
+  accel->writeDATO(reg, &status);
+  accel->strobeGO(&status);
+
+  // Execute and wait until it's done (up to a millisecond)
+  initialTime = HAL_GetFPGATime(&status);
+  while (accel->readSTAT(&status) & 1) {
+    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+  }
+
+  // Send a stop transmit/receive message with the data
+  accel->writeCNTL(kControlStop | kControlTxRx, &status);
+  accel->writeDATO(data, &status);
+  accel->strobeGO(&status);
+
+  // Execute and wait until it's done (up to a millisecond)
+  initialTime = HAL_GetFPGATime(&status);
+  while (accel->readSTAT(&status) & 1) {
+    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+  }
+}
+
+static uint8_t readRegister(Register reg) {
+  int32_t status = 0;
+  uint64_t initialTime;
+
+  // Send a start transmit/receive message with the register address
+  accel->writeADDR(kSendAddress, &status);
+  accel->writeCNTL(kControlStart | kControlTxRx, &status);
+  accel->writeDATO(reg, &status);
+  accel->strobeGO(&status);
+
+  // Execute and wait until it's done (up to a millisecond)
+  initialTime = HAL_GetFPGATime(&status);
+  while (accel->readSTAT(&status) & 1) {
+    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+  }
+
+  // Receive a message with the data and stop
+  accel->writeADDR(kReceiveAddress, &status);
+  accel->writeCNTL(kControlStart | kControlStop | kControlTxRx, &status);
+  accel->strobeGO(&status);
+
+  // Execute and wait until it's done (up to a millisecond)
+  initialTime = HAL_GetFPGATime(&status);
+  while (accel->readSTAT(&status) & 1) {
+    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+  }
+
+  return accel->readDATI(&status);
+}
+
+/**
+ * Convert a 12-bit raw acceleration value into a scaled double in units of
+ * 1 g-force, taking into account the accelerometer range.
+ */
+static double unpackAxis(int16_t raw) {
+  // The raw value is actually 12 bits, not 16, so we need to propogate the
+  // 2's complement sign bit to the unused 4 bits for this to work with
+  // negative numbers.
+  raw <<= 4;
+  raw >>= 4;
+
+  switch (accelerometerRange) {
+    case HAL_AccelerometerRange_k2G:
+      return raw / 1024.0;
+    case HAL_AccelerometerRange_k4G:
+      return raw / 512.0;
+    case HAL_AccelerometerRange_k8G:
+      return raw / 256.0;
+    default:
+      return 0.0;
+  }
+}
+
+}  // namespace hal
+
+extern "C" {
+
+void HAL_SetAccelerometerActive(HAL_Bool active) {
+  initializeAccelerometer();
+
+  uint8_t ctrlReg1 = readRegister(kReg_CtrlReg1);
+  ctrlReg1 &= ~1;  // Clear the existing active bit
+  writeRegister(kReg_CtrlReg1, ctrlReg1 | (active ? 1 : 0));
+}
+
+void HAL_SetAccelerometerRange(HAL_AccelerometerRange range) {
+  initializeAccelerometer();
+
+  accelerometerRange = range;
+
+  uint8_t xyzDataCfg = readRegister(kReg_XYZDataCfg);
+  xyzDataCfg &= ~3;  // Clear the existing two range bits
+  writeRegister(kReg_XYZDataCfg, xyzDataCfg | range);
+}
+
+double HAL_GetAccelerometerX(void) {
+  initializeAccelerometer();
+
+  int32_t raw =
+      (readRegister(kReg_OutXMSB) << 4) | (readRegister(kReg_OutXLSB) >> 4);
+  return unpackAxis(raw);
+}
+
+double HAL_GetAccelerometerY(void) {
+  initializeAccelerometer();
+
+  int32_t raw =
+      (readRegister(kReg_OutYMSB) << 4) | (readRegister(kReg_OutYLSB) >> 4);
+  return unpackAxis(raw);
+}
+
+double HAL_GetAccelerometerZ(void) {
+  initializeAccelerometer();
+
+  int32_t raw =
+      (readRegister(kReg_OutZMSB) << 4) | (readRegister(kReg_OutZLSB) >> 4);
+  return unpackAxis(raw);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/AnalogAccumulator.cpp b/hal/src/main/native/athena/AnalogAccumulator.cpp
new file mode 100644
index 0000000..6664c52
--- /dev/null
+++ b/hal/src/main/native/athena/AnalogAccumulator.cpp
@@ -0,0 +1,139 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogAccumulator.h"
+
+#include "AnalogInternal.h"
+#include "hal/HAL.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAnalogAccumulator() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_Bool HAL_IsAccumulatorChannel(HAL_AnalogInputHandle analogPortHandle,
+                                  int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  for (int32_t i = 0; i < kNumAccumulators; i++) {
+    if (port->channel == kAccumulatorChannels[i]) return true;
+  }
+  return false;
+}
+
+void HAL_InitAccumulator(HAL_AnalogInputHandle analogPortHandle,
+                         int32_t* status) {
+  if (!HAL_IsAccumulatorChannel(analogPortHandle, status)) {
+    *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
+    return;
+  }
+  HAL_SetAccumulatorCenter(analogPortHandle, 0, status);
+  HAL_ResetAccumulator(analogPortHandle, status);
+}
+
+void HAL_ResetAccumulator(HAL_AnalogInputHandle analogPortHandle,
+                          int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (port->accumulator == nullptr) {
+    *status = NULL_PARAMETER;
+    return;
+  }
+  port->accumulator->strobeReset(status);
+}
+
+void HAL_SetAccumulatorCenter(HAL_AnalogInputHandle analogPortHandle,
+                              int32_t center, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (port->accumulator == nullptr) {
+    *status = NULL_PARAMETER;
+    return;
+  }
+  port->accumulator->writeCenter(center, status);
+}
+
+void HAL_SetAccumulatorDeadband(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t deadband, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (port->accumulator == nullptr) {
+    *status = NULL_PARAMETER;
+    return;
+  }
+  port->accumulator->writeDeadband(deadband, status);
+}
+
+int64_t HAL_GetAccumulatorValue(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  if (port->accumulator == nullptr) {
+    *status = NULL_PARAMETER;
+    return 0;
+  }
+  int64_t value = port->accumulator->readOutput_Value(status);
+  return value;
+}
+
+int64_t HAL_GetAccumulatorCount(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  if (port->accumulator == nullptr) {
+    *status = NULL_PARAMETER;
+    return 0;
+  }
+  return port->accumulator->readOutput_Count(status);
+}
+
+void HAL_GetAccumulatorOutput(HAL_AnalogInputHandle analogPortHandle,
+                              int64_t* value, int64_t* count, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (port->accumulator == nullptr) {
+    *status = NULL_PARAMETER;
+    return;
+  }
+  if (value == nullptr || count == nullptr) {
+    *status = NULL_PARAMETER;
+    return;
+  }
+
+  tAccumulator::tOutput output = port->accumulator->readOutput(status);
+
+  *value = output.Value;
+  *count = output.Count;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/AnalogGyro.cpp b/hal/src/main/native/athena/AnalogGyro.cpp
new file mode 100644
index 0000000..56b6f28
--- /dev/null
+++ b/hal/src/main/native/athena/AnalogGyro.cpp
@@ -0,0 +1,261 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogGyro.h"
+
+#include <thread>
+
+#include <wpi/raw_ostream.h>
+
+#include "AnalogInternal.h"
+#include "HALInitializer.h"
+#include "hal/AnalogAccumulator.h"
+#include "hal/AnalogInput.h"
+#include "hal/handles/IndexedHandleResource.h"
+
+namespace {
+
+struct AnalogGyro {
+  HAL_AnalogInputHandle handle;
+  double voltsPerDegreePerSecond;
+  double offset;
+  int32_t center;
+};
+
+}  // namespace
+
+static constexpr uint32_t kOversampleBits = 10;
+static constexpr uint32_t kAverageBits = 0;
+static constexpr double kSamplesPerSecond = 50.0;
+static constexpr double kCalibrationSampleTime = 5.0;
+static constexpr double kDefaultVoltsPerDegreePerSecond = 0.007;
+
+using namespace hal;
+
+static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
+                             HAL_HandleEnum::AnalogGyro>* analogGyroHandles;
+
+namespace hal {
+namespace init {
+void InitializeAnalogGyro() {
+  static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
+                               HAL_HandleEnum::AnalogGyro>
+      agHandles;
+  analogGyroHandles = &agHandles;
+}
+}  // namespace init
+}  // namespace hal
+
+static void Wait(double seconds) {
+  if (seconds < 0.0) return;
+  std::this_thread::sleep_for(std::chrono::duration<double>(seconds));
+}
+
+extern "C" {
+
+HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  if (!HAL_IsAccumulatorChannel(analogHandle, status)) {
+    if (*status == 0) {
+      *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
+    }
+    return HAL_kInvalidHandle;
+  }
+
+  // handle known to be correct, so no need to type check
+  int16_t channel = getHandleIndex(analogHandle);
+
+  auto handle = analogGyroHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  // Initialize port structure
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {  // would only error on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  gyro->handle = analogHandle;
+  gyro->voltsPerDegreePerSecond = 0;
+  gyro->offset = 0;
+  gyro->center = 0;
+
+  return handle;
+}
+
+void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  gyro->voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
+
+  HAL_SetAnalogAverageBits(gyro->handle, kAverageBits, status);
+  if (*status != 0) return;
+  HAL_SetAnalogOversampleBits(gyro->handle, kOversampleBits, status);
+  if (*status != 0) return;
+  double sampleRate =
+      kSamplesPerSecond * (1 << (kAverageBits + kOversampleBits));
+  HAL_SetAnalogSampleRate(sampleRate, status);
+  if (*status != 0) return;
+  Wait(0.1);
+
+  HAL_SetAnalogGyroDeadband(handle, 0.0, status);
+  if (*status != 0) return;
+}
+
+void HAL_FreeAnalogGyro(HAL_GyroHandle handle) {
+  analogGyroHandles->Free(handle);
+}
+
+void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
+                                 double voltsPerDegreePerSecond, double offset,
+                                 int32_t center, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
+  gyro->offset = offset;
+  gyro->center = center;
+  HAL_SetAccumulatorCenter(gyro->handle, center, status);
+}
+
+void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
+                                              double voltsPerDegreePerSecond,
+                                              int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
+}
+
+void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  HAL_ResetAccumulator(gyro->handle, status);
+  if (*status != 0) return;
+
+  const double sampleTime = 1.0 / HAL_GetAnalogSampleRate(status);
+  const double overSamples =
+      1 << HAL_GetAnalogOversampleBits(gyro->handle, status);
+  const double averageSamples =
+      1 << HAL_GetAnalogAverageBits(gyro->handle, status);
+  if (*status != 0) return;
+  Wait(sampleTime * overSamples * averageSamples);
+}
+
+void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  HAL_InitAccumulator(gyro->handle, status);
+  if (*status != 0) return;
+  wpi::outs() << "Calibrating analog gyro for " << kCalibrationSampleTime
+              << " seconds." << '\n';
+  Wait(kCalibrationSampleTime);
+
+  int64_t value;
+  int64_t count;
+  HAL_GetAccumulatorOutput(gyro->handle, &value, &count, status);
+  if (*status != 0) return;
+
+  gyro->center = static_cast<int32_t>(
+      static_cast<double>(value) / static_cast<double>(count) + .5);
+
+  gyro->offset = static_cast<double>(value) / static_cast<double>(count) -
+                 static_cast<double>(gyro->center);
+  HAL_SetAccumulatorCenter(gyro->handle, gyro->center, status);
+  if (*status != 0) return;
+  HAL_ResetAnalogGyro(handle, status);
+}
+
+void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
+                               int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  int32_t deadband = static_cast<int32_t>(
+      volts * 1e9 / HAL_GetAnalogLSBWeight(gyro->handle, status) *
+      (1 << HAL_GetAnalogOversampleBits(gyro->handle, status)));
+  if (*status != 0) return;
+  HAL_SetAccumulatorDeadband(gyro->handle, deadband, status);
+}
+
+double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  int64_t rawValue = 0;
+  int64_t count = 0;
+  HAL_GetAccumulatorOutput(gyro->handle, &rawValue, &count, status);
+
+  int64_t value = rawValue - static_cast<int64_t>(static_cast<double>(count) *
+                                                  gyro->offset);
+
+  double scaledValue =
+      value * 1e-9 *
+      static_cast<double>(HAL_GetAnalogLSBWeight(gyro->handle, status)) *
+      static_cast<double>(1 << HAL_GetAnalogAverageBits(gyro->handle, status)) /
+      (HAL_GetAnalogSampleRate(status) * gyro->voltsPerDegreePerSecond);
+
+  return scaledValue;
+}
+
+double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return (HAL_GetAnalogAverageValue(gyro->handle, status) -
+          (static_cast<double>(gyro->center) + gyro->offset)) *
+         1e-9 * HAL_GetAnalogLSBWeight(gyro->handle, status) /
+         ((1 << HAL_GetAnalogOversampleBits(gyro->handle, status)) *
+          gyro->voltsPerDegreePerSecond);
+}
+
+double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return gyro->offset;
+}
+
+int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return gyro->center;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/AnalogInput.cpp b/hal/src/main/native/athena/AnalogInput.cpp
new file mode 100644
index 0000000..b11280d
--- /dev/null
+++ b/hal/src/main/native/athena/AnalogInput.cpp
@@ -0,0 +1,238 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogInput.h"
+
+#include <FRC_NetworkCommunication/AICalibration.h>
+#include <wpi/mutex.h>
+
+#include "AnalogInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/AnalogAccumulator.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+namespace init {
+void InitializeAnalogInput() {}
+}  // namespace init
+}  // namespace hal
+
+using namespace hal;
+
+extern "C" {
+
+HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle,
+                                                    int32_t* status) {
+  hal::init::CheckInit();
+  initializeAnalog(status);
+
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  HAL_AnalogInputHandle handle = analogInputHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  // Initialize port structure
+  auto analog_port = analogInputHandles->Get(handle);
+  if (analog_port == nullptr) {  // would only error on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  analog_port->channel = static_cast<uint8_t>(channel);
+  if (HAL_IsAccumulatorChannel(handle, status)) {
+    analog_port->accumulator.reset(tAccumulator::create(channel, status));
+  } else {
+    analog_port->accumulator = nullptr;
+  }
+
+  // Set default configuration
+  analogInputSystem->writeScanList(channel, channel, status);
+  HAL_SetAnalogAverageBits(handle, kDefaultAverageBits, status);
+  HAL_SetAnalogOversampleBits(handle, kDefaultOversampleBits, status);
+  return handle;
+}
+
+void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle) {
+  // no status, so no need to check for a proper free.
+  analogInputHandles->Free(analogPortHandle);
+}
+
+HAL_Bool HAL_CheckAnalogModule(int32_t module) { return module == 1; }
+
+HAL_Bool HAL_CheckAnalogInputChannel(int32_t channel) {
+  return channel < kNumAnalogInputs && channel >= 0;
+}
+
+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.
+  // wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
+  initializeAnalog(status);
+  if (*status != 0) return;
+  setAnalogSampleRate(samplesPerSecond, status);
+}
+
+double HAL_GetAnalogSampleRate(int32_t* status) {
+  initializeAnalog(status);
+  if (*status != 0) return 0;
+  uint32_t ticksPerConversion = analogInputSystem->readLoopTiming(status);
+  uint32_t ticksPerSample =
+      ticksPerConversion * getAnalogNumActiveChannels(status);
+  return static_cast<double>(kTimebase) / static_cast<double>(ticksPerSample);
+}
+
+void HAL_SetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
+                              int32_t bits, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  analogInputSystem->writeAverageBits(port->channel, static_cast<uint8_t>(bits),
+                                      status);
+}
+
+int32_t HAL_GetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
+                                 int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return kDefaultAverageBits;
+  }
+  uint8_t result = analogInputSystem->readAverageBits(port->channel, status);
+  return result;
+}
+
+void HAL_SetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
+                                 int32_t bits, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  analogInputSystem->writeOversampleBits(port->channel,
+                                         static_cast<uint8_t>(bits), status);
+}
+
+int32_t HAL_GetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
+                                    int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return kDefaultOversampleBits;
+  }
+  uint8_t result = analogInputSystem->readOversampleBits(port->channel, status);
+  return result;
+}
+
+int32_t HAL_GetAnalogValue(HAL_AnalogInputHandle analogPortHandle,
+                           int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  tAI::tReadSelect readSelect;
+  readSelect.Channel = port->channel;
+  readSelect.Averaged = false;
+
+  std::lock_guard<wpi::mutex> lock(analogRegisterWindowMutex);
+  analogInputSystem->writeReadSelect(readSelect, status);
+  analogInputSystem->strobeLatchOutput(status);
+  return static_cast<int16_t>(analogInputSystem->readOutput(status));
+}
+
+int32_t HAL_GetAnalogAverageValue(HAL_AnalogInputHandle analogPortHandle,
+                                  int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  tAI::tReadSelect readSelect;
+  readSelect.Channel = port->channel;
+  readSelect.Averaged = true;
+
+  std::lock_guard<wpi::mutex> lock(analogRegisterWindowMutex);
+  analogInputSystem->writeReadSelect(readSelect, status);
+  analogInputSystem->strobeLatchOutput(status);
+  return static_cast<int32_t>(analogInputSystem->readOutput(status));
+}
+
+int32_t HAL_GetAnalogVoltsToValue(HAL_AnalogInputHandle analogPortHandle,
+                                  double voltage, int32_t* status) {
+  if (voltage > 5.0) {
+    voltage = 5.0;
+    *status = VOLTAGE_OUT_OF_RANGE;
+  }
+  if (voltage < 0.0) {
+    voltage = 0.0;
+    *status = VOLTAGE_OUT_OF_RANGE;
+  }
+  int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogPortHandle, status);
+  int32_t offset = HAL_GetAnalogOffset(analogPortHandle, status);
+  int32_t value =
+      static_cast<int32_t>((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9));
+  return value;
+}
+
+double HAL_GetAnalogVoltage(HAL_AnalogInputHandle analogPortHandle,
+                            int32_t* status) {
+  int32_t value = HAL_GetAnalogValue(analogPortHandle, status);
+  int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogPortHandle, status);
+  int32_t offset = HAL_GetAnalogOffset(analogPortHandle, status);
+  double voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
+  return voltage;
+}
+
+double HAL_GetAnalogAverageVoltage(HAL_AnalogInputHandle analogPortHandle,
+                                   int32_t* status) {
+  int32_t value = HAL_GetAnalogAverageValue(analogPortHandle, status);
+  int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogPortHandle, status);
+  int32_t offset = HAL_GetAnalogOffset(analogPortHandle, status);
+  int32_t oversampleBits =
+      HAL_GetAnalogOversampleBits(analogPortHandle, status);
+  double voltage =
+      LSBWeight * 1.0e-9 * value / static_cast<double>(1 << oversampleBits) -
+      offset * 1.0e-9;
+  return voltage;
+}
+
+int32_t HAL_GetAnalogLSBWeight(HAL_AnalogInputHandle analogPortHandle,
+                               int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  int32_t lsbWeight = FRC_NetworkCommunication_nAICalibration_getLSBWeight(
+      0, port->channel, status);  // XXX: aiSystemIndex == 0?
+  return lsbWeight;
+}
+
+int32_t HAL_GetAnalogOffset(HAL_AnalogInputHandle analogPortHandle,
+                            int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  int32_t offset = FRC_NetworkCommunication_nAICalibration_getOffset(
+      0, port->channel, status);  // XXX: aiSystemIndex == 0?
+  return offset;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/AnalogInternal.cpp b/hal/src/main/native/athena/AnalogInternal.cpp
new file mode 100644
index 0000000..6e02def
--- /dev/null
+++ b/hal/src/main/native/athena/AnalogInternal.cpp
@@ -0,0 +1,100 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "AnalogInternal.h"
+
+#include <atomic>
+
+#include <wpi/mutex.h>
+
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/AnalogInput.h"
+#include "hal/ChipObject.h"
+
+namespace hal {
+
+wpi::mutex analogRegisterWindowMutex;
+std::unique_ptr<tAI> analogInputSystem;
+std::unique_ptr<tAO> analogOutputSystem;
+
+IndexedHandleResource<HAL_AnalogInputHandle, ::hal::AnalogPort,
+                      kNumAnalogInputs, HAL_HandleEnum::AnalogInput>*
+    analogInputHandles;
+
+static int32_t analogNumChannelsToActivate = 0;
+
+static std::atomic<bool> analogSystemInitialized{false};
+
+bool analogSampleRateSet = false;
+
+namespace init {
+void InitializeAnalogInternal() {
+  static IndexedHandleResource<HAL_AnalogInputHandle, ::hal::AnalogPort,
+                               kNumAnalogInputs, HAL_HandleEnum::AnalogInput>
+      alH;
+  analogInputHandles = &alH;
+}
+}  // namespace init
+
+void initializeAnalog(int32_t* status) {
+  hal::init::CheckInit();
+  if (analogSystemInitialized) return;
+  std::lock_guard<wpi::mutex> lock(analogRegisterWindowMutex);
+  if (analogSystemInitialized) return;
+  analogInputSystem.reset(tAI::create(status));
+  analogOutputSystem.reset(tAO::create(status));
+  setAnalogNumChannelsToActivate(kNumAnalogInputs);
+  setAnalogSampleRate(kDefaultSampleRate, status);
+  analogSystemInitialized = true;
+}
+
+int32_t getAnalogNumActiveChannels(int32_t* status) {
+  int32_t scanSize = analogInputSystem->readConfig_ScanSize(status);
+  if (scanSize == 0) return 8;
+  return scanSize;
+}
+
+void setAnalogNumChannelsToActivate(int32_t channels) {
+  analogNumChannelsToActivate = channels;
+}
+
+int32_t getAnalogNumChannelsToActivate(int32_t* status) {
+  if (analogNumChannelsToActivate == 0)
+    return getAnalogNumActiveChannels(status);
+  return analogNumChannelsToActivate;
+}
+
+void setAnalogSampleRate(double samplesPerSecond, int32_t* status) {
+  // TODO: This will change when variable size scan lists are implemented.
+  // TODO: Need double comparison with epsilon.
+  // wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
+  analogSampleRateSet = true;
+
+  // Compute the convert rate
+  uint32_t ticksPerSample =
+      static_cast<uint32_t>(static_cast<double>(kTimebase) / samplesPerSecond);
+  uint32_t ticksPerConversion =
+      ticksPerSample / getAnalogNumChannelsToActivate(status);
+  // ticksPerConversion must be at least 80
+  if (ticksPerConversion < 80) {
+    if ((*status) >= 0) *status = SAMPLE_RATE_TOO_HIGH;
+    ticksPerConversion = 80;
+  }
+
+  // Atomically set the scan size and the convert rate so that the sample rate
+  // is constant
+  tAI::tConfig config;
+  config.ScanSize = getAnalogNumChannelsToActivate(status);
+  config.ConvertRate = ticksPerConversion;
+  analogInputSystem->writeConfig(config, status);
+
+  // Indicate that the scan size has been commited to hardware.
+  setAnalogNumChannelsToActivate(0);
+}
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/AnalogInternal.h b/hal/src/main/native/athena/AnalogInternal.h
new file mode 100644
index 0000000..a74562f
--- /dev/null
+++ b/hal/src/main/native/athena/AnalogInternal.h
@@ -0,0 +1,88 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <memory>
+
+#include <wpi/mutex.h>
+
+#include "PortsInternal.h"
+#include "hal/ChipObject.h"
+#include "hal/Ports.h"
+#include "hal/handles/IndexedHandleResource.h"
+
+namespace hal {
+
+constexpr int32_t kTimebase = 40000000;  ///< 40 MHz clock
+constexpr int32_t kDefaultOversampleBits = 0;
+constexpr int32_t kDefaultAverageBits = 7;
+constexpr double kDefaultSampleRate = 50000.0;
+static constexpr uint32_t kAccumulatorChannels[] = {0, 1};
+
+extern std::unique_ptr<tAI> analogInputSystem;
+extern std::unique_ptr<tAO> analogOutputSystem;
+extern wpi::mutex analogRegisterWindowMutex;
+extern bool analogSampleRateSet;
+
+struct AnalogPort {
+  uint8_t channel;
+  std::unique_ptr<tAccumulator> accumulator;
+};
+
+extern IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
+                             kNumAnalogInputs, HAL_HandleEnum::AnalogInput>*
+    analogInputHandles;
+
+/**
+ * Initialize the analog System.
+ */
+void initializeAnalog(int32_t* status);
+
+/**
+ * Return the number of channels on the module in use.
+ *
+ * @return Active channels.
+ */
+int32_t getAnalogNumActiveChannels(int32_t* status);
+
+/**
+ * Set the number of active channels.
+ *
+ * Store the number of active channels to set.  Don't actually commit to
+ * hardware
+ * until SetSampleRate().
+ *
+ * @param channels Number of active channels.
+ */
+void setAnalogNumChannelsToActivate(int32_t channels);
+
+/**
+ * Get the number of active channels.
+ *
+ * This is an internal function to allow the atomic update of both the
+ * number of active channels and the sample rate.
+ *
+ * When the number of channels changes, use the new value.  Otherwise,
+ * return the curent value.
+ *
+ * @return Value to write to the active channels field.
+ */
+int32_t getAnalogNumChannelsToActivate(int32_t* status);
+
+/**
+ * Set the sample rate.
+ *
+ * This is a global setting for the Athena and effects all channels.
+ *
+ * @param samplesPerSecond The number of samples per channel per second.
+ */
+void setAnalogSampleRate(double samplesPerSecond, int32_t* status);
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/AnalogOutput.cpp b/hal/src/main/native/athena/AnalogOutput.cpp
new file mode 100644
index 0000000..77f841b
--- /dev/null
+++ b/hal/src/main/native/athena/AnalogOutput.cpp
@@ -0,0 +1,113 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogOutput.h"
+
+#include "AnalogInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/IndexedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+
+struct AnalogOutput {
+  uint8_t channel;
+};
+
+}  // namespace
+
+static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
+                             kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>*
+    analogOutputHandles;
+
+namespace hal {
+namespace init {
+void InitializeAnalogOutput() {
+  static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
+                               kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>
+      aoH;
+  analogOutputHandles = &aoH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle,
+                                                      int32_t* status) {
+  hal::init::CheckInit();
+  initializeAnalog(status);
+
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  HAL_AnalogOutputHandle handle =
+      analogOutputHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = analogOutputHandles->Get(handle);
+  if (port == nullptr) {  // would only error on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  port->channel = static_cast<uint8_t>(channel);
+  return handle;
+}
+
+void HAL_FreeAnalogOutputPort(HAL_AnalogOutputHandle analogOutputHandle) {
+  // no status, so no need to check for a proper free.
+  analogOutputHandles->Free(analogOutputHandle);
+}
+
+void HAL_SetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
+                         double voltage, int32_t* status) {
+  auto port = analogOutputHandles->Get(analogOutputHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint16_t rawValue = static_cast<uint16_t>(voltage / 5.0 * 0x1000);
+
+  if (voltage < 0.0)
+    rawValue = 0;
+  else if (voltage > 5.0)
+    rawValue = 0x1000;
+
+  analogOutputSystem->writeMXP(port->channel, rawValue, status);
+}
+
+double HAL_GetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
+                           int32_t* status) {
+  auto port = analogOutputHandles->Get(analogOutputHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+
+  uint16_t rawValue = analogOutputSystem->readMXP(port->channel, status);
+
+  return rawValue * 5.0 / 0x1000;
+}
+
+HAL_Bool HAL_CheckAnalogOutputChannel(int32_t channel) {
+  return channel < kNumAnalogOutputs && channel >= 0;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/AnalogTrigger.cpp b/hal/src/main/native/athena/AnalogTrigger.cpp
new file mode 100644
index 0000000..1841c51
--- /dev/null
+++ b/hal/src/main/native/athena/AnalogTrigger.cpp
@@ -0,0 +1,192 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogTrigger.h"
+
+#include "AnalogInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/AnalogInput.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+
+struct AnalogTrigger {
+  std::unique_ptr<tAnalogTrigger> trigger;
+  HAL_AnalogInputHandle analogHandle;
+  uint8_t index;
+};
+
+}  // namespace
+
+static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
+                             kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>*
+    analogTriggerHandles;
+
+namespace hal {
+namespace init {
+void InitializeAnalogTrigger() {
+  static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
+                               kNumAnalogTriggers,
+                               HAL_HandleEnum::AnalogTrigger>
+      atH;
+  analogTriggerHandles = &atH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
+    HAL_AnalogInputHandle portHandle, int32_t* index, int32_t* status) {
+  hal::init::CheckInit();
+  // ensure we are given a valid and active AnalogInput handle
+  auto analog_port = analogInputHandles->Get(portHandle);
+  if (analog_port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  HAL_AnalogTriggerHandle handle = analogTriggerHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto trigger = analogTriggerHandles->Get(handle);
+  if (trigger == nullptr) {  // would only occur on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  trigger->analogHandle = portHandle;
+  trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
+  *index = trigger->index;
+
+  trigger->trigger.reset(tAnalogTrigger::create(trigger->index, status));
+  trigger->trigger->writeSourceSelect_Channel(analog_port->channel, status);
+  return handle;
+}
+
+void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
+                            int32_t* status) {
+  analogTriggerHandles->Free(analogTriggerHandle);
+  // caller owns the analog input handle.
+}
+
+void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                   int32_t lower, int32_t upper,
+                                   int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (lower > upper) {
+    *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
+  }
+  trigger->trigger->writeLowerLimit(lower, status);
+  trigger->trigger->writeUpperLimit(upper, status);
+}
+
+void HAL_SetAnalogTriggerLimitsVoltage(
+    HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
+    int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (lower > upper) {
+    *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
+  }
+
+  // TODO: This depends on the averaged setting.  Only raw values will work as
+  // is.
+  trigger->trigger->writeLowerLimit(
+      HAL_GetAnalogVoltsToValue(trigger->analogHandle, lower, status), status);
+  trigger->trigger->writeUpperLimit(
+      HAL_GetAnalogVoltsToValue(trigger->analogHandle, upper, status), status);
+}
+
+void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                  HAL_Bool useAveragedValue, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (trigger->trigger->readSourceSelect_Filter(status) != 0) {
+    *status = INCOMPATIBLE_STATE;
+    // TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not
+    // support average and filtering at the same time.");
+  }
+  trigger->trigger->writeSourceSelect_Averaged(useAveragedValue, status);
+}
+
+void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                  HAL_Bool useFilteredValue, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (trigger->trigger->readSourceSelect_Averaged(status) != 0) {
+    *status = INCOMPATIBLE_STATE;
+    // TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not "
+    // "support average and filtering at the same time.");
+  }
+  trigger->trigger->writeSourceSelect_Filter(useFilteredValue, status);
+}
+
+HAL_Bool HAL_GetAnalogTriggerInWindow(
+    HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return trigger->trigger->readOutput_InHysteresis(trigger->index, status) != 0;
+}
+
+HAL_Bool HAL_GetAnalogTriggerTriggerState(
+    HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return trigger->trigger->readOutput_OverLimit(trigger->index, status) != 0;
+}
+
+HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                    HAL_AnalogTriggerType type,
+                                    int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool result = false;
+  switch (type) {
+    case HAL_Trigger_kInWindow:
+      result =
+          trigger->trigger->readOutput_InHysteresis(trigger->index, status);
+      break;  // XXX: Backport
+    case HAL_Trigger_kState:
+      result = trigger->trigger->readOutput_OverLimit(trigger->index, status);
+      break;  // XXX: Backport
+    case HAL_Trigger_kRisingPulse:
+    case HAL_Trigger_kFallingPulse:
+      *status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
+      return false;
+  }
+  return result;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/CAN.cpp b/hal/src/main/native/athena/CAN.cpp
new file mode 100644
index 0000000..8105358
--- /dev/null
+++ b/hal/src/main/native/athena/CAN.cpp
@@ -0,0 +1,55 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/CAN.h"
+
+#include <FRC_NetworkCommunication/CANSessionMux.h>
+
+namespace hal {
+namespace init {
+void InitializeCAN() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
+                         uint8_t dataSize, int32_t periodMs, int32_t* status) {
+  FRC_NetworkCommunication_CANSessionMux_sendMessage(messageID, data, dataSize,
+                                                     periodMs, status);
+}
+void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
+                            uint8_t* data, uint8_t* dataSize,
+                            uint32_t* timeStamp, int32_t* status) {
+  FRC_NetworkCommunication_CANSessionMux_receiveMessage(
+      messageID, messageIDMask, data, dataSize, timeStamp, status);
+}
+void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
+                               uint32_t messageIDMask, uint32_t maxMessages,
+                               int32_t* status) {
+  FRC_NetworkCommunication_CANSessionMux_openStreamSession(
+      sessionHandle, messageID, messageIDMask, maxMessages, status);
+}
+void HAL_CAN_CloseStreamSession(uint32_t sessionHandle) {
+  FRC_NetworkCommunication_CANSessionMux_closeStreamSession(sessionHandle);
+}
+void HAL_CAN_ReadStreamSession(uint32_t sessionHandle,
+                               struct HAL_CANStreamMessage* messages,
+                               uint32_t messagesToRead, uint32_t* messagesRead,
+                               int32_t* status) {
+  FRC_NetworkCommunication_CANSessionMux_readStreamSession(
+      sessionHandle, reinterpret_cast<tCANStreamMessage*>(messages),
+      messagesToRead, messagesRead, status);
+}
+void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
+                          uint32_t* txFullCount, uint32_t* receiveErrorCount,
+                          uint32_t* transmitErrorCount, int32_t* status) {
+  FRC_NetworkCommunication_CANSessionMux_getCANStatus(
+      percentBusUtilization, busOffCount, txFullCount, receiveErrorCount,
+      transmitErrorCount, status);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/athena/CANAPI.cpp b/hal/src/main/native/athena/CANAPI.cpp
new file mode 100644
index 0000000..01c06bd
--- /dev/null
+++ b/hal/src/main/native/athena/CANAPI.cpp
@@ -0,0 +1,326 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/CANAPI.h"
+
+#include <atomic>
+#include <ctime>
+
+#include <wpi/DenseMap.h>
+
+#include "HALInitializer.h"
+#include "hal/CAN.h"
+#include "hal/Errors.h"
+#include "hal/HAL.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+struct Receives {
+  uint32_t lastTimeStamp;
+  uint8_t data[8];
+  uint8_t length;
+};
+
+struct CANStorage {
+  HAL_CANManufacturer manufacturer;
+  HAL_CANDeviceType deviceType;
+  uint8_t deviceId;
+  wpi::mutex mapMutex;
+  wpi::SmallDenseMap<int32_t, int32_t> periodicSends;
+  wpi::SmallDenseMap<int32_t, Receives> receives;
+};
+}  // namespace
+
+static UnlimitedHandleResource<HAL_CANHandle, CANStorage, HAL_HandleEnum::CAN>*
+    canHandles;
+
+static uint32_t GetPacketBaseTime() {
+  timespec t;
+  clock_gettime(CLOCK_MONOTONIC, &t);
+
+  // Convert t to milliseconds
+  uint64_t ms = t.tv_sec * 1000ull + t.tv_nsec / 1000000ull;
+  return ms & 0xFFFFFFFF;
+}
+
+namespace hal {
+namespace init {
+void InitializeCANAPI() {
+  static UnlimitedHandleResource<HAL_CANHandle, CANStorage, HAL_HandleEnum::CAN>
+      cH;
+  canHandles = &cH;
+}
+}  // namespace init
+}  // namespace hal
+
+static int32_t CreateCANId(CANStorage* storage, int32_t apiId) {
+  int32_t createdId = 0;
+  createdId |= (static_cast<int32_t>(storage->deviceType) & 0x1F) << 24;
+  createdId |= (static_cast<int32_t>(storage->manufacturer) & 0xFF) << 16;
+  createdId |= (apiId & 0x3FF) << 6;
+  createdId |= (storage->deviceId & 0x3F);
+  return createdId;
+}
+
+HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
+                                int32_t deviceId, HAL_CANDeviceType deviceType,
+                                int32_t* status) {
+  hal::init::CheckInit();
+  auto can = std::make_shared<CANStorage>();
+
+  auto handle = canHandles->Allocate(can);
+
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+
+  can->deviceId = deviceId;
+  can->deviceType = deviceType;
+  can->manufacturer = manufacturer;
+
+  return handle;
+}
+
+void HAL_CleanCAN(HAL_CANHandle handle) {
+  auto data = canHandles->Free(handle);
+
+  std::lock_guard<wpi::mutex> 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);
+    i.second = -1;
+  }
+}
+
+void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
+                        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);
+
+  HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  can->periodicSends[apiId] = -1;
+}
+
+void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
+                                 int32_t length, int32_t apiId,
+                                 int32_t repeatMs, int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  auto id = CreateCANId(can.get(), apiId);
+
+  HAL_CAN_SendMessage(id, data, length, repeatMs, status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  can->periodicSends[apiId] = repeatMs;
+}
+
+void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
+                                int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  auto id = CreateCANId(can.get(), apiId);
+
+  HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING,
+                      status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  can->periodicSends[apiId] = -1;
+}
+
+void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
+                          int32_t* length, uint64_t* receivedTimestamp,
+                          int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint32_t messageId = CreateCANId(can.get(), apiId);
+  uint8_t dataSize = 0;
+  uint32_t ts = 0;
+  HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
+
+  if (*status == 0) {
+    std::lock_guard<wpi::mutex> lock(can->mapMutex);
+    auto& msg = can->receives[messageId];
+    msg.length = dataSize;
+    msg.lastTimeStamp = ts;
+    // The NetComm call placed in data, copy into the msg
+    std::memcpy(msg.data, data, dataSize);
+  }
+  *length = dataSize;
+  *receivedTimestamp = ts;
+}
+
+void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
+                             int32_t* length, uint64_t* receivedTimestamp,
+                             int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint32_t messageId = CreateCANId(can.get(), apiId);
+  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()) {
+      // 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;
+    }
+  }
+}
+
+void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
+                              uint8_t* data, int32_t* length,
+                              uint64_t* receivedTimestamp, int32_t timeoutMs,
+                              int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint32_t messageId = CreateCANId(can.get(), apiId);
+  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;
+    }
+  }
+}
+
+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;
+    }
+  }
+}
diff --git a/hal/src/main/native/athena/Compressor.cpp b/hal/src/main/native/athena/Compressor.cpp
new file mode 100644
index 0000000..f381305
--- /dev/null
+++ b/hal/src/main/native/athena/Compressor.cpp
@@ -0,0 +1,202 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Compressor.h"
+
+#include "HALInitializer.h"
+#include "PCMInternal.h"
+#include "PortsInternal.h"
+#include "ctre/PCM.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeCompressor() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_CompressorHandle HAL_InitializeCompressor(int32_t module, int32_t* status) {
+  hal::init::CheckInit();
+  // Use status to check for invalid index
+  initializePCM(module, status);
+  if (*status != 0) {
+    return HAL_kInvalidHandle;
+  }
+
+  // As compressors can have unlimited objects, just create a
+  // handle with the module number as the index.
+
+  return (HAL_CompressorHandle)createHandle(static_cast<int16_t>(module),
+                                            HAL_HandleEnum::Compressor, 0);
+}
+
+HAL_Bool HAL_CheckCompressorModule(int32_t module) {
+  return module < kNumPCMModules && module >= 0;
+}
+
+HAL_Bool HAL_GetCompressor(HAL_CompressorHandle compressorHandle,
+                           int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetCompressor(value);
+
+  return value;
+}
+
+void HAL_SetCompressorClosedLoopControl(HAL_CompressorHandle compressorHandle,
+                                        HAL_Bool value, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  *status = PCM_modules[index]->SetClosedLoopControl(value);
+}
+
+HAL_Bool HAL_GetCompressorClosedLoopControl(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetClosedLoopControl(value);
+
+  return value;
+}
+
+HAL_Bool HAL_GetCompressorPressureSwitch(HAL_CompressorHandle compressorHandle,
+                                         int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetPressure(value);
+
+  return value;
+}
+
+double HAL_GetCompressorCurrent(HAL_CompressorHandle compressorHandle,
+                                int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  float value;
+
+  *status = PCM_modules[index]->GetCompressorCurrent(value);
+
+  return value;
+}
+HAL_Bool HAL_GetCompressorCurrentTooHighFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetCompressorCurrentTooHighFault(value);
+
+  return value;
+}
+HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetCompressorCurrentTooHighStickyFault(value);
+
+  return value;
+}
+HAL_Bool HAL_GetCompressorShortedStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetCompressorShortedStickyFault(value);
+
+  return value;
+}
+HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
+                                       int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetCompressorShortedFault(value);
+
+  return value;
+}
+HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetCompressorNotConnectedStickyFault(value);
+
+  return value;
+}
+HAL_Bool HAL_GetCompressorNotConnectedFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[index]->GetCompressorNotConnectedFault(value);
+
+  return value;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/Constants.cpp b/hal/src/main/native/athena/Constants.cpp
new file mode 100644
index 0000000..6af443d
--- /dev/null
+++ b/hal/src/main/native/athena/Constants.cpp
@@ -0,0 +1,26 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Constants.h"
+
+#include "ConstantsInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeConstants() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+int32_t HAL_GetSystemClockTicksPerMicrosecond(void) {
+  return kSystemClockTicksPerMicrosecond;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/ConstantsInternal.h b/hal/src/main/native/athena/ConstantsInternal.h
new file mode 100644
index 0000000..55bbdee
--- /dev/null
+++ b/hal/src/main/native/athena/ConstantsInternal.h
@@ -0,0 +1,16 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+namespace hal {
+
+constexpr int32_t kSystemClockTicksPerMicrosecond = 40;
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/Counter.cpp b/hal/src/main/native/athena/Counter.cpp
new file mode 100644
index 0000000..6d7e254
--- /dev/null
+++ b/hal/src/main/native/athena/Counter.cpp
@@ -0,0 +1,372 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Counter.h"
+
+#include "ConstantsInternal.h"
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/HAL.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+
+struct Counter {
+  std::unique_ptr<tCounter> counter;
+  uint8_t index;
+};
+
+}  // namespace
+
+static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
+                             HAL_HandleEnum::Counter>* counterHandles;
+
+namespace hal {
+namespace init {
+void InitializeCounter() {
+  static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
+                               HAL_HandleEnum::Counter>
+      ch;
+  counterHandles = &ch;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  auto handle = counterHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {  // out of resources
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto counter = counterHandles->Get(handle);
+  if (counter == nullptr) {  // would only occur on thread issues
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  counter->index = static_cast<uint8_t>(getHandleIndex(handle));
+  *index = counter->index;
+
+  counter->counter.reset(tCounter::create(counter->index, status));
+  counter->counter->writeConfig_Mode(mode, status);
+  counter->counter->writeTimerConfig_AverageSize(1, status);
+  return handle;
+}
+
+void HAL_FreeCounter(HAL_CounterHandle counterHandle, int32_t* status) {
+  counterHandles->Free(counterHandle);
+}
+
+void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
+                               int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeTimerConfig_AverageSize(size, status);
+}
+
+void HAL_SetCounterUpSource(HAL_CounterHandle counterHandle,
+                            HAL_Handle digitalSourceHandle,
+                            HAL_AnalogTriggerType analogTriggerType,
+                            int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  bool routingAnalogTrigger = false;
+  uint8_t routingChannel = 0;
+  uint8_t routingModule = 0;
+  bool success =
+      remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
+                         routingModule, routingAnalogTrigger);
+  if (!success) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  counter->counter->writeConfig_UpSource_Module(routingModule, status);
+  counter->counter->writeConfig_UpSource_Channel(routingChannel, status);
+  counter->counter->writeConfig_UpSource_AnalogTrigger(routingAnalogTrigger,
+                                                       status);
+
+  if (counter->counter->readConfig_Mode(status) == HAL_Counter_kTwoPulse ||
+      counter->counter->readConfig_Mode(status) ==
+          HAL_Counter_kExternalDirection) {
+    HAL_SetCounterUpSourceEdge(counterHandle, true, false, status);
+  }
+  counter->counter->strobeReset(status);
+}
+
+void HAL_SetCounterUpSourceEdge(HAL_CounterHandle counterHandle,
+                                HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_UpRisingEdge(risingEdge, status);
+  counter->counter->writeConfig_UpFallingEdge(fallingEdge, status);
+}
+
+void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle,
+                              int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_UpFallingEdge(false, status);
+  counter->counter->writeConfig_UpRisingEdge(false, status);
+  // Index 0 of digital is always 0.
+  counter->counter->writeConfig_UpSource_Channel(0, status);
+  counter->counter->writeConfig_UpSource_AnalogTrigger(false, status);
+}
+
+void HAL_SetCounterDownSource(HAL_CounterHandle counterHandle,
+                              HAL_Handle digitalSourceHandle,
+                              HAL_AnalogTriggerType analogTriggerType,
+                              int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  uint8_t mode = counter->counter->readConfig_Mode(status);
+  if (mode != HAL_Counter_kTwoPulse && mode != HAL_Counter_kExternalDirection) {
+    // TODO: wpi_setWPIErrorWithContext(ParameterOutOfRange, "Counter only
+    // supports DownSource in TwoPulse and ExternalDirection modes.");
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  bool routingAnalogTrigger = false;
+  uint8_t routingChannel = 0;
+  uint8_t routingModule = 0;
+  bool success =
+      remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
+                         routingModule, routingAnalogTrigger);
+  if (!success) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  counter->counter->writeConfig_DownSource_Module(routingModule, status);
+  counter->counter->writeConfig_DownSource_Channel(routingChannel, status);
+  counter->counter->writeConfig_DownSource_AnalogTrigger(routingAnalogTrigger,
+                                                         status);
+
+  HAL_SetCounterDownSourceEdge(counterHandle, true, false, status);
+  counter->counter->strobeReset(status);
+}
+
+void HAL_SetCounterDownSourceEdge(HAL_CounterHandle counterHandle,
+                                  HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                  int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_DownRisingEdge(risingEdge, status);
+  counter->counter->writeConfig_DownFallingEdge(fallingEdge, status);
+}
+
+void HAL_ClearCounterDownSource(HAL_CounterHandle counterHandle,
+                                int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_DownFallingEdge(false, status);
+  counter->counter->writeConfig_DownRisingEdge(false, status);
+  // Index 0 of digital is always 0.
+  counter->counter->writeConfig_DownSource_Channel(0, status);
+  counter->counter->writeConfig_DownSource_AnalogTrigger(false, status);
+}
+
+void HAL_SetCounterUpDownMode(HAL_CounterHandle counterHandle,
+                              int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_Mode(HAL_Counter_kTwoPulse, status);
+}
+
+void HAL_SetCounterExternalDirectionMode(HAL_CounterHandle counterHandle,
+                                         int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_Mode(HAL_Counter_kExternalDirection, status);
+}
+
+void HAL_SetCounterSemiPeriodMode(HAL_CounterHandle counterHandle,
+                                  HAL_Bool highSemiPeriod, int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_Mode(HAL_Counter_kSemiperiod, status);
+  counter->counter->writeConfig_UpRisingEdge(highSemiPeriod, status);
+  HAL_SetCounterUpdateWhenEmpty(counterHandle, false, status);
+}
+
+void HAL_SetCounterPulseLengthMode(HAL_CounterHandle counterHandle,
+                                   double threshold, int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeConfig_Mode(HAL_Counter_kPulseLength, status);
+  counter->counter->writeConfig_PulseLengthThreshold(
+      static_cast<uint32_t>(threshold * 1.0e6) *
+          kSystemClockTicksPerMicrosecond,
+      status);
+}
+
+int32_t HAL_GetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
+                                       int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return counter->counter->readTimerConfig_AverageSize(status);
+}
+
+void HAL_SetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
+                                    int32_t samplesToAverage, int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (samplesToAverage < 1 || samplesToAverage > 127) {
+    *status = PARAMETER_OUT_OF_RANGE;
+  }
+  counter->counter->writeTimerConfig_AverageSize(samplesToAverage, status);
+}
+
+void HAL_ResetCounter(HAL_CounterHandle counterHandle, int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->strobeReset(status);
+}
+
+int32_t HAL_GetCounter(HAL_CounterHandle counterHandle, int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  int32_t value = counter->counter->readOutput_Value(status);
+  return value;
+}
+
+double HAL_GetCounterPeriod(HAL_CounterHandle counterHandle, int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+  tCounter::tTimerOutput output = counter->counter->readTimerOutput(status);
+  double period;
+  if (output.Stalled) {
+    // Return infinity
+    double zero = 0.0;
+    period = 1.0 / zero;
+  } else {
+    // output.Period is a fixed point number that counts by 2 (24 bits, 25
+    // integer bits)
+    period = static_cast<double>(output.Period << 1) /
+             static_cast<double>(output.Count);
+  }
+  return static_cast<double>(period *
+                             2.5e-8);  // result * timebase (currently 25ns)
+}
+
+void HAL_SetCounterMaxPeriod(HAL_CounterHandle counterHandle, double maxPeriod,
+                             int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeTimerConfig_StallPeriod(
+      static_cast<uint32_t>(maxPeriod * 4.0e8), status);
+}
+
+void HAL_SetCounterUpdateWhenEmpty(HAL_CounterHandle counterHandle,
+                                   HAL_Bool enabled, int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  counter->counter->writeTimerConfig_UpdateWhenEmpty(enabled, status);
+}
+
+HAL_Bool HAL_GetCounterStopped(HAL_CounterHandle counterHandle,
+                               int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return counter->counter->readTimerOutput_Stalled(status);
+}
+
+HAL_Bool HAL_GetCounterDirection(HAL_CounterHandle counterHandle,
+                                 int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value = counter->counter->readOutput_Direction(status);
+  return value;
+}
+
+void HAL_SetCounterReverseDirection(HAL_CounterHandle counterHandle,
+                                    HAL_Bool reverseDirection,
+                                    int32_t* status) {
+  auto counter = counterHandles->Get(counterHandle);
+  if (counter == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (counter->counter->readConfig_Mode(status) ==
+      HAL_Counter_kExternalDirection) {
+    if (reverseDirection)
+      HAL_SetCounterDownSourceEdge(counterHandle, true, true, status);
+    else
+      HAL_SetCounterDownSourceEdge(counterHandle, false, true, status);
+  }
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/DIO.cpp b/hal/src/main/native/athena/DIO.cpp
new file mode 100644
index 0000000..96eab2b
--- /dev/null
+++ b/hal/src/main/native/athena/DIO.cpp
@@ -0,0 +1,486 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/DIO.h"
+
+#include <cmath>
+#include <thread>
+
+#include <wpi/raw_ostream.h>
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/cpp/fpga_clock.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+using namespace hal;
+
+// Create a mutex to protect changes to the DO PWM config
+static wpi::mutex digitalPwmMutex;
+
+static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
+                             kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
+    digitalPWMHandles;
+
+namespace hal {
+namespace init {
+void InitializeDIO() {
+  static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
+                               kNumDigitalPWMOutputs,
+                               HAL_HandleEnum::DigitalPWM>
+      dpH;
+  digitalPWMHandles = &dpH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
+                                        HAL_Bool input, int32_t* status) {
+  hal::init::CheckInit();
+  initializeDigital(status);
+
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex || channel >= kNumDigitalChannels) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  auto handle =
+      digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  port->channel = static_cast<uint8_t>(channel);
+
+  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+
+  tDIO::tOutputEnable outputEnable = digitalSystem->readOutputEnable(status);
+
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    if (!getPortHandleSPIEnable(portHandle)) {
+      // if this flag is not set, we actually want DIO.
+      uint32_t bitToSet = 1u << remapSPIChannel(port->channel);
+
+      uint16_t specialFunctions = spiSystem->readEnableDIO(status);
+      // Set the field to enable SPI DIO
+      spiSystem->writeEnableDIO(specialFunctions | bitToSet, status);
+
+      if (input) {
+        outputEnable.SPIPort =
+            outputEnable.SPIPort & (~bitToSet);  // clear the field for read
+      } else {
+        outputEnable.SPIPort =
+            outputEnable.SPIPort | bitToSet;  // set the bits for write
+      }
+    }
+  } else if (port->channel < kNumDigitalHeaders) {
+    uint32_t bitToSet = 1u << port->channel;
+    if (input) {
+      outputEnable.Headers =
+          outputEnable.Headers & (~bitToSet);  // clear the bit for read
+    } else {
+      outputEnable.Headers =
+          outputEnable.Headers | bitToSet;  // set the bit for write
+    }
+  } else {
+    uint32_t bitToSet = 1u << remapMXPChannel(port->channel);
+
+    uint16_t specialFunctions =
+        digitalSystem->readEnableMXPSpecialFunction(status);
+    digitalSystem->writeEnableMXPSpecialFunction(specialFunctions & ~bitToSet,
+                                                 status);
+
+    if (input) {
+      outputEnable.MXP =
+          outputEnable.MXP & (~bitToSet);  // clear the bit for read
+    } else {
+      outputEnable.MXP = outputEnable.MXP | bitToSet;  // set the bit for write
+    }
+  }
+
+  digitalSystem->writeOutputEnable(outputEnable, status);
+
+  return handle;
+}
+
+HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
+  return channel < kNumDigitalChannels && channel >= 0;
+}
+
+void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  // no status, so no need to check for a proper free.
+  if (port == nullptr) return;
+  digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
+
+  // Wait for no other object to hold this handle.
+  auto start = hal::fpga_clock::now();
+  while (port.use_count() != 1) {
+    auto current = hal::fpga_clock::now();
+    if (start + std::chrono::seconds(1) < current) {
+      wpi::outs() << "DIO handle free timeout\n";
+      wpi::outs().flush();
+      break;
+    }
+    std::this_thread::yield();
+  }
+
+  int32_t status = 0;
+  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    // Unset the SPI flag
+    int32_t bitToUnset = 1 << remapSPIChannel(port->channel);
+    uint16_t specialFunctions = spiSystem->readEnableDIO(&status);
+    spiSystem->writeEnableDIO(specialFunctions & ~bitToUnset, &status);
+  } else if (port->channel >= kNumDigitalHeaders) {
+    // Unset the MXP flag
+    uint32_t bitToUnset = 1u << remapMXPChannel(port->channel);
+
+    uint16_t specialFunctions =
+        digitalSystem->readEnableMXPSpecialFunction(&status);
+    digitalSystem->writeEnableMXPSpecialFunction(specialFunctions | bitToUnset,
+                                                 &status);
+  }
+}
+
+HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
+  auto handle = digitalPWMHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+
+  auto id = digitalPWMHandles->Get(handle);
+  if (id == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  *id = static_cast<uint8_t>(getHandleIndex(handle));
+
+  return handle;
+}
+
+void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
+  digitalPWMHandles->Free(pwmGenerator);
+}
+
+void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
+  // Currently rounding in the log rate domain... heavy weight toward picking a
+  // higher freq.
+  // TODO: Round in the linear rate domain.
+  initializeDigital(status);
+  if (*status != 0) return;
+  uint16_t pwmPeriodPower = static_cast<uint16_t>(
+      std::log(1.0 / (16 * 1.0E-6 * rate)) / std::log(2.0) + 0.5);
+  digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
+}
+
+void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
+                                double dutyCycle, int32_t* status) {
+  auto port = digitalPWMHandles->Get(pwmGenerator);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  int32_t id = *port;
+  if (dutyCycle > 1.0) dutyCycle = 1.0;
+  if (dutyCycle < 0.0) dutyCycle = 0.0;
+  double rawDutyCycle = 256.0 * dutyCycle;
+  if (rawDutyCycle > 255.5) rawDutyCycle = 255.5;
+  {
+    std::lock_guard<wpi::mutex> lock(digitalPwmMutex);
+    uint16_t pwmPeriodPower = digitalSystem->readPWMPeriodPower(status);
+    if (pwmPeriodPower < 4) {
+      // The resolution of the duty cycle drops close to the highest
+      // frequencies.
+      rawDutyCycle = rawDutyCycle / std::pow(2.0, 4 - pwmPeriodPower);
+    }
+    if (id < 4)
+      digitalSystem->writePWMDutyCycleA(id, static_cast<uint8_t>(rawDutyCycle),
+                                        status);
+    else
+      digitalSystem->writePWMDutyCycleB(
+          id - 4, static_cast<uint8_t>(rawDutyCycle), status);
+  }
+}
+
+void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
+                                    int32_t channel, int32_t* status) {
+  auto port = digitalPWMHandles->Get(pwmGenerator);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  int32_t id = *port;
+  if (channel >= kNumDigitalHeaders &&
+      channel <
+          kNumDigitalHeaders + kNumDigitalMXPChannels) {  // If it is on the MXP
+    /* Then to write as a digital PWM channel an offset is needed to write on
+     * the correct channel
+     */
+    channel += kMXPDigitalPWMOffset;
+  }
+  digitalSystem->writePWMOutputSelect(id, channel, status);
+}
+
+void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
+                int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (value != 0 && value != 1) {
+    if (value != 0) value = 1;
+  }
+  {
+    std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+    tDIO::tDO currentDIO = digitalSystem->readDO(status);
+
+    if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+      if (value == 0) {
+        currentDIO.SPIPort =
+            currentDIO.SPIPort & ~(1u << remapSPIChannel(port->channel));
+      } else if (value == 1) {
+        currentDIO.SPIPort =
+            currentDIO.SPIPort | (1u << remapSPIChannel(port->channel));
+      }
+    } else if (port->channel < kNumDigitalHeaders) {
+      if (value == 0) {
+        currentDIO.Headers = currentDIO.Headers & ~(1u << port->channel);
+      } else if (value == 1) {
+        currentDIO.Headers = currentDIO.Headers | (1u << port->channel);
+      }
+    } else {
+      if (value == 0) {
+        currentDIO.MXP =
+            currentDIO.MXP & ~(1u << remapMXPChannel(port->channel));
+      } else if (value == 1) {
+        currentDIO.MXP =
+            currentDIO.MXP | (1u << remapMXPChannel(port->channel));
+      }
+    }
+    digitalSystem->writeDO(currentDIO, status);
+  }
+}
+
+void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  {
+    std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+    tDIO::tOutputEnable currentDIO = digitalSystem->readOutputEnable(status);
+
+    if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+      if (input) {
+        currentDIO.SPIPort =
+            currentDIO.SPIPort & ~(1u << remapSPIChannel(port->channel));
+      } else {
+        currentDIO.SPIPort =
+            currentDIO.SPIPort | (1u << remapSPIChannel(port->channel));
+      }
+    } else if (port->channel < kNumDigitalHeaders) {
+      if (input) {
+        currentDIO.Headers = currentDIO.Headers & ~(1u << port->channel);
+      } else {
+        currentDIO.Headers = currentDIO.Headers | (1u << port->channel);
+      }
+    } else {
+      if (input) {
+        currentDIO.MXP =
+            currentDIO.MXP & ~(1u << remapMXPChannel(port->channel));
+      } else {
+        currentDIO.MXP =
+            currentDIO.MXP | (1u << remapMXPChannel(port->channel));
+      }
+    }
+    digitalSystem->writeOutputEnable(currentDIO, status);
+  }
+}
+
+HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  tDIO::tDI currentDIO = digitalSystem->readDI(status);
+  // Shift 00000001 over channel-1 places.
+  // AND it against the currentDIO
+  // if it == 0, then return false
+  // else return true
+
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    return ((currentDIO.SPIPort >> remapSPIChannel(port->channel)) & 1) != 0;
+  } else if (port->channel < kNumDigitalHeaders) {
+    return ((currentDIO.Headers >> port->channel) & 1) != 0;
+  } else {
+    return ((currentDIO.MXP >> remapMXPChannel(port->channel)) & 1) != 0;
+  }
+}
+
+HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  tDIO::tOutputEnable currentOutputEnable =
+      digitalSystem->readOutputEnable(status);
+  // Shift 00000001 over port->channel-1 places.
+  // AND it against the currentOutputEnable
+  // if it == 0, then return false
+  // else return true
+
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    return ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
+            1) != 0;
+  } else if (port->channel < kNumDigitalHeaders) {
+    return ((currentOutputEnable.Headers >> port->channel) & 1) != 0;
+  } else {
+    return ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) & 1) !=
+           0;
+  }
+}
+
+void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
+               int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  tDIO::tPulse pulse;
+
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    pulse.SPIPort = 1u << remapSPIChannel(port->channel);
+  } else if (port->channel < kNumDigitalHeaders) {
+    pulse.Headers = 1u << port->channel;
+  } else {
+    pulse.MXP = 1u << remapMXPChannel(port->channel);
+  }
+
+  digitalSystem->writePulseLength(
+      static_cast<uint8_t>(1.0e9 * pulseLength /
+                           (pwmSystem->readLoopTiming(status) * 25)),
+      status);
+  digitalSystem->writePulse(pulse, status);
+}
+
+HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
+
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    return (pulseRegister.SPIPort & (1 << remapSPIChannel(port->channel))) != 0;
+  } else if (port->channel < kNumDigitalHeaders) {
+    return (pulseRegister.Headers & (1 << port->channel)) != 0;
+  } else {
+    return (pulseRegister.MXP & (1 << remapMXPChannel(port->channel))) != 0;
+  }
+}
+
+HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
+  initializeDigital(status);
+  if (*status != 0) return false;
+  tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
+  return pulseRegister.Headers != 0 && pulseRegister.MXP != 0 &&
+         pulseRegister.SPIPort != 0;
+}
+
+void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    // Channels 10-15 are SPI channels, so subtract our MXP channels
+    digitalSystem->writeFilterSelectHdr(port->channel - kNumDigitalMXPChannels,
+                                        filterIndex, status);
+  } else if (port->channel < kNumDigitalHeaders) {
+    digitalSystem->writeFilterSelectHdr(port->channel, filterIndex, status);
+  } else {
+    digitalSystem->writeFilterSelectMXP(remapMXPChannel(port->channel),
+                                        filterIndex, status);
+  }
+}
+
+int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    // Channels 10-15 are SPI channels, so subtract our MXP channels
+    return digitalSystem->readFilterSelectHdr(
+        port->channel - kNumDigitalMXPChannels, status);
+  } else if (port->channel < kNumDigitalHeaders) {
+    return digitalSystem->readFilterSelectHdr(port->channel, status);
+  } else {
+    return digitalSystem->readFilterSelectMXP(remapMXPChannel(port->channel),
+                                              status);
+  }
+}
+
+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);
+  digitalSystem->writeFilterPeriodHdr(filterIndex, value, status);
+  if (*status == 0) {
+    digitalSystem->writeFilterPeriodMXP(filterIndex, value, status);
+  }
+}
+
+int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
+  initializeDigital(status);
+  if (*status != 0) return 0;
+  uint32_t hdrPeriod = 0;
+  uint32_t mxpPeriod = 0;
+  {
+    std::lock_guard<wpi::mutex> lock(digitalDIOMutex);
+    hdrPeriod = digitalSystem->readFilterPeriodHdr(filterIndex, status);
+    if (*status == 0) {
+      mxpPeriod = digitalSystem->readFilterPeriodMXP(filterIndex, status);
+    }
+  }
+  if (hdrPeriod != mxpPeriod) {
+    *status = NiFpga_Status_SoftwareFault;
+    return -1;
+  }
+  return hdrPeriod;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/DigitalInternal.cpp b/hal/src/main/native/athena/DigitalInternal.cpp
new file mode 100644
index 0000000..1db6c7e
--- /dev/null
+++ b/hal/src/main/native/athena/DigitalInternal.cpp
@@ -0,0 +1,183 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "DigitalInternal.h"
+
+#include <atomic>
+#include <thread>
+
+#include <FRC_NetworkCommunication/LoadOut.h>
+#include <wpi/mutex.h>
+
+#include "ConstantsInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/AnalogTrigger.h"
+#include "hal/ChipObject.h"
+#include "hal/HAL.h"
+#include "hal/Ports.h"
+#include "hal/cpp/UnsafeDIO.h"
+
+namespace hal {
+
+std::unique_ptr<tDIO> digitalSystem;
+std::unique_ptr<tRelay> relaySystem;
+std::unique_ptr<tPWM> pwmSystem;
+std::unique_ptr<tSPI> spiSystem;
+
+// Create a mutex to protect changes to the digital output values
+wpi::mutex digitalDIOMutex;
+
+DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
+                      kNumDigitalChannels + kNumPWMHeaders>*
+    digitalChannelHandles;
+
+namespace init {
+void InitializeDigitalInternal() {
+  static DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
+                               kNumDigitalChannels + kNumPWMHeaders>
+      dcH;
+  digitalChannelHandles = &dcH;
+}
+}  // namespace init
+
+namespace detail {
+wpi::mutex& UnsafeGetDIOMutex() { return digitalDIOMutex; }
+tDIO* UnsafeGetDigialSystem() { return digitalSystem.get(); }
+int32_t ComputeDigitalMask(HAL_DigitalHandle handle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  tDIO::tDO output;
+  output.value = 0;
+  if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+    output.SPIPort = (1u << remapSPIChannel(port->channel));
+  } else if (port->channel < kNumDigitalHeaders) {
+    output.Headers = (1u << port->channel);
+  } else {
+    output.MXP = (1u << remapMXPChannel(port->channel));
+  }
+  return output.value;
+}
+}  // namespace detail
+
+void initializeDigital(int32_t* status) {
+  hal::init::CheckInit();
+  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;
+
+  digitalSystem.reset(tDIO::create(status));
+
+  // Relay Setup
+  relaySystem.reset(tRelay::create(status));
+
+  // Turn off all relay outputs.
+  relaySystem->writeValue_Forward(0, status);
+  relaySystem->writeValue_Reverse(0, status);
+
+  // PWM Setup
+  pwmSystem.reset(tPWM::create(status));
+
+  // Make sure that the 9403 IONode has had a chance to initialize before
+  // continuing.
+  while (pwmSystem->readLoopTiming(status) == 0) std::this_thread::yield();
+
+  if (pwmSystem->readLoopTiming(status) != kExpectedLoopTiming) {
+    *status = LOOP_TIMING_ERROR;  // NOTE: Doesn't display the error
+  }
+
+  // Calculate the length, in ms, of one DIO loop
+  double loopTime = pwmSystem->readLoopTiming(status) /
+                    (kSystemClockTicksPerMicrosecond * 1e3);
+
+  pwmSystem->writeConfig_Period(
+      static_cast<uint16_t>(kDefaultPwmPeriod / loopTime + .5), status);
+  uint16_t minHigh = static_cast<uint16_t>(
+      (kDefaultPwmCenter - kDefaultPwmStepsDown * loopTime) / loopTime + .5);
+  pwmSystem->writeConfig_MinHigh(minHigh, status);
+  // Ensure that PWM output values are set to OFF
+  for (uint8_t pwmIndex = 0; pwmIndex < kNumPWMChannels; pwmIndex++) {
+    // Copy of SetPWM
+    if (pwmIndex < tPWM::kNumHdrRegisters) {
+      pwmSystem->writeHdr(pwmIndex, kPwmDisabled, status);
+    } else {
+      pwmSystem->writeMXP(pwmIndex - tPWM::kNumHdrRegisters, kPwmDisabled,
+                          status);
+    }
+
+    // Copy of SetPWMPeriodScale, set to 4x by default.
+    if (pwmIndex < tPWM::kNumPeriodScaleHdrElements) {
+      pwmSystem->writePeriodScaleHdr(pwmIndex, 3, status);
+    } else {
+      pwmSystem->writePeriodScaleMXP(
+          pwmIndex - tPWM::kNumPeriodScaleHdrElements, 3, status);
+    }
+  }
+
+  // SPI setup
+  spiSystem.reset(tSPI::create(status));
+
+  initialized = true;
+}
+
+bool remapDigitalSource(HAL_Handle digitalSourceHandle,
+                        HAL_AnalogTriggerType analogTriggerType,
+                        uint8_t& channel, uint8_t& module,
+                        bool& analogTrigger) {
+  if (isHandleType(digitalSourceHandle, HAL_HandleEnum::AnalogTrigger)) {
+    // If handle passed, index is not negative
+    int32_t index = getHandleIndex(digitalSourceHandle);
+    channel = (index << 2) + analogTriggerType;
+    module = channel >> 4;
+    analogTrigger = true;
+    return true;
+  } else if (isHandleType(digitalSourceHandle, HAL_HandleEnum::DIO)) {
+    int32_t index = getHandleIndex(digitalSourceHandle);
+    if (index > kNumDigitalHeaders + kNumDigitalMXPChannels) {
+      // channels 10-15, so need to add headers to remap index
+      channel = remapSPIChannel(index) + kNumDigitalHeaders;
+      module = 0;
+    } else if (index >= kNumDigitalHeaders) {
+      channel = remapMXPChannel(index);
+      module = 1;
+    } else {
+      channel = index;
+      module = 0;
+    }
+    analogTrigger = false;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+int32_t remapMXPChannel(int32_t channel) { return channel - 10; }
+
+int32_t remapMXPPWMChannel(int32_t channel) {
+  if (channel < 14) {
+    return channel - 10;  // first block of 4 pwms (MXP 0-3)
+  } else {
+    return channel - 6;  // block of PWMs after SPI
+  }
+}
+
+int32_t remapSPIChannel(int32_t channel) { return channel - 26; }
+
+}  // namespace hal
+
+// Unused function here to test template compile.
+__attribute__((unused)) static void CompileFunctorTest() {
+  hal::UnsafeManipulateDIO(0, nullptr, [](hal::DIOSetProxy& proxy) {});
+}
diff --git a/hal/src/main/native/athena/DigitalInternal.h b/hal/src/main/native/athena/DigitalInternal.h
new file mode 100644
index 0000000..b486f48
--- /dev/null
+++ b/hal/src/main/native/athena/DigitalInternal.h
@@ -0,0 +1,113 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <memory>
+
+#include <wpi/mutex.h>
+
+#include "PortsInternal.h"
+#include "hal/AnalogTrigger.h"
+#include "hal/ChipObject.h"
+#include "hal/Ports.h"
+#include "hal/Types.h"
+#include "hal/handles/DigitalHandleResource.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * MXP channels when used as digital output PWM are offset from actual value
+ */
+constexpr int32_t kMXPDigitalPWMOffset = 6;
+
+constexpr int32_t kExpectedLoopTiming = 40;
+
+/**
+ * kDefaultPwmPeriod is in ms
+ *
+ * - 20ms periods (50 Hz) are the "safest" setting in that this works for all
+ *   devices
+ * - 20ms periods seem to be desirable for Vex Motors
+ * - 20ms periods are the specified period for HS-322HD servos, but work
+ *   reliably down to 10.0 ms; starting at about 8.5ms, the servo sometimes hums
+ *   and get hot; by 5.0ms the hum is nearly continuous
+ * - 10ms periods work well for Victor 884
+ * - 5ms periods allows higher update rates for Luminary Micro Jaguar speed
+ *   controllers. Due to the shipping firmware on the Jaguar, we can't run the
+ *   update period less than 5.05 ms.
+ *
+ * kDefaultPwmPeriod is the 1x period (5.05 ms).  In hardware, the period
+ * scaling is implemented as an output squelch to get longer periods for old
+ * devices.
+ */
+constexpr double kDefaultPwmPeriod = 5.05;
+/**
+ * kDefaultPwmCenter is the PWM range center in ms
+ */
+constexpr double kDefaultPwmCenter = 1.5;
+/**
+ * kDefaultPWMStepsDown is the number of PWM steps below the centerpoint
+ */
+constexpr int32_t kDefaultPwmStepsDown = 1000;
+constexpr int32_t kPwmDisabled = 0;
+
+extern std::unique_ptr<tDIO> digitalSystem;
+extern std::unique_ptr<tRelay> relaySystem;
+extern std::unique_ptr<tPWM> pwmSystem;
+extern std::unique_ptr<tSPI> spiSystem;
+
+struct DigitalPort {
+  uint8_t channel;
+  bool configSet = false;
+  bool eliminateDeadband = false;
+  int32_t maxPwm = 0;
+  int32_t deadbandMaxPwm = 0;
+  int32_t centerPwm = 0;
+  int32_t deadbandMinPwm = 0;
+  int32_t minPwm = 0;
+};
+
+extern DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
+                             kNumDigitalChannels + kNumPWMHeaders>*
+    digitalChannelHandles;
+
+extern wpi::mutex digitalDIOMutex;
+
+/**
+ * Initialize the digital system.
+ */
+void initializeDigital(int32_t* status);
+
+/**
+ * remap the digital source channel and set the module.
+ * If it's an analog trigger, determine the module from the high order routing
+ * channel else do normal digital input remapping based on channel number
+ * (MXP)
+ */
+bool remapDigitalSource(HAL_Handle digitalSourceHandle,
+                        HAL_AnalogTriggerType analogTriggerType,
+                        uint8_t& channel, uint8_t& module, bool& analogTrigger);
+
+/**
+ * Map DIO channel numbers from their physical number (10 to 26) to their
+ * position in the bit field.
+ */
+int32_t remapMXPChannel(int32_t channel);
+
+int32_t remapMXPPWMChannel(int32_t channel);
+
+/**
+ * Map SPI channel numbers from their physical number (27 to 31) to their
+ * position in the bit field.
+ */
+int32_t remapSPIChannel(int32_t channel);
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/Encoder.cpp b/hal/src/main/native/athena/Encoder.cpp
new file mode 100644
index 0000000..adf70ed
--- /dev/null
+++ b/hal/src/main/native/athena/Encoder.cpp
@@ -0,0 +1,462 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Encoder.h"
+
+#include "EncoderInternal.h"
+#include "FPGAEncoder.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/ChipObject.h"
+#include "hal/Counter.h"
+#include "hal/Errors.h"
+#include "hal/handles/LimitedClassedHandleResource.h"
+
+using namespace hal;
+
+Encoder::Encoder(HAL_Handle digitalSourceHandleA,
+                 HAL_AnalogTriggerType analogTriggerTypeA,
+                 HAL_Handle digitalSourceHandleB,
+                 HAL_AnalogTriggerType analogTriggerTypeB,
+                 bool reverseDirection, HAL_EncoderEncodingType encodingType,
+                 int32_t* status) {
+  m_encodingType = encodingType;
+  switch (encodingType) {
+    case HAL_Encoder_k4X: {
+      m_encodingScale = 4;
+      m_encoder = HAL_InitializeFPGAEncoder(
+          digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
+          analogTriggerTypeB, reverseDirection, &m_index, status);
+      if (*status != 0) {
+        return;
+      }
+      m_counter = HAL_kInvalidHandle;
+      SetMaxPeriod(.5, status);
+      break;
+    }
+    case HAL_Encoder_k1X:
+    case HAL_Encoder_k2X: {
+      SetupCounter(digitalSourceHandleA, analogTriggerTypeA,
+                   digitalSourceHandleB, analogTriggerTypeB, reverseDirection,
+                   encodingType, status);
+
+      m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
+      break;
+    }
+    default:
+      *status = PARAMETER_OUT_OF_RANGE;
+      return;
+  }
+}
+
+void Encoder::SetupCounter(HAL_Handle digitalSourceHandleA,
+                           HAL_AnalogTriggerType analogTriggerTypeA,
+                           HAL_Handle digitalSourceHandleB,
+                           HAL_AnalogTriggerType analogTriggerTypeB,
+                           bool reverseDirection,
+                           HAL_EncoderEncodingType encodingType,
+                           int32_t* status) {
+  m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
+  m_counter =
+      HAL_InitializeCounter(HAL_Counter_kExternalDirection, &m_index, status);
+  if (*status != 0) return;
+  HAL_SetCounterMaxPeriod(m_counter, 0.5, status);
+  if (*status != 0) return;
+  HAL_SetCounterUpSource(m_counter, digitalSourceHandleA, analogTriggerTypeA,
+                         status);
+  if (*status != 0) return;
+  HAL_SetCounterDownSource(m_counter, digitalSourceHandleB, analogTriggerTypeB,
+                           status);
+  if (*status != 0) return;
+  if (encodingType == HAL_Encoder_k1X) {
+    HAL_SetCounterUpSourceEdge(m_counter, true, false, status);
+    HAL_SetCounterAverageSize(m_counter, 1, status);
+  } else {
+    HAL_SetCounterUpSourceEdge(m_counter, true, true, status);
+    HAL_SetCounterAverageSize(m_counter, 2, status);
+  }
+  HAL_SetCounterDownSourceEdge(m_counter, reverseDirection, true, status);
+}
+
+Encoder::~Encoder() {
+  if (m_counter != HAL_kInvalidHandle) {
+    int32_t status = 0;
+    HAL_FreeCounter(m_counter, &status);
+  } else {
+    int32_t status = 0;
+    HAL_FreeFPGAEncoder(m_encoder, &status);
+  }
+}
+
+// CounterBase interface
+int32_t Encoder::Get(int32_t* status) const {
+  return static_cast<int32_t>(GetRaw(status) * DecodingScaleFactor());
+}
+
+int32_t Encoder::GetRaw(int32_t* status) const {
+  if (m_counter) {
+    return HAL_GetCounter(m_counter, status);
+  } else {
+    return HAL_GetFPGAEncoder(m_encoder, status);
+  }
+}
+
+int32_t Encoder::GetEncodingScale(int32_t* status) const {
+  return m_encodingScale;
+}
+
+void Encoder::Reset(int32_t* status) {
+  if (m_counter) {
+    HAL_ResetCounter(m_counter, status);
+  } else {
+    HAL_ResetFPGAEncoder(m_encoder, status);
+  }
+}
+
+double Encoder::GetPeriod(int32_t* status) const {
+  if (m_counter) {
+    return HAL_GetCounterPeriod(m_counter, status) / DecodingScaleFactor();
+  } else {
+    return HAL_GetFPGAEncoderPeriod(m_encoder, status);
+  }
+}
+
+void Encoder::SetMaxPeriod(double maxPeriod, int32_t* status) {
+  if (m_counter) {
+    HAL_SetCounterMaxPeriod(m_counter, maxPeriod, status);
+  } else {
+    HAL_SetFPGAEncoderMaxPeriod(m_encoder, maxPeriod, status);
+  }
+}
+
+bool Encoder::GetStopped(int32_t* status) const {
+  if (m_counter) {
+    return HAL_GetCounterStopped(m_counter, status);
+  } else {
+    return HAL_GetFPGAEncoderStopped(m_encoder, status);
+  }
+}
+
+bool Encoder::GetDirection(int32_t* status) const {
+  if (m_counter) {
+    return HAL_GetCounterDirection(m_counter, status);
+  } else {
+    return HAL_GetFPGAEncoderDirection(m_encoder, status);
+  }
+}
+
+double Encoder::GetDistance(int32_t* status) const {
+  return GetRaw(status) * DecodingScaleFactor() * m_distancePerPulse;
+}
+
+double Encoder::GetRate(int32_t* status) const {
+  return m_distancePerPulse / GetPeriod(status);
+}
+
+void Encoder::SetMinRate(double minRate, int32_t* status) {
+  SetMaxPeriod(m_distancePerPulse / minRate, status);
+}
+
+void Encoder::SetDistancePerPulse(double distancePerPulse, int32_t* status) {
+  m_distancePerPulse = distancePerPulse;
+}
+
+void Encoder::SetReverseDirection(bool reverseDirection, int32_t* status) {
+  if (m_counter) {
+    HAL_SetCounterReverseDirection(m_counter, reverseDirection, status);
+  } else {
+    HAL_SetFPGAEncoderReverseDirection(m_encoder, reverseDirection, status);
+  }
+}
+
+void Encoder::SetSamplesToAverage(int32_t samplesToAverage, int32_t* status) {
+  if (samplesToAverage < 1 || samplesToAverage > 127) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+  if (m_counter) {
+    HAL_SetCounterSamplesToAverage(m_counter, samplesToAverage, status);
+  } else {
+    HAL_SetFPGAEncoderSamplesToAverage(m_encoder, samplesToAverage, status);
+  }
+}
+
+int32_t Encoder::GetSamplesToAverage(int32_t* status) const {
+  if (m_counter) {
+    return HAL_GetCounterSamplesToAverage(m_counter, status);
+  } else {
+    return HAL_GetFPGAEncoderSamplesToAverage(m_encoder, status);
+  }
+}
+
+void Encoder::SetIndexSource(HAL_Handle digitalSourceHandle,
+                             HAL_AnalogTriggerType analogTriggerType,
+                             HAL_EncoderIndexingType type, int32_t* status) {
+  if (m_counter) {
+    *status = HAL_COUNTER_NOT_SUPPORTED;
+    return;
+  }
+  bool activeHigh =
+      (type == HAL_kResetWhileHigh) || (type == HAL_kResetOnRisingEdge);
+  bool edgeSensitive =
+      (type == HAL_kResetOnFallingEdge) || (type == HAL_kResetOnRisingEdge);
+  HAL_SetFPGAEncoderIndexSource(m_encoder, digitalSourceHandle,
+                                analogTriggerType, activeHigh, edgeSensitive,
+                                status);
+}
+
+double Encoder::DecodingScaleFactor() const {
+  switch (m_encodingType) {
+    case HAL_Encoder_k1X:
+      return 1.0;
+    case HAL_Encoder_k2X:
+      return 0.5;
+    case HAL_Encoder_k4X:
+      return 0.25;
+    default:
+      return 0.0;
+  }
+}
+
+static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
+                                    kNumEncoders + kNumCounters,
+                                    HAL_HandleEnum::Encoder>* encoderHandles;
+
+namespace hal {
+namespace init {
+void InitializeEncoder() {
+  static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
+                                      kNumEncoders + kNumCounters,
+                                      HAL_HandleEnum::Encoder>
+      eH;
+  encoderHandles = &eH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_EncoderHandle HAL_InitializeEncoder(
+    HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
+    HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
+    HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
+    int32_t* status) {
+  hal::init::CheckInit();
+  auto encoder = std::make_shared<Encoder>(
+      digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
+      analogTriggerTypeB, reverseDirection, encodingType, status);
+  if (*status != 0) return HAL_kInvalidHandle;  // return in creation error
+  auto handle = encoderHandles->Allocate(encoder);
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  return handle;
+}
+
+void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  encoderHandles->Free(encoderHandle);
+}
+
+int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->Get(status);
+}
+
+int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetRaw(status);
+}
+
+int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
+                                    int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetEncodingScale(status);
+}
+
+void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->Reset(status);
+}
+
+double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetPeriod(status);
+}
+
+void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
+                             int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->SetMaxPeriod(maxPeriod, status);
+}
+
+HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
+                               int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetStopped(status);
+}
+
+HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
+                                 int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetDirection(status);
+}
+
+double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
+                              int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetDistance(status);
+}
+
+double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetRate(status);
+}
+
+void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
+                           int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->SetMinRate(minRate, status);
+}
+
+void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
+                                    double distancePerPulse, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->SetDistancePerPulse(distancePerPulse, status);
+}
+
+void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
+                                    HAL_Bool reverseDirection,
+                                    int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->SetReverseDirection(reverseDirection, status);
+}
+
+void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
+                                    int32_t samplesToAverage, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->SetSamplesToAverage(samplesToAverage, status);
+}
+
+int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
+                                       int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetSamplesToAverage(status);
+}
+
+double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
+                                         int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->DecodingScaleFactor();
+}
+
+double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
+                                      int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetDistancePerPulse();
+}
+
+HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
+    HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_Encoder_k4X;  // default to k4X
+  }
+  return encoder->GetEncodingType();
+}
+
+void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
+                               HAL_Handle digitalSourceHandle,
+                               HAL_AnalogTriggerType analogTriggerType,
+                               HAL_EncoderIndexingType type, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->SetIndexSource(digitalSourceHandle, analogTriggerType, type, status);
+}
+
+int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
+                                int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->GetFPGAIndex();
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/EncoderInternal.h b/hal/src/main/native/athena/EncoderInternal.h
new file mode 100644
index 0000000..1e7ed4d
--- /dev/null
+++ b/hal/src/main/native/athena/EncoderInternal.h
@@ -0,0 +1,78 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Encoder.h"
+
+namespace hal {
+
+class Encoder {
+ public:
+  Encoder(HAL_Handle digitalSourceHandleA,
+          HAL_AnalogTriggerType analogTriggerTypeA,
+          HAL_Handle digitalSourceHandleB,
+          HAL_AnalogTriggerType analogTriggerTypeB, bool reverseDirection,
+          HAL_EncoderEncodingType encodingType, int32_t* status);
+  ~Encoder();
+
+  // CounterBase interface
+  int32_t Get(int32_t* status) const;
+  int32_t GetRaw(int32_t* status) const;
+  int32_t GetEncodingScale(int32_t* status) const;
+  void Reset(int32_t* status);
+  double GetPeriod(int32_t* status) const;
+  void SetMaxPeriod(double maxPeriod, int32_t* status);
+  bool GetStopped(int32_t* status) const;
+  bool GetDirection(int32_t* status) const;
+
+  double GetDistance(int32_t* status) const;
+  double GetRate(int32_t* status) const;
+  void SetMinRate(double minRate, int32_t* status);
+  void SetDistancePerPulse(double distancePerPulse, int32_t* status);
+  void SetReverseDirection(bool reverseDirection, int32_t* status);
+  void SetSamplesToAverage(int32_t samplesToAverage, int32_t* status);
+  int32_t GetSamplesToAverage(int32_t* status) const;
+
+  void SetIndexSource(HAL_Handle digitalSourceHandle,
+                      HAL_AnalogTriggerType analogTriggerType,
+                      HAL_EncoderIndexingType type, int32_t* status);
+
+  int32_t GetFPGAIndex() const { return m_index; }
+
+  int32_t GetEncodingScale() const { return m_encodingScale; }
+
+  double DecodingScaleFactor() const;
+
+  double GetDistancePerPulse() const { return m_distancePerPulse; }
+
+  HAL_EncoderEncodingType GetEncodingType() const { return m_encodingType; }
+
+ private:
+  void SetupCounter(HAL_Handle digitalSourceHandleA,
+                    HAL_AnalogTriggerType analogTriggerTypeA,
+                    HAL_Handle digitalSourceHandleB,
+                    HAL_AnalogTriggerType analogTriggerTypeB,
+                    bool reverseDirection, HAL_EncoderEncodingType encodingType,
+                    int32_t* status);
+
+  HAL_FPGAEncoderHandle m_encoder = HAL_kInvalidHandle;
+
+  HAL_CounterHandle m_counter = HAL_kInvalidHandle;
+
+  int32_t m_index = 0;
+
+  double m_distancePerPulse = 1.0;
+
+  HAL_EncoderEncodingType m_encodingType;
+
+  int32_t m_encodingScale;
+};
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/FPGAEncoder.cpp b/hal/src/main/native/athena/FPGAEncoder.cpp
new file mode 100644
index 0000000..7f2e107
--- /dev/null
+++ b/hal/src/main/native/athena/FPGAEncoder.cpp
@@ -0,0 +1,245 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "FPGAEncoder.h"
+
+#include <memory>
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+
+struct Encoder {
+  std::unique_ptr<tEncoder> encoder;
+  uint8_t index;
+};
+
+}  // namespace
+
+static constexpr double DECODING_SCALING_FACTOR = 0.25;
+
+static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
+                             HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
+
+namespace hal {
+namespace init {
+void InitializeFPGAEncoder() {
+  static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
+                               HAL_HandleEnum::FPGAEncoder>
+      feH;
+  fpgaEncoderHandles = &feH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_FPGAEncoderHandle HAL_InitializeFPGAEncoder(
+    HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
+    HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
+    HAL_Bool reverseDirection, int32_t* index, int32_t* status) {
+  hal::init::CheckInit();
+  bool routingAnalogTriggerA = false;
+  uint8_t routingChannelA = 0;
+  uint8_t routingModuleA = 0;
+  bool successA = remapDigitalSource(digitalSourceHandleA, analogTriggerTypeA,
+                                     routingChannelA, routingModuleA,
+                                     routingAnalogTriggerA);
+  bool routingAnalogTriggerB = false;
+  uint8_t routingChannelB = 0;
+  uint8_t routingModuleB = 0;
+  bool successB = remapDigitalSource(digitalSourceHandleB, analogTriggerTypeB,
+                                     routingChannelB, routingModuleB,
+                                     routingAnalogTriggerB);
+
+  if (!successA || !successB) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  auto handle = fpgaEncoderHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {  // out of resources
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+
+  auto encoder = fpgaEncoderHandles->Get(handle);
+  if (encoder == nullptr) {  // will only error on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  encoder->index = static_cast<uint8_t>(getHandleIndex(handle));
+  *index = encoder->index;
+  // TODO: if (index == ~0ul) { CloneError(quadEncoders); return; }
+  encoder->encoder.reset(tEncoder::create(encoder->index, status));
+  encoder->encoder->writeConfig_ASource_Module(routingModuleA, status);
+  encoder->encoder->writeConfig_ASource_Channel(routingChannelA, status);
+  encoder->encoder->writeConfig_ASource_AnalogTrigger(routingAnalogTriggerA,
+                                                      status);
+  encoder->encoder->writeConfig_BSource_Module(routingModuleB, status);
+  encoder->encoder->writeConfig_BSource_Channel(routingChannelB, status);
+  encoder->encoder->writeConfig_BSource_AnalogTrigger(routingAnalogTriggerB,
+                                                      status);
+  encoder->encoder->strobeReset(status);
+  encoder->encoder->writeConfig_Reverse(reverseDirection, status);
+  encoder->encoder->writeTimerConfig_AverageSize(4, status);
+
+  return handle;
+}
+
+void HAL_FreeFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                         int32_t* status) {
+  fpgaEncoderHandles->Free(fpgaEncoderHandle);
+}
+
+void HAL_ResetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                          int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->encoder->strobeReset(status);
+}
+
+int32_t HAL_GetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                           int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->encoder->readOutput_Value(status);
+}
+
+double HAL_GetFPGAEncoderPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+  tEncoder::tTimerOutput output = encoder->encoder->readTimerOutput(status);
+  double value;
+  if (output.Stalled) {
+    // Return infinity
+    double zero = 0.0;
+    value = 1.0 / zero;
+  } else {
+    // output.Period is a fixed point number that counts by 2 (24 bits, 25
+    // integer bits)
+    value = static_cast<double>(output.Period << 1) /
+            static_cast<double>(output.Count);
+  }
+  double measuredPeriod = value * 2.5e-8;
+  return measuredPeriod / DECODING_SCALING_FACTOR;
+}
+
+void HAL_SetFPGAEncoderMaxPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                 double maxPeriod, int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->encoder->writeTimerConfig_StallPeriod(
+      static_cast<uint32_t>(maxPeriod * 4.0e8 * DECODING_SCALING_FACTOR),
+      status);
+}
+
+HAL_Bool HAL_GetFPGAEncoderStopped(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                   int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return encoder->encoder->readTimerOutput_Stalled(status) != 0;
+}
+
+HAL_Bool HAL_GetFPGAEncoderDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                     int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return encoder->encoder->readOutput_Direction(status);
+}
+
+void HAL_SetFPGAEncoderReverseDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                        HAL_Bool reverseDirection,
+                                        int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  encoder->encoder->writeConfig_Reverse(reverseDirection, status);
+}
+
+void HAL_SetFPGAEncoderSamplesToAverage(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                        int32_t samplesToAverage,
+                                        int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (samplesToAverage < 1 || samplesToAverage > 127) {
+    *status = PARAMETER_OUT_OF_RANGE;
+  }
+  encoder->encoder->writeTimerConfig_AverageSize(samplesToAverage, status);
+}
+
+int32_t HAL_GetFPGAEncoderSamplesToAverage(
+    HAL_FPGAEncoderHandle fpgaEncoderHandle, int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return encoder->encoder->readTimerConfig_AverageSize(status);
+}
+
+void HAL_SetFPGAEncoderIndexSource(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                   HAL_Handle digitalSourceHandle,
+                                   HAL_AnalogTriggerType analogTriggerType,
+                                   HAL_Bool activeHigh, HAL_Bool edgeSensitive,
+                                   int32_t* status) {
+  auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  bool routingAnalogTrigger = false;
+  uint8_t routingChannel = 0;
+  uint8_t routingModule = 0;
+  bool success =
+      remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
+                         routingModule, routingAnalogTrigger);
+  if (!success) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  encoder->encoder->writeConfig_IndexSource_Channel(routingChannel, status);
+  encoder->encoder->writeConfig_IndexSource_Module(routingModule, status);
+  encoder->encoder->writeConfig_IndexSource_AnalogTrigger(routingAnalogTrigger,
+                                                          status);
+  encoder->encoder->writeConfig_IndexActiveHigh(activeHigh, status);
+  encoder->encoder->writeConfig_IndexEdgeSensitive(edgeSensitive, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/FPGAEncoder.h b/hal/src/main/native/athena/FPGAEncoder.h
new file mode 100644
index 0000000..f29aeae
--- /dev/null
+++ b/hal/src/main/native/athena/FPGAEncoder.h
@@ -0,0 +1,126 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/AnalogTrigger.h"
+#include "hal/Types.h"
+
+extern "C" {
+
+HAL_FPGAEncoderHandle HAL_InitializeFPGAEncoder(
+    HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
+    HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
+    HAL_Bool reverseDirection, int32_t* index, int32_t* status);
+void HAL_FreeFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                         int32_t* status);
+
+/**
+ * Reset the Encoder distance to zero.
+ * Resets the current count to zero on the encoder.
+ */
+void HAL_ResetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                          int32_t* status);
+
+/**
+ * Gets the fpga value from the encoder.
+ * The fpga value is the actual count unscaled by the 1x, 2x, or 4x scale
+ * factor.
+ * @return Current fpga count from the encoder
+ */
+int32_t HAL_GetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                           int32_t* status);  // Raw value
+
+/**
+ * Returns the period of the most recent pulse.
+ * Returns the period of the most recent Encoder pulse in seconds.
+ * This method compenstates for the decoding type.
+ *
+ * @deprecated Use GetRate() in favor of this method.  This returns unscaled
+ * periods and GetRate() scales using value from SetDistancePerPulse().
+ *
+ * @return Period in seconds of the most recent pulse.
+ */
+double HAL_GetFPGAEncoderPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                int32_t* status);
+
+/**
+ * Sets the maximum period for stopped detection.
+ * Sets the value that represents the maximum period of the Encoder before it
+ * will assume that the attached device is stopped. This timeout allows users
+ * to determine if the wheels or other shaft has stopped rotating.
+ * This method compensates for the decoding type.
+ *
+ * @deprecated Use SetMinRate() in favor of this method.  This takes unscaled
+ * periods and SetMinRate() scales using value from SetDistancePerPulse().
+ *
+ * @param maxPeriod The maximum time between rising and falling edges before the
+ * FPGA will
+ * report the device stopped. This is expressed in seconds.
+ */
+void HAL_SetFPGAEncoderMaxPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                 double maxPeriod, int32_t* status);
+
+/**
+ * Determine if the encoder is stopped.
+ * Using the MaxPeriod value, a boolean is returned that is true if the encoder
+ * is considered stopped and false if it is still moving. A stopped encoder is
+ * one where the most recent pulse width exceeds the MaxPeriod.
+ * @return True if the encoder is considered stopped.
+ */
+HAL_Bool HAL_GetFPGAEncoderStopped(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                   int32_t* status);
+
+/**
+ * The last direction the encoder value changed.
+ * @return The last direction the encoder value changed.
+ */
+HAL_Bool HAL_GetFPGAEncoderDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                     int32_t* status);
+
+/**
+ * Set the direction sensing for this encoder.
+ * This sets the direction sensing on the encoder so that it could count in the
+ * correct software direction regardless of the mounting.
+ * @param reverseDirection true if the encoder direction should be reversed
+ */
+void HAL_SetFPGAEncoderReverseDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                        HAL_Bool reverseDirection,
+                                        int32_t* status);
+
+/**
+ * Set the Samples to Average which specifies the number of samples of the timer
+ * to average when calculating the period. Perform averaging to account for
+ * mechanical imperfections or as oversampling to increase resolution.
+ * @param samplesToAverage The number of samples to average from 1 to 127.
+ */
+void HAL_SetFPGAEncoderSamplesToAverage(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                        int32_t samplesToAverage,
+                                        int32_t* status);
+
+/**
+ * Get the Samples to Average which specifies the number of samples of the timer
+ * to average when calculating the period. Perform averaging to account for
+ * mechanical imperfections or as oversampling to increase resolution.
+ * @return SamplesToAverage The number of samples being averaged (from 1 to 127)
+ */
+int32_t HAL_GetFPGAEncoderSamplesToAverage(
+    HAL_FPGAEncoderHandle fpgaEncoderHandle, int32_t* status);
+
+/**
+ * Set an index source for an encoder, which is an input that resets the
+ * encoder's count.
+ */
+void HAL_SetFPGAEncoderIndexSource(HAL_FPGAEncoderHandle fpgaEncoderHandle,
+                                   HAL_Handle digitalSourceHandle,
+                                   HAL_AnalogTriggerType analogTriggerType,
+                                   HAL_Bool activeHigh, HAL_Bool edgeSensitive,
+                                   int32_t* status);
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/FRCDriverStation.cpp b/hal/src/main/native/athena/FRCDriverStation.cpp
new file mode 100644
index 0000000..5409ad0
--- /dev/null
+++ b/hal/src/main/native/athena/FRCDriverStation.cpp
@@ -0,0 +1,536 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <atomic>
+#include <chrono>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+
+#include <FRC_NetworkCommunication/FRCComm.h>
+#include <FRC_NetworkCommunication/NetCommRPCProxy_Occur.h>
+#include <wpi/SafeThread.h>
+#include <wpi/condition_variable.h>
+#include <wpi/mutex.h>
+#include <wpi/raw_ostream.h>
+
+#include "hal/DriverStation.h"
+
+static_assert(sizeof(int32_t) >= sizeof(int),
+              "FRC_NetworkComm status variable is larger than 32 bits");
+
+struct HAL_JoystickAxesInt {
+  int16_t count;
+  int16_t axes[HAL_kMaxJoystickAxes];
+};
+
+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;
+
+  int retVal = FRC_NetworkCommunication_getJoystickAxes(
+      joystickNum, reinterpret_cast<JoystickAxes_t*>(&axesInt),
+      HAL_kMaxJoystickAxes);
+
+  // copy integer values to double values
+  axes->count = axesInt.count;
+  // current scaling is -128 to 127, can easily be patched in the future by
+  // changing this function.
+  for (int32_t i = 0; i < axesInt.count; i++) {
+    int8_t value = axesInt.axes[i];
+    if (value < 0) {
+      axes->axes[i] = value / 128.0;
+    } else {
+      axes->axes[i] = value / 127.0;
+    }
+  }
+
+  return retVal;
+}
+
+static int32_t HAL_GetJoystickPOVsInternal(int32_t joystickNum,
+                                           HAL_JoystickPOVs* povs) {
+  return FRC_NetworkCommunication_getJoystickPOVs(
+      joystickNum, reinterpret_cast<JoystickPOV_t*>(povs),
+      HAL_kMaxJoystickPOVs);
+}
+
+static int32_t HAL_GetJoystickButtonsInternal(int32_t joystickNum,
+                                              HAL_JoystickButtons* buttons) {
+  return FRC_NetworkCommunication_getJoystickButtons(
+      joystickNum, &buttons->buttons, &buttons->count);
+}
+/**
+ * Retrieve the Joystick Descriptor for particular slot
+ * @param desc [out] descriptor (data transfer object) to fill in.  desc is
+ * filled in regardless of success. In other words, if descriptor is not
+ * available, desc is filled in with default values matching the init-values in
+ * Java and C++ Driverstation for when caller requests a too-large joystick
+ * index.
+ *
+ * @return error code reported from Network Comm back-end.  Zero is good,
+ * nonzero is bad.
+ */
+static int32_t HAL_GetJoystickDescriptorInternal(int32_t joystickNum,
+                                                 HAL_JoystickDescriptor* desc) {
+  desc->isXbox = 0;
+  desc->type = std::numeric_limits<uint8_t>::max();
+  desc->name[0] = '\0';
+  desc->axisCount =
+      HAL_kMaxJoystickAxes; /* set to the desc->axisTypes's capacity */
+  desc->buttonCount = 0;
+  desc->povCount = 0;
+  int retval = FRC_NetworkCommunication_getJoystickDesc(
+      joystickNum, &desc->isXbox, &desc->type,
+      reinterpret_cast<char*>(&desc->name), &desc->axisCount,
+      reinterpret_cast<uint8_t*>(&desc->axisTypes), &desc->buttonCount,
+      &desc->povCount);
+  /* check the return, if there is an error and the RIOimage predates FRC2017,
+   * then axisCount needs to be cleared */
+  if (retval != 0) {
+    /* set count to zero so downstream code doesn't decode invalid axisTypes. */
+    desc->axisCount = 0;
+  }
+  return retval;
+}
+
+static int32_t HAL_GetControlWordInternal(HAL_ControlWord* controlWord) {
+  std::memset(controlWord, 0, sizeof(HAL_ControlWord));
+  return FRC_NetworkCommunication_getControlWord(
+      reinterpret_cast<ControlWord_t*>(controlWord));
+}
+
+static int32_t HAL_GetMatchInfoInternal(HAL_MatchInfo* info) {
+  MatchType_t matchType = MatchType_t::kMatchType_none;
+  int status = FRC_NetworkCommunication_getMatchInfo(
+      info->eventName, &matchType, &info->matchNumber, &info->replayNumber,
+      info->gameSpecificMessage, &info->gameSpecificMessageSize);
+
+  info->matchType = static_cast<HAL_MatchType>(matchType);
+
+  *(std::end(info->eventName) - 1) = '\0';
+
+  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;
+
+namespace hal {
+namespace init {
+void InitializeFRCDriverStation() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+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) {
+  // 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);
+  static std::string prevMsg[KEEP_MSGS];
+  static std::chrono::time_point<std::chrono::steady_clock>
+      prevMsgTime[KEEP_MSGS];
+  static bool initialized = false;
+  if (!initialized) {
+    for (int i = 0; i < KEEP_MSGS; i++) {
+      prevMsgTime[i] =
+          std::chrono::steady_clock::now() - std::chrono::seconds(2);
+    }
+    initialized = true;
+  }
+
+  auto curTime = std::chrono::steady_clock::now();
+  int i;
+  for (i = 0; i < KEEP_MSGS; ++i) {
+    if (prevMsg[i] == details) break;
+  }
+  int retval = 0;
+  if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
+    retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
+                                                details, location, callStack);
+    if (printMsg) {
+      if (location && location[0] != '\0') {
+        wpi::errs() << (isError ? "Error" : "Warning") << " at " << location
+                    << ": ";
+      }
+      wpi::errs() << details << "\n";
+      if (callStack && callStack[0] != '\0') {
+        wpi::errs() << callStack << "\n";
+      }
+    }
+    if (i == KEEP_MSGS) {
+      // replace the oldest one
+      i = 0;
+      auto first = prevMsgTime[0];
+      for (int j = 1; j < KEEP_MSGS; ++j) {
+        if (prevMsgTime[j] < first) {
+          first = prevMsgTime[j];
+          i = j;
+        }
+      }
+      prevMsg[i] = details;
+    }
+    prevMsgTime[i] = curTime;
+  }
+  return retval;
+}
+
+int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
+  std::memset(controlWord, 0, sizeof(HAL_ControlWord));
+  UpdateDriverStationControlWord(false, *controlWord);
+  return 0;
+}
+
+int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
+  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
+  *axes = m_joystickAxes[joystickNum];
+  return 0;
+}
+
+int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
+  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
+  *povs = m_joystickPOVs[joystickNum];
+  return 0;
+}
+
+int32_t HAL_GetJoystickButtons(int32_t joystickNum,
+                               HAL_JoystickButtons* buttons) {
+  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
+  *buttons = m_joystickButtons[joystickNum];
+  return 0;
+}
+
+int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
+                                  HAL_JoystickDescriptor* desc) {
+  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
+  *desc = m_joystickDescriptor[joystickNum];
+  return 0;
+}
+
+int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
+  std::unique_lock<wpi::mutex> lock(m_cacheDataMutex);
+  *info = *m_matchInfo;
+  return 0;
+}
+
+HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
+  HAL_AllianceStationID allianceStation;
+  *status = FRC_NetworkCommunication_getAllianceStation(
+      reinterpret_cast<AllianceStationID_t*>(&allianceStation));
+  return allianceStation;
+}
+
+HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
+  HAL_JoystickDescriptor joystickDesc;
+  if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
+    return 0;
+  } else {
+    return joystickDesc.isXbox;
+  }
+}
+
+int32_t HAL_GetJoystickType(int32_t joystickNum) {
+  HAL_JoystickDescriptor joystickDesc;
+  if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
+    return -1;
+  } else {
+    return joystickDesc.type;
+  }
+}
+
+char* HAL_GetJoystickName(int32_t joystickNum) {
+  HAL_JoystickDescriptor joystickDesc;
+  if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
+    char* name = static_cast<char*>(std::malloc(1));
+    name[0] = '\0';
+    return name;
+  } else {
+    size_t len = std::strlen(joystickDesc.name);
+    char* name = static_cast<char*>(std::malloc(len + 1));
+    std::strncpy(name, joystickDesc.name, len);
+    name[len] = '\0';
+    return name;
+  }
+}
+
+void HAL_FreeJoystickName(char* name) { std::free(name); }
+
+int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
+  HAL_JoystickDescriptor joystickDesc;
+  if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
+    return -1;
+  } else {
+    return joystickDesc.axisTypes[axis];
+  }
+}
+
+int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
+                               int32_t leftRumble, int32_t rightRumble) {
+  return FRC_NetworkCommunication_setJoystickOutputs(joystickNum, outputs,
+                                                     leftRumble, rightRumble);
+}
+
+double HAL_GetMatchTime(int32_t* status) {
+  float matchTime;
+  *status = FRC_NetworkCommunication_getMatchTime(&matchTime);
+  return matchTime;
+}
+
+void HAL_ObserveUserProgramStarting(void) {
+  FRC_NetworkCommunication_observeUserProgramStarting();
+}
+
+void HAL_ObserveUserProgramDisabled(void) {
+  FRC_NetworkCommunication_observeUserProgramDisabled();
+}
+
+void HAL_ObserveUserProgramAutonomous(void) {
+  FRC_NetworkCommunication_observeUserProgramAutonomous();
+}
+
+void HAL_ObserveUserProgramTeleop(void) {
+  FRC_NetworkCommunication_observeUserProgramTeleop();
+}
+
+void HAL_ObserveUserProgramTest(void) {
+  FRC_NetworkCommunication_observeUserProgramTest();
+}
+
+HAL_Bool HAL_IsNewControlData(void) {
+  // There is a rollover error condition here. At Packet# = n * (uintmax), this
+  // will return false when instead it should return true. However, this at a
+  // 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;
+  if (lastCount == currentCount) return false;
+  lastCount = currentCount;
+  return true;
+}
+
+/**
+ * Waits for the newest DS packet to arrive. Note that this is a blocking call.
+ */
+void HAL_WaitForDSData(void) { HAL_WaitForDSDataTimeout(0); }
+
+/**
+ * Waits for the newest DS packet to arrive. If timeout is <= 0, this will wait
+ * forever. Otherwise, it will wait until either a new packet, or the timeout
+ * time has passed. Returns true on new data, false on timeout.
+ */
+HAL_Bool HAL_WaitForDSDataTimeout(double timeout) {
+  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) {
+    if (timeout > 0) {
+      auto timedOut =
+          thr->newDSDataAvailableCond.wait_until(thr.GetLock(), timeoutTime);
+      if (timedOut == std::cv_status::timeout) {
+        return false;
+      }
+    } else {
+      thr->newDSDataAvailableCond.wait(thr.GetLock());
+    }
+  }
+  return true;
+}
+
+// Constant number to be used for our occur handle
+constexpr int32_t refNumber = 42;
+
+static void newDataOccur(uint32_t refNum) {
+  // Since we could get other values, require our specific handle
+  // to signal our threads
+  if (refNum != refNumber) return;
+  dsThread->Notify();
+}
+
+/*
+ * Call this to initialize the driver station communication. This will properly
+ * handle multiple calls. However note that this CANNOT be called from a library
+ * that interfaces with LabVIEW.
+ */
+void HAL_InitializeDriverStation(void) {
+  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;
+
+  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
+  setNewDataOccurRef(refNumber);
+
+  initialized = true;
+}
+
+/*
+ * Releases the DS Mutex to allow proper shutdown of any threads that are
+ * waiting on it.
+ */
+void HAL_ReleaseDSMutex(void) { newDataOccur(refNumber); }
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp
new file mode 100644
index 0000000..dbdb826
--- /dev/null
+++ b/hal/src/main/native/athena/HAL.cpp
@@ -0,0 +1,410 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/HAL.h"
+
+#include <signal.h>  // linux for kill
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <cstdlib>
+#include <fstream>
+#include <thread>
+
+#include <FRC_NetworkCommunication/FRCComm.h>
+#include <FRC_NetworkCommunication/LoadOut.h>
+#include <FRC_NetworkCommunication/UsageReporting.h>
+#include <wpi/mutex.h>
+#include <wpi/raw_ostream.h>
+#include <wpi/timestamp.h>
+
+#include "HALInitializer.h"
+#include "ctre/ctre.h"
+#include "hal/ChipObject.h"
+#include "hal/DriverStation.h"
+#include "hal/Errors.h"
+#include "hal/Notifier.h"
+#include "hal/handles/HandlesInternal.h"
+#include "visa/visa.h"
+
+using namespace hal;
+
+static std::unique_ptr<tGlobal> global;
+static std::unique_ptr<tSysWatchdog> watchdog;
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeHAL() {
+  InitializeAccelerometer();
+  InitializeAnalogAccumulator();
+  InitializeAnalogGyro();
+  InitializeAnalogInput();
+  InitializeAnalogInternal();
+  InitializeAnalogOutput();
+  InitializeAnalogTrigger();
+  InitializeCAN();
+  InitializeCANAPI();
+  InitializeCompressor();
+  InitializeConstants();
+  InitializeCounter();
+  InitializeDigitalInternal();
+  InitializeDIO();
+  InitializeEncoder();
+  InitializeFPGAEncoder();
+  InitializeFRCDriverStation();
+  InitializeI2C();
+  InitialzeInterrupts();
+  InitializeNotifier();
+  InitializePCMInternal();
+  InitializePDP();
+  InitializePorts();
+  InitializePower();
+  InitializePWM();
+  InitializeRelay();
+  InitializeSerialPort();
+  InitializeSolenoid();
+  InitializeSPI();
+  InitializeThreads();
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_PortHandle HAL_GetPort(int32_t channel) {
+  // Dont allow a number that wouldn't fit in a uint8_t
+  if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
+  return createPortHandle(channel, 1);
+}
+
+HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
+  // Dont allow a number that wouldn't fit in a uint8_t
+  if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
+  if (module < 0 || module >= 255) return HAL_kInvalidHandle;
+  return createPortHandle(channel, module);
+}
+
+const char* HAL_GetErrorMessage(int32_t code) {
+  switch (code) {
+    case 0:
+      return "";
+    case CTR_RxTimeout:
+      return CTR_RxTimeout_MESSAGE;
+    case CTR_TxTimeout:
+      return CTR_TxTimeout_MESSAGE;
+    case CTR_InvalidParamValue:
+      return CTR_InvalidParamValue_MESSAGE;
+    case CTR_UnexpectedArbId:
+      return CTR_UnexpectedArbId_MESSAGE;
+    case CTR_TxFailed:
+      return CTR_TxFailed_MESSAGE;
+    case CTR_SigNotUpdated:
+      return CTR_SigNotUpdated_MESSAGE;
+    case NiFpga_Status_FifoTimeout:
+      return NiFpga_Status_FifoTimeout_MESSAGE;
+    case NiFpga_Status_TransferAborted:
+      return NiFpga_Status_TransferAborted_MESSAGE;
+    case NiFpga_Status_MemoryFull:
+      return NiFpga_Status_MemoryFull_MESSAGE;
+    case NiFpga_Status_SoftwareFault:
+      return NiFpga_Status_SoftwareFault_MESSAGE;
+    case NiFpga_Status_InvalidParameter:
+      return NiFpga_Status_InvalidParameter_MESSAGE;
+    case NiFpga_Status_ResourceNotFound:
+      return NiFpga_Status_ResourceNotFound_MESSAGE;
+    case NiFpga_Status_ResourceNotInitialized:
+      return NiFpga_Status_ResourceNotInitialized_MESSAGE;
+    case NiFpga_Status_HardwareFault:
+      return NiFpga_Status_HardwareFault_MESSAGE;
+    case NiFpga_Status_IrqTimeout:
+      return NiFpga_Status_IrqTimeout_MESSAGE;
+    case SAMPLE_RATE_TOO_HIGH:
+      return SAMPLE_RATE_TOO_HIGH_MESSAGE;
+    case VOLTAGE_OUT_OF_RANGE:
+      return VOLTAGE_OUT_OF_RANGE_MESSAGE;
+    case LOOP_TIMING_ERROR:
+      return LOOP_TIMING_ERROR_MESSAGE;
+    case SPI_WRITE_NO_MOSI:
+      return SPI_WRITE_NO_MOSI_MESSAGE;
+    case SPI_READ_NO_MISO:
+      return SPI_READ_NO_MISO_MESSAGE;
+    case SPI_READ_NO_DATA:
+      return SPI_READ_NO_DATA_MESSAGE;
+    case INCOMPATIBLE_STATE:
+      return INCOMPATIBLE_STATE_MESSAGE;
+    case NO_AVAILABLE_RESOURCES:
+      return NO_AVAILABLE_RESOURCES_MESSAGE;
+    case RESOURCE_IS_ALLOCATED:
+      return RESOURCE_IS_ALLOCATED_MESSAGE;
+    case RESOURCE_OUT_OF_RANGE:
+      return RESOURCE_OUT_OF_RANGE_MESSAGE;
+    case HAL_INVALID_ACCUMULATOR_CHANNEL:
+      return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
+    case HAL_HANDLE_ERROR:
+      return HAL_HANDLE_ERROR_MESSAGE;
+    case NULL_PARAMETER:
+      return NULL_PARAMETER_MESSAGE;
+    case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
+      return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
+    case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
+      return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
+    case PARAMETER_OUT_OF_RANGE:
+      return PARAMETER_OUT_OF_RANGE_MESSAGE;
+    case HAL_COUNTER_NOT_SUPPORTED:
+      return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
+    case HAL_ERR_CANSessionMux_InvalidBuffer:
+      return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
+    case HAL_ERR_CANSessionMux_MessageNotFound:
+      return ERR_CANSessionMux_MessageNotFound_MESSAGE;
+    case HAL_WARN_CANSessionMux_NoToken:
+      return WARN_CANSessionMux_NoToken_MESSAGE;
+    case HAL_ERR_CANSessionMux_NotAllowed:
+      return ERR_CANSessionMux_NotAllowed_MESSAGE;
+    case HAL_ERR_CANSessionMux_NotInitialized:
+      return ERR_CANSessionMux_NotInitialized_MESSAGE;
+    case VI_ERROR_SYSTEM_ERROR:
+      return VI_ERROR_SYSTEM_ERROR_MESSAGE;
+    case VI_ERROR_INV_OBJECT:
+      return VI_ERROR_INV_OBJECT_MESSAGE;
+    case VI_ERROR_RSRC_LOCKED:
+      return VI_ERROR_RSRC_LOCKED_MESSAGE;
+    case VI_ERROR_RSRC_NFOUND:
+      return VI_ERROR_RSRC_NFOUND_MESSAGE;
+    case VI_ERROR_INV_RSRC_NAME:
+      return VI_ERROR_INV_RSRC_NAME_MESSAGE;
+    case VI_ERROR_QUEUE_OVERFLOW:
+      return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
+    case VI_ERROR_IO:
+      return VI_ERROR_IO_MESSAGE;
+    case VI_ERROR_ASRL_PARITY:
+      return VI_ERROR_ASRL_PARITY_MESSAGE;
+    case VI_ERROR_ASRL_FRAMING:
+      return VI_ERROR_ASRL_FRAMING_MESSAGE;
+    case VI_ERROR_ASRL_OVERRUN:
+      return VI_ERROR_ASRL_OVERRUN_MESSAGE;
+    case VI_ERROR_RSRC_BUSY:
+      return VI_ERROR_RSRC_BUSY_MESSAGE;
+    case VI_ERROR_INV_PARAMETER:
+      return VI_ERROR_INV_PARAMETER_MESSAGE;
+    case HAL_PWM_SCALE_ERROR:
+      return HAL_PWM_SCALE_ERROR_MESSAGE;
+    case HAL_SERIAL_PORT_NOT_FOUND:
+      return HAL_SERIAL_PORT_NOT_FOUND_MESSAGE;
+    case HAL_THREAD_PRIORITY_ERROR:
+      return HAL_THREAD_PRIORITY_ERROR_MESSAGE;
+    case HAL_THREAD_PRIORITY_RANGE_ERROR:
+      return HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE;
+    case HAL_SERIAL_PORT_OPEN_ERROR:
+      return HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE;
+    case HAL_SERIAL_PORT_ERROR:
+      return HAL_SERIAL_PORT_ERROR_MESSAGE;
+    case HAL_CAN_TIMEOUT:
+      return HAL_CAN_TIMEOUT_MESSAGE;
+    case ERR_FRCSystem_NetCommNotResponding:
+      return ERR_FRCSystem_NetCommNotResponding_MESSAGE;
+    case ERR_FRCSystem_NoDSConnection:
+      return ERR_FRCSystem_NoDSConnection_MESSAGE;
+    default:
+      return "Unknown error status";
+  }
+}
+
+HAL_RuntimeType HAL_GetRuntimeType(void) { return HAL_Athena; }
+
+int32_t HAL_GetFPGAVersion(int32_t* status) {
+  if (!global) {
+    *status = NiFpga_Status_ResourceNotInitialized;
+    return 0;
+  }
+  return global->readVersion(status);
+}
+
+int64_t HAL_GetFPGARevision(int32_t* status) {
+  if (!global) {
+    *status = NiFpga_Status_ResourceNotInitialized;
+    return 0;
+  }
+  return global->readRevision(status);
+}
+
+uint64_t HAL_GetFPGATime(int32_t* status) {
+  if (!global) {
+    *status = NiFpga_Status_ResourceNotInitialized;
+    return 0;
+  }
+  *status = 0;
+  uint64_t upper1 = global->readLocalTimeUpper(status);
+  uint32_t lower = global->readLocalTime(status);
+  uint64_t upper2 = global->readLocalTimeUpper(status);
+  if (*status != 0) return 0;
+  if (upper1 != upper2) {
+    // Rolled over between the lower call, reread lower
+    lower = global->readLocalTime(status);
+    if (*status != 0) return 0;
+  }
+  return (upper2 << 32) + lower;
+}
+
+HAL_Bool HAL_GetFPGAButton(int32_t* status) {
+  if (!global) {
+    *status = NiFpga_Status_ResourceNotInitialized;
+    return false;
+  }
+  return global->readUserButton(status);
+}
+
+HAL_Bool HAL_GetSystemActive(int32_t* status) {
+  if (!watchdog) {
+    *status = NiFpga_Status_ResourceNotInitialized;
+    return false;
+  }
+  return watchdog->readStatus_SystemActive(status);
+}
+
+HAL_Bool HAL_GetBrownedOut(int32_t* status) {
+  if (!watchdog) {
+    *status = NiFpga_Status_ResourceNotInitialized;
+    return false;
+  }
+  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;
+  // By making this both in/out, it won't give us an error if it doesnt exist
+  fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
+  if (fs.bad()) return false;
+
+  pid_t pid = 0;
+  if (!fs.eof() && !fs.fail()) {
+    fs >> pid;
+    // see if the pid is around, but we don't want to mess with init id=1, or
+    // ourselves
+    if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
+      wpi::outs() << "Killing previously running FRC program...\n";
+      kill(pid, SIGTERM);  // try to kill it
+      std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
+      if (kill(pid, 0) == 0) {
+        // still not successfull
+        wpi::outs() << "FRC pid " << pid << " did not die within " << timeout
+                    << "ms. Force killing with kill -9\n";
+        // Force kill -9
+        auto forceKill = kill(pid, SIGKILL);
+        if (forceKill != 0) {
+          auto errorMsg = std::strerror(forceKill);
+          wpi::outs() << "Kill -9 error: " << errorMsg << "\n";
+        }
+        // Give a bit of time for the kill to take place
+        std::this_thread::sleep_for(std::chrono::milliseconds(250));
+      }
+    }
+  }
+  fs.close();
+  // we will re-open it write only to truncate the file
+  fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
+  fs.seekp(0);
+  pid = getpid();
+  fs << pid << std::endl;
+  fs.close();
+  return true;
+}
+
+HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
+  static std::atomic_bool initialized{false};
+  static wpi::mutex initializeMutex;
+  // Initial check, as if it's true initialization has finished
+  if (initialized) return true;
+
+  std::lock_guard<wpi::mutex> lock(initializeMutex);
+  // Second check in case another thread was waiting
+  if (initialized) return true;
+
+  hal::init::InitializeHAL();
+
+  hal::init::HAL_IsInitialized.store(true);
+
+  setlinebuf(stdin);
+  setlinebuf(stdout);
+  wpi::outs().SetUnbuffered();
+
+  prctl(PR_SET_PDEATHSIG, SIGTERM);
+
+  // Return false if program failed to kill an existing program
+  if (!killExistingProgram(timeout, mode)) {
+    return false;
+  }
+
+  FRC_NetworkCommunication_Reserve(nullptr);
+
+  std::atexit([]() {
+    // Unregister our new data condition variable.
+    setNewDataSem(nullptr);
+  });
+
+  int32_t status = 0;
+  HAL_BaseInitialize(&status);
+  if (status != 0) return false;
+
+  HAL_InitializeDriverStation();
+
+  // Set WPI_Now to use FPGA timestamp
+  wpi::SetNowImpl([]() -> uint64_t {
+    int32_t status = 0;
+    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";
+      wpi::errs().flush();
+      return 0u;
+    }
+    return rv;
+  });
+
+  initialized = true;
+  return true;
+}
+
+int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
+                   const char* feature) {
+  if (feature == nullptr) {
+    feature = "";
+  }
+
+  return FRC_NetworkCommunication_nUsageReporting_report(
+      resource, instanceNumber, context, feature);
+}
+
+// TODO: HACKS
+// No need for header definitions, as we should not run from user code.
+void NumericArrayResize(void) {}
+void RTSetCleanupProc(void) {}
+void EDVR_CreateReference(void) {}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/HALInitializer.cpp b/hal/src/main/native/athena/HALInitializer.cpp
new file mode 100644
index 0000000..a0456d4
--- /dev/null
+++ b/hal/src/main/native/athena/HALInitializer.cpp
@@ -0,0 +1,17 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HALInitializer.h"
+
+#include "hal/HAL.h"
+
+namespace hal {
+namespace init {
+std::atomic_bool HAL_IsInitialized{false};
+void RunInitialize() { HAL_Initialize(500, 0); }
+}  // namespace init
+}  // namespace hal
diff --git a/hal/src/main/native/athena/HALInitializer.h b/hal/src/main/native/athena/HALInitializer.h
new file mode 100644
index 0000000..384fe58
--- /dev/null
+++ b/hal/src/main/native/athena/HALInitializer.h
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <atomic>
+
+namespace hal {
+namespace init {
+extern std::atomic_bool HAL_IsInitialized;
+extern void RunInitialize();
+static inline void CheckInit() {
+  if (HAL_IsInitialized.load(std::memory_order_relaxed)) return;
+  RunInitialize();
+}
+
+extern void InitializeAccelerometer();
+extern void InitializeAnalogAccumulator();
+extern void InitializeAnalogGyro();
+extern void InitializeAnalogInput();
+extern void InitializeAnalogInternal();
+extern void InitializeAnalogOutput();
+extern void InitializeAnalogTrigger();
+extern void InitializeCAN();
+extern void InitializeCANAPI();
+extern void InitializeCompressor();
+extern void InitializeConstants();
+extern void InitializeCounter();
+extern void InitializeDigitalInternal();
+extern void InitializeDIO();
+extern void InitializeEncoder();
+extern void InitializeFPGAEncoder();
+extern void InitializeFRCDriverStation();
+extern void InitializeHAL();
+extern void InitializeI2C();
+extern void InitialzeInterrupts();
+extern void InitializeNotifier();
+extern void InitializePCMInternal();
+extern void InitializePDP();
+extern void InitializePorts();
+extern void InitializePower();
+extern void InitializePWM();
+extern void InitializeRelay();
+extern void InitializeSerialPort();
+extern void InitializeSolenoid();
+extern void InitializeSPI();
+extern void InitializeThreads();
+}  // namespace init
+}  // namespace hal
diff --git a/hal/src/main/native/athena/I2C.cpp b/hal/src/main/native/athena/I2C.cpp
new file mode 100644
index 0000000..907906e
--- /dev/null
+++ b/hal/src/main/native/athena/I2C.cpp
@@ -0,0 +1,192 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/I2C.h"
+
+#include <fcntl.h>
+#include <linux/i2c-dev.h>
+#include <linux/i2c.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <cstring>
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "hal/DIO.h"
+#include "hal/HAL.h"
+
+using namespace hal;
+
+static wpi::mutex digitalI2COnBoardMutex;
+static wpi::mutex digitalI2CMXPMutex;
+
+static uint8_t i2COnboardObjCount{0};
+static uint8_t i2CMXPObjCount{0};
+static int i2COnBoardHandle{-1};
+static int i2CMXPHandle{-1};
+
+static HAL_DigitalHandle i2CMXPDigitalHandle1{HAL_kInvalidHandle};
+static HAL_DigitalHandle i2CMXPDigitalHandle2{HAL_kInvalidHandle};
+
+namespace hal {
+namespace init {
+void InitializeI2C() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status) {
+  hal::init::CheckInit();
+  initializeDigital(status);
+  if (*status != 0) return;
+
+  if (port < 0 || port > 1) {
+    // Set port out of range error here
+    return;
+  }
+
+  if (port == HAL_I2C_kOnboard) {
+    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    i2COnboardObjCount++;
+    if (i2COnboardObjCount > 1) return;
+    int handle = open("/dev/i2c-2", O_RDWR);
+    if (handle < 0) {
+      std::printf("Failed to open onboard i2c bus: %s\n", std::strerror(errno));
+      return;
+    }
+    i2COnBoardHandle = handle;
+  } else {
+    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    i2CMXPObjCount++;
+    if (i2CMXPObjCount > 1) return;
+    if ((i2CMXPDigitalHandle1 = HAL_InitializeDIOPort(
+             HAL_GetPort(24), false, status)) == HAL_kInvalidHandle) {
+      return;
+    }
+    if ((i2CMXPDigitalHandle2 = HAL_InitializeDIOPort(
+             HAL_GetPort(25), false, status)) == HAL_kInvalidHandle) {
+      HAL_FreeDIOPort(i2CMXPDigitalHandle1);  // free the first port allocated
+      return;
+    }
+    digitalSystem->writeEnableMXPSpecialFunction(
+        digitalSystem->readEnableMXPSpecialFunction(status) | 0xC000, status);
+    int handle = open("/dev/i2c-1", O_RDWR);
+    if (handle < 0) {
+      std::printf("Failed to open MXP i2c bus: %s\n", std::strerror(errno));
+      return;
+    }
+    i2CMXPHandle = handle;
+  }
+}
+
+int32_t HAL_TransactionI2C(HAL_I2CPort port, int32_t deviceAddress,
+                           const uint8_t* dataToSend, int32_t sendSize,
+                           uint8_t* dataReceived, int32_t receiveSize) {
+  if (port < 0 || port > 1) {
+    // Set port out of range error here
+    return -1;
+  }
+
+  struct i2c_msg msgs[2];
+  msgs[0].addr = deviceAddress;
+  msgs[0].flags = 0;
+  msgs[0].len = sendSize;
+  msgs[0].buf = const_cast<uint8_t*>(dataToSend);
+  msgs[1].addr = deviceAddress;
+  msgs[1].flags = I2C_M_RD;
+  msgs[1].len = receiveSize;
+  msgs[1].buf = dataReceived;
+
+  struct i2c_rdwr_ioctl_data rdwr;
+  rdwr.msgs = msgs;
+  rdwr.nmsgs = 2;
+
+  if (port == HAL_I2C_kOnboard) {
+    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr);
+  } else {
+    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    return ioctl(i2CMXPHandle, I2C_RDWR, &rdwr);
+  }
+}
+
+int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress,
+                     const uint8_t* dataToSend, int32_t sendSize) {
+  if (port < 0 || port > 1) {
+    // Set port out of range error here
+    return -1;
+  }
+
+  struct i2c_msg msg;
+  msg.addr = deviceAddress;
+  msg.flags = 0;
+  msg.len = sendSize;
+  msg.buf = const_cast<uint8_t*>(dataToSend);
+
+  struct i2c_rdwr_ioctl_data rdwr;
+  rdwr.msgs = &msg;
+  rdwr.nmsgs = 1;
+
+  if (port == HAL_I2C_kOnboard) {
+    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr);
+  } else {
+    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    return ioctl(i2CMXPHandle, I2C_RDWR, &rdwr);
+  }
+}
+
+int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer,
+                    int32_t count) {
+  if (port < 0 || port > 1) {
+    // Set port out of range error here
+    return -1;
+  }
+
+  struct i2c_msg msg;
+  msg.addr = deviceAddress;
+  msg.flags = I2C_M_RD;
+  msg.len = count;
+  msg.buf = buffer;
+
+  struct i2c_rdwr_ioctl_data rdwr;
+  rdwr.msgs = &msg;
+  rdwr.nmsgs = 1;
+
+  if (port == HAL_I2C_kOnboard) {
+    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr);
+  } else {
+    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    return ioctl(i2CMXPHandle, I2C_RDWR, &rdwr);
+  }
+}
+
+void HAL_CloseI2C(HAL_I2CPort port) {
+  if (port < 0 || port > 1) {
+    // Set port out of range error here
+    return;
+  }
+
+  if (port == HAL_I2C_kOnboard) {
+    std::lock_guard<wpi::mutex> lock(digitalI2COnBoardMutex);
+    if (i2COnboardObjCount-- == 0) {
+      close(i2COnBoardHandle);
+    }
+  } else {
+    std::lock_guard<wpi::mutex> lock(digitalI2CMXPMutex);
+    if (i2CMXPObjCount-- == 0) {
+      close(i2CMXPHandle);
+    }
+    HAL_FreeDIOPort(i2CMXPDigitalHandle1);
+    HAL_FreeDIOPort(i2CMXPDigitalHandle2);
+  }
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/Interrupts.cpp b/hal/src/main/native/athena/Interrupts.cpp
new file mode 100644
index 0000000..c661da4
--- /dev/null
+++ b/hal/src/main/native/athena/Interrupts.cpp
@@ -0,0 +1,262 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Interrupts.h"
+
+#include <memory>
+
+#include <wpi/SafeThread.h>
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/ChipObject.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+// Safe thread to allow callbacks to run on their own thread
+class InterruptThread : 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;
+      HAL_InterruptHandlerFunction handler = m_handler;
+      uint32_t mask = m_mask;
+      void* param = m_param;
+      lock.unlock();  // don't hold mutex during callback execution
+      handler(mask, param);
+      lock.lock();
+    }
+  }
+
+  bool m_notify = false;
+  HAL_InterruptHandlerFunction m_handler;
+  void* m_param;
+  uint32_t m_mask;
+};
+
+class InterruptThreadOwner : public wpi::SafeThreadOwner<InterruptThread> {
+ public:
+  void SetFunc(HAL_InterruptHandlerFunction handler, void* param) {
+    auto thr = GetThread();
+    if (!thr) return;
+    thr->m_handler = handler;
+    thr->m_param = param;
+  }
+
+  void Notify(uint32_t mask) {
+    auto thr = GetThread();
+    if (!thr) return;
+    thr->m_mask = mask;
+    thr->m_notify = true;
+    thr->m_cond.notify_one();
+  }
+};
+
+}  // namespace
+
+static void threadedInterruptHandler(uint32_t mask, void* param) {
+  static_cast<InterruptThreadOwner*>(param)->Notify(mask);
+}
+
+struct Interrupt {
+  std::unique_ptr<tInterrupt> anInterrupt;
+  std::unique_ptr<tInterruptManager> manager;
+  std::unique_ptr<InterruptThreadOwner> threadOwner = nullptr;
+  void* param = nullptr;
+};
+
+static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+                             HAL_HandleEnum::Interrupt>* interruptHandles;
+
+namespace hal {
+namespace init {
+void InitialzeInterrupts() {
+  static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+                               HAL_HandleEnum::Interrupt>
+      iH;
+  interruptHandles = &iH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
+                                             int32_t* status) {
+  hal::init::CheckInit();
+  HAL_InterruptHandle handle = interruptHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto anInterrupt = interruptHandles->Get(handle);
+  uint32_t interruptIndex = static_cast<uint32_t>(getHandleIndex(handle));
+  // Expects the calling leaf class to allocate an interrupt index.
+  anInterrupt->anInterrupt.reset(tInterrupt::create(interruptIndex, status));
+  anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
+  anInterrupt->manager = std::make_unique<tInterruptManager>(
+      (1u << interruptIndex) | (1u << (interruptIndex + 8u)), watcher, status);
+  return handle;
+}
+
+void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
+                          int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  interruptHandles->Free(interruptHandle);
+  if (anInterrupt == nullptr) {
+    return nullptr;
+  }
+  anInterrupt->manager->enable(status);
+  void* param = anInterrupt->param;
+  return param;
+}
+
+int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
+                             double timeout, HAL_Bool ignorePrevious,
+                             int32_t* status) {
+  uint32_t result;
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  result = anInterrupt->manager->watch(static_cast<int32_t>(timeout * 1e3),
+                                       ignorePrevious, status);
+
+  // Don't report a timeout as an error - the return code is enough to tell
+  // that a timeout happened.
+  if (*status == -NiFpga_Status_IrqTimeout) {
+    *status = NiFpga_Status_Success;
+  }
+
+  return result;
+}
+
+void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
+                          int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  anInterrupt->manager->enable(status);
+}
+
+void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
+                           int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  anInterrupt->manager->disable(status);
+}
+
+int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
+                                         int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  uint32_t timestamp = anInterrupt->anInterrupt->readRisingTimeStamp(status);
+  return timestamp;
+}
+
+int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
+                                          int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  uint32_t timestamp = anInterrupt->anInterrupt->readFallingTimeStamp(status);
+  return timestamp;
+}
+
+void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
+                           HAL_Handle digitalSourceHandle,
+                           HAL_AnalogTriggerType analogTriggerType,
+                           int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
+  bool routingAnalogTrigger = false;
+  uint8_t routingChannel = 0;
+  uint8_t routingModule = 0;
+  bool success =
+      remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
+                         routingModule, routingAnalogTrigger);
+  if (!success) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  anInterrupt->anInterrupt->writeConfig_Source_AnalogTrigger(
+      routingAnalogTrigger, status);
+  anInterrupt->anInterrupt->writeConfig_Source_Channel(routingChannel, status);
+  anInterrupt->anInterrupt->writeConfig_Source_Module(routingModule, status);
+}
+
+void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
+                                HAL_InterruptHandlerFunction handler,
+                                void* param, int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  anInterrupt->manager->registerHandler(handler, param, status);
+  anInterrupt->param = param;
+}
+
+void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interrupt_handle,
+                                        HAL_InterruptHandlerFunction handler,
+                                        void* param, int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interrupt_handle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  anInterrupt->threadOwner = std::make_unique<InterruptThreadOwner>();
+  anInterrupt->threadOwner->Start();
+  anInterrupt->threadOwner->SetFunc(handler, param);
+
+  HAL_AttachInterruptHandler(interrupt_handle, threadedInterruptHandler,
+                             anInterrupt->threadOwner.get(), status);
+
+  if (*status != 0) {
+    anInterrupt->threadOwner = nullptr;
+  }
+  anInterrupt->param = param;
+}
+
+void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
+                                  HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                  int32_t* status) {
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  if (anInterrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  anInterrupt->anInterrupt->writeConfig_RisingEdge(risingEdge, status);
+  anInterrupt->anInterrupt->writeConfig_FallingEdge(fallingEdge, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/Notifier.cpp b/hal/src/main/native/athena/Notifier.cpp
new file mode 100644
index 0000000..c457cd1
--- /dev/null
+++ b/hal/src/main/native/athena/Notifier.cpp
@@ -0,0 +1,233 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Notifier.h"
+
+#include <atomic>
+#include <cstdlib>  // For std::atexit()
+#include <memory>
+
+#include <wpi/condition_variable.h>
+#include <wpi/mutex.h>
+
+#include "HALInitializer.h"
+#include "hal/ChipObject.h"
+#include "hal/Errors.h"
+#include "hal/HAL.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+
+using namespace hal;
+
+static constexpr int32_t kTimerInterruptNumber = 28;
+
+static wpi::mutex notifierMutex;
+static std::unique_ptr<tAlarm> notifierAlarm;
+static std::unique_ptr<tInterruptManager> notifierManager;
+static uint64_t closestTrigger{UINT64_MAX};
+
+namespace {
+
+struct Notifier {
+  uint64_t triggerTime = UINT64_MAX;
+  uint64_t triggeredTime = UINT64_MAX;
+  bool active = true;
+  wpi::mutex mutex;
+  wpi::condition_variable cond;
+};
+
+}  // namespace
+
+static std::atomic_flag notifierAtexitRegistered{ATOMIC_FLAG_INIT};
+static std::atomic_int notifierRefCount{0};
+
+using namespace hal;
+
+class NotifierHandleContainer
+    : public UnlimitedHandleResource<HAL_NotifierHandle, Notifier,
+                                     HAL_HandleEnum::Notifier> {
+ public:
+  ~NotifierHandleContainer() {
+    ForEach([](HAL_NotifierHandle handle, Notifier* notifier) {
+      {
+        std::lock_guard<wpi::mutex> lock(notifier->mutex);
+        notifier->triggerTime = UINT64_MAX;
+        notifier->triggeredTime = 0;
+        notifier->active = false;
+      }
+      notifier->cond.notify_all();  // wake up any waiting threads
+    });
+  }
+};
+
+static NotifierHandleContainer* notifierHandles;
+
+static void alarmCallback(uint32_t, void*) {
+  std::lock_guard<wpi::mutex> lock(notifierMutex);
+  int32_t status = 0;
+  uint64_t currentTime = 0;
+
+  // the hardware disables itself after each alarm
+  closestTrigger = UINT64_MAX;
+
+  // process all notifiers
+  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);
+    if (notifier->triggerTime < currentTime) {
+      notifier->triggerTime = UINT64_MAX;
+      notifier->triggeredTime = currentTime;
+      lock.unlock();
+      notifier->cond.notify_all();
+    } else if (notifier->triggerTime < closestTrigger) {
+      closestTrigger = notifier->triggerTime;
+    }
+  });
+
+  if (notifierAlarm && closestTrigger != UINT64_MAX) {
+    // Simply truncate the hardware trigger time to 32-bit.
+    notifierAlarm->writeTriggerTime(static_cast<uint32_t>(closestTrigger),
+                                    &status);
+    // Enable the alarm.  The hardware disables itself after each alarm.
+    notifierAlarm->writeEnable(true, &status);
+  }
+}
+
+static void cleanupNotifierAtExit() {
+  notifierAlarm = nullptr;
+  notifierManager = nullptr;
+}
+
+namespace hal {
+namespace init {
+void InitializeNotifier() {
+  static NotifierHandleContainer nH;
+  notifierHandles = &nH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_NotifierHandle HAL_InitializeNotifier(int32_t* status) {
+  hal::init::CheckInit();
+  if (!notifierAtexitRegistered.test_and_set())
+    std::atexit(cleanupNotifierAtExit);
+
+  if (notifierRefCount.fetch_add(1) == 0) {
+    std::lock_guard<wpi::mutex> lock(notifierMutex);
+    // create manager and alarm if not already created
+    if (!notifierManager) {
+      notifierManager = std::make_unique<tInterruptManager>(
+          1 << kTimerInterruptNumber, false, status);
+      notifierManager->registerHandler(alarmCallback, nullptr, status);
+      notifierManager->enable(status);
+    }
+    if (!notifierAlarm) notifierAlarm.reset(tAlarm::create(status));
+  }
+
+  std::shared_ptr<Notifier> notifier = std::make_shared<Notifier>();
+  HAL_NotifierHandle handle = notifierHandles->Allocate(notifier);
+  if (handle == HAL_kInvalidHandle) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  return handle;
+}
+
+void HAL_StopNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return;
+
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->triggerTime = UINT64_MAX;
+    notifier->triggeredTime = 0;
+    notifier->active = false;
+  }
+  notifier->cond.notify_all();  // wake up any waiting threads
+}
+
+void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) {
+  auto notifier = notifierHandles->Free(notifierHandle);
+  if (!notifier) return;
+
+  // Just in case HAL_StopNotifier() wasn't called...
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->triggerTime = UINT64_MAX;
+    notifier->triggeredTime = 0;
+    notifier->active = false;
+  }
+  notifier->cond.notify_all();
+
+  if (notifierRefCount.fetch_sub(1) == 1) {
+    // if this was the last notifier, clean up alarm and manager
+    // the notifier can call back into our callback, so don't hold the lock
+    // here (the atomic fetch_sub will prevent multiple parallel entries
+    // into this function)
+
+    // Cleaning up the manager takes up to a second to complete, so don't do
+    // that here. Fix it more permanently in 2019...
+
+    // if (notifierAlarm) notifierAlarm->writeEnable(false, status);
+    // if (notifierManager) notifierManager->disable(status);
+
+    // std::lock_guard<wpi::mutex> lock(notifierMutex);
+    // notifierAlarm = nullptr;
+    // notifierManager = nullptr;
+    // closestTrigger = UINT64_MAX;
+  }
+}
+
+void HAL_UpdateNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                             uint64_t triggerTime, int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return;
+
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->triggerTime = triggerTime;
+    notifier->triggeredTime = UINT64_MAX;
+  }
+
+  std::lock_guard<wpi::mutex> lock(notifierMutex);
+  // Update alarm time if closer than current.
+  if (triggerTime < closestTrigger) {
+    bool wasActive = (closestTrigger != UINT64_MAX);
+    closestTrigger = triggerTime;
+    // Simply truncate the hardware trigger time to 32-bit.
+    notifierAlarm->writeTriggerTime(static_cast<uint32_t>(closestTrigger),
+                                    status);
+    // Enable the alarm.
+    if (!wasActive) notifierAlarm->writeEnable(true, status);
+  }
+}
+
+void HAL_CancelNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                             int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return;
+
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->triggerTime = UINT64_MAX;
+  }
+}
+
+uint64_t HAL_WaitForNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                                  int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return 0;
+  std::unique_lock<wpi::mutex> lock(notifier->mutex);
+  notifier->cond.wait(lock, [&] {
+    return !notifier->active || notifier->triggeredTime != UINT64_MAX;
+  });
+  return notifier->active ? notifier->triggeredTime : 0;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/PCMInternal.cpp b/hal/src/main/native/athena/PCMInternal.cpp
new file mode 100644
index 0000000..dee64cf
--- /dev/null
+++ b/hal/src/main/native/athena/PCMInternal.cpp
@@ -0,0 +1,38 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "PCMInternal.h"
+
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/Errors.h"
+#include "hal/Solenoid.h"
+
+namespace hal {
+
+std::unique_ptr<PCM> PCM_modules[kNumPCMModules];
+
+namespace init {
+void InitializePCMInternal() {
+  for (int i = 0; i < kNumPCMModules; i++) {
+    PCM_modules[i] = nullptr;
+  }
+}
+}  // namespace init
+
+void initializePCM(int32_t module, int32_t* status) {
+  hal::init::CheckInit();
+  if (!HAL_CheckSolenoidModule(module)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return;
+  }
+  if (!PCM_modules[module]) {
+    PCM_modules[module] = std::make_unique<PCM>(module);
+  }
+}
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/PCMInternal.h b/hal/src/main/native/athena/PCMInternal.h
new file mode 100644
index 0000000..52f0f75
--- /dev/null
+++ b/hal/src/main/native/athena/PCMInternal.h
@@ -0,0 +1,38 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <memory>
+
+#include "PortsInternal.h"
+#include "ctre/PCM.h"
+#include "hal/Errors.h"
+#include "hal/Ports.h"
+#include "hal/Solenoid.h"
+
+namespace hal {
+
+extern std::unique_ptr<PCM> PCM_modules[kNumPCMModules];
+
+static inline bool checkPCMInit(int32_t module, int32_t* status) {
+  if (!HAL_CheckSolenoidModule(module)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return false;
+  }
+  if (!PCM_modules[module]) {
+    *status = INCOMPATIBLE_STATE;
+    return false;
+  }
+  return true;
+}
+
+void initializePCM(int32_t module, int32_t* status);
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/PDP.cpp b/hal/src/main/native/athena/PDP.cpp
new file mode 100644
index 0000000..ff1eb81
--- /dev/null
+++ b/hal/src/main/native/athena/PDP.cpp
@@ -0,0 +1,341 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/PDP.h"
+
+#include <memory>
+
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/CANAPI.h"
+#include "hal/Errors.h"
+#include "hal/Ports.h"
+#include "hal/handles/IndexedHandleResource.h"
+
+using namespace hal;
+
+static constexpr HAL_CANManufacturer manufacturer =
+    HAL_CANManufacturer::HAL_CAN_Man_kCTRE;
+
+static constexpr HAL_CANDeviceType deviceType =
+    HAL_CANDeviceType::HAL_CAN_Dev_kPowerDistribution;
+
+static constexpr int32_t Status1 = 0x50;
+static constexpr int32_t Status2 = 0x51;
+static constexpr int32_t Status3 = 0x52;
+static constexpr int32_t StatusEnergy = 0x5D;
+
+static constexpr int32_t Control1 = 0x70;
+
+static constexpr int32_t TimeoutMs = 100;
+static constexpr int32_t StatusPeriodMs = 25;
+
+/* encoder/decoders */
+union PdpStatus1 {
+  uint8_t data[8];
+  struct Bits {
+    unsigned chan1_h8 : 8;
+    unsigned chan2_h6 : 6;
+    unsigned chan1_l2 : 2;
+    unsigned chan3_h4 : 4;
+    unsigned chan2_l4 : 4;
+    unsigned chan4_h2 : 2;
+    unsigned chan3_l6 : 6;
+    unsigned chan4_l8 : 8;
+    unsigned chan5_h8 : 8;
+    unsigned chan6_h6 : 6;
+    unsigned chan5_l2 : 2;
+    unsigned reserved4 : 4;
+    unsigned chan6_l4 : 4;
+  } bits;
+};
+
+union PdpStatus2 {
+  uint8_t data[8];
+  struct Bits {
+    unsigned chan7_h8 : 8;
+    unsigned chan8_h6 : 6;
+    unsigned chan7_l2 : 2;
+    unsigned chan9_h4 : 4;
+    unsigned chan8_l4 : 4;
+    unsigned chan10_h2 : 2;
+    unsigned chan9_l6 : 6;
+    unsigned chan10_l8 : 8;
+    unsigned chan11_h8 : 8;
+    unsigned chan12_h6 : 6;
+    unsigned chan11_l2 : 2;
+    unsigned reserved4 : 4;
+    unsigned chan12_l4 : 4;
+  } bits;
+};
+
+union PdpStatus3 {
+  uint8_t data[8];
+  struct Bits {
+    unsigned chan13_h8 : 8;
+    unsigned chan14_h6 : 6;
+    unsigned chan13_l2 : 2;
+    unsigned chan15_h4 : 4;
+    unsigned chan14_l4 : 4;
+    unsigned chan16_h2 : 2;
+    unsigned chan15_l6 : 6;
+    unsigned chan16_l8 : 8;
+    unsigned internalResBattery_mOhms : 8;
+    unsigned busVoltage : 8;
+    unsigned temp : 8;
+  } bits;
+};
+
+union PdpStatusEnergy {
+  uint8_t data[8];
+  struct Bits {
+    unsigned TmeasMs_likelywillbe20ms_ : 8;
+    unsigned TotalCurrent_125mAperunit_h8 : 8;
+    unsigned Power_125mWperunit_h4 : 4;
+    unsigned TotalCurrent_125mAperunit_l4 : 4;
+    unsigned Power_125mWperunit_m8 : 8;
+    unsigned Energy_125mWPerUnitXTmeas_h4 : 4;
+    unsigned Power_125mWperunit_l4 : 4;
+    unsigned Energy_125mWPerUnitXTmeas_mh8 : 8;
+    unsigned Energy_125mWPerUnitXTmeas_ml8 : 8;
+    unsigned Energy_125mWPerUnitXTmeas_l8 : 8;
+  } bits;
+};
+
+namespace hal {
+namespace init {
+void InitializePDP() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status) {
+  hal::init::CheckInit();
+  if (!HAL_CheckPDPModule(module)) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
+
+  if (*status != 0) {
+    HAL_CleanCAN(handle);
+    return HAL_kInvalidHandle;
+  }
+
+  return handle;
+}
+
+void HAL_CleanPDP(HAL_PDPHandle handle) { HAL_CleanCAN(handle); }
+
+HAL_Bool HAL_CheckPDPModule(int32_t module) {
+  return module < kNumPDPModules && module >= 0;
+}
+
+HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
+  return channel < kNumPDPChannels && channel >= 0;
+}
+
+double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
+  PdpStatus3 pdpStatus;
+  int32_t length = 0;
+  uint64_t receivedTimestamp = 0;
+
+  HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
+                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                            status);
+
+  return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
+}
+
+double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
+  PdpStatus3 pdpStatus;
+  int32_t length = 0;
+  uint64_t receivedTimestamp = 0;
+
+  HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
+                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                            status);
+
+  return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
+}
+
+double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
+                                int32_t* status) {
+  if (!HAL_CheckPDPChannel(channel)) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return 0;
+  }
+
+  int32_t length = 0;
+  uint64_t receivedTimestamp = 0;
+
+  double raw = 0;
+
+  if (channel <= 5) {
+    PdpStatus1 pdpStatus;
+    HAL_ReadCANPeriodicPacket(handle, Status1, pdpStatus.data, &length,
+                              &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                              status);
+    switch (channel) {
+      case 0:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
+              pdpStatus.bits.chan1_l2;
+        break;
+      case 1:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan2_h6) << 4) |
+              pdpStatus.bits.chan2_l4;
+        break;
+      case 2:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan3_h4) << 6) |
+              pdpStatus.bits.chan3_l6;
+        break;
+      case 3:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan4_h2) << 8) |
+              pdpStatus.bits.chan4_l8;
+        break;
+      case 4:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan5_h8) << 2) |
+              pdpStatus.bits.chan5_l2;
+        break;
+      case 5:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan6_h6) << 4) |
+              pdpStatus.bits.chan6_l4;
+        break;
+    }
+  } else if (channel <= 11) {
+    PdpStatus2 pdpStatus;
+    HAL_ReadCANPeriodicPacket(handle, Status2, pdpStatus.data, &length,
+                              &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                              status);
+    switch (channel) {
+      case 6:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
+              pdpStatus.bits.chan7_l2;
+        break;
+      case 7:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan8_h6) << 4) |
+              pdpStatus.bits.chan8_l4;
+        break;
+      case 8:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan9_h4) << 6) |
+              pdpStatus.bits.chan9_l6;
+        break;
+      case 9:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan10_h2) << 8) |
+              pdpStatus.bits.chan10_l8;
+        break;
+      case 10:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan11_h8) << 2) |
+              pdpStatus.bits.chan11_l2;
+        break;
+      case 11:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan12_h6) << 4) |
+              pdpStatus.bits.chan12_l4;
+        break;
+    }
+  } else {
+    PdpStatus3 pdpStatus;
+    HAL_ReadCANPeriodicPacket(handle, Status3, pdpStatus.data, &length,
+                              &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                              status);
+    switch (channel) {
+      case 12:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |
+              pdpStatus.bits.chan13_l2;
+        break;
+      case 13:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan14_h6) << 4) |
+              pdpStatus.bits.chan14_l4;
+        break;
+      case 14:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan15_h4) << 6) |
+              pdpStatus.bits.chan15_l6;
+        break;
+      case 15:
+        raw = (static_cast<uint32_t>(pdpStatus.bits.chan16_h2) << 8) |
+              pdpStatus.bits.chan16_l8;
+        break;
+    }
+  }
+
+  /* convert to amps */
+  return raw * 0.125; /* 7.3 fixed pt value in Amps */
+}
+
+double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
+  PdpStatusEnergy pdpStatus;
+  int32_t length = 0;
+  uint64_t receivedTimestamp = 0;
+
+  HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
+                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                            status);
+
+  uint32_t raw;
+  raw = pdpStatus.bits.TotalCurrent_125mAperunit_h8;
+  raw <<= 4;
+  raw |= pdpStatus.bits.TotalCurrent_125mAperunit_l4;
+  return 0.125 * raw; /* 7.3 fixed pt value in Amps */
+}
+
+double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
+  PdpStatusEnergy pdpStatus;
+  int32_t length = 0;
+  uint64_t receivedTimestamp = 0;
+
+  HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
+                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                            status);
+
+  uint32_t raw;
+  raw = pdpStatus.bits.Power_125mWperunit_h4;
+  raw <<= 8;
+  raw |= pdpStatus.bits.Power_125mWperunit_m8;
+  raw <<= 4;
+  raw |= pdpStatus.bits.Power_125mWperunit_l4;
+  return 0.125 * raw; /* 7.3 fixed pt value in Watts */
+}
+
+double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
+  PdpStatusEnergy pdpStatus;
+  int32_t length = 0;
+  uint64_t receivedTimestamp = 0;
+
+  HAL_ReadCANPeriodicPacket(handle, StatusEnergy, pdpStatus.data, &length,
+                            &receivedTimestamp, TimeoutMs, StatusPeriodMs,
+                            status);
+
+  uint32_t raw;
+  raw = pdpStatus.bits.Energy_125mWPerUnitXTmeas_h4;
+  raw <<= 8;
+  raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_mh8;
+  raw <<= 8;
+  raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_ml8;
+  raw <<= 8;
+  raw |= pdpStatus.bits.Energy_125mWPerUnitXTmeas_l8;
+
+  double energyJoules = 0.125 * raw; /* mW integrated every TmeasMs */
+  energyJoules *= 0.001;             /* convert from mW to W */
+  energyJoules *=
+      pdpStatus.bits
+          .TmeasMs_likelywillbe20ms_; /* multiplied by TmeasMs = joules */
+  return 0.125 * raw;
+}
+
+void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
+  uint8_t pdpControl[] = {0x40}; /* only bit set is ResetEnergy */
+  HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
+}
+
+void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {
+  uint8_t pdpControl[] = {0x80}; /* only bit set is ClearStickyFaults */
+  HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/PWM.cpp b/hal/src/main/native/athena/PWM.cpp
new file mode 100644
index 0000000..06b527c
--- /dev/null
+++ b/hal/src/main/native/athena/PWM.cpp
@@ -0,0 +1,458 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/PWM.h"
+
+#include <cmath>
+#include <thread>
+
+#include <wpi/raw_ostream.h>
+
+#include "ConstantsInternal.h"
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/cpp/fpga_clock.h"
+#include "hal/handles/HandlesInternal.h"
+
+using namespace hal;
+
+static inline int32_t GetMaxPositivePwm(DigitalPort* port) {
+  return port->maxPwm;
+}
+
+static inline int32_t GetMinPositivePwm(DigitalPort* port) {
+  if (port->eliminateDeadband) {
+    return port->deadbandMaxPwm;
+  } else {
+    return port->centerPwm + 1;
+  }
+}
+
+static inline int32_t GetCenterPwm(DigitalPort* port) {
+  return port->centerPwm;
+}
+
+static inline int32_t GetMaxNegativePwm(DigitalPort* port) {
+  if (port->eliminateDeadband) {
+    return port->deadbandMinPwm;
+  } else {
+    return port->centerPwm - 1;
+  }
+}
+
+static inline int32_t GetMinNegativePwm(DigitalPort* port) {
+  return port->minPwm;
+}
+
+static inline int32_t GetPositiveScaleFactor(DigitalPort* port) {
+  return GetMaxPositivePwm(port) - GetMinPositivePwm(port);
+}  ///< The scale for positive speeds.
+
+static inline int32_t GetNegativeScaleFactor(DigitalPort* port) {
+  return GetMaxNegativePwm(port) - GetMinNegativePwm(port);
+}  ///< The scale for negative speeds.
+
+static inline int32_t GetFullRangeScaleFactor(DigitalPort* port) {
+  return GetMaxPositivePwm(port) - GetMinNegativePwm(port);
+}  ///< The scale for positions.
+
+namespace hal {
+namespace init {
+void InitializePWM() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  initializeDigital(status);
+
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex || channel >= kNumPWMChannels) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  uint8_t origChannel = static_cast<uint8_t>(channel);
+
+  if (origChannel < kNumPWMHeaders) {
+    channel += kNumDigitalChannels;  // remap Headers to end of allocations
+  } else {
+    channel = remapMXPPWMChannel(channel) + 10;  // remap MXP to proper channel
+  }
+
+  auto handle =
+      digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  port->channel = origChannel;
+
+  if (port->channel > tPWM::kNumHdrRegisters - 1) {
+    int32_t bitToSet = 1 << remapMXPPWMChannel(port->channel);
+    uint16_t specialFunctions =
+        digitalSystem->readEnableMXPSpecialFunction(status);
+    digitalSystem->writeEnableMXPSpecialFunction(specialFunctions | bitToSet,
+                                                 status);
+  }
+
+  // Defaults to allow an always valid config.
+  HAL_SetPWMConfig(handle, 2.0, 1.501, 1.5, 1.499, 1.0, status);
+
+  return handle;
+}
+void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  digitalChannelHandles->Free(pwmPortHandle, HAL_HandleEnum::PWM);
+
+  // Wait for no other object to hold this handle.
+  auto start = hal::fpga_clock::now();
+  while (port.use_count() != 1) {
+    auto current = hal::fpga_clock::now();
+    if (start + std::chrono::seconds(1) < current) {
+      wpi::outs() << "PWM handle free timeout\n";
+      wpi::outs().flush();
+      break;
+    }
+    std::this_thread::yield();
+  }
+
+  if (port->channel > tPWM::kNumHdrRegisters - 1) {
+    int32_t bitToUnset = 1 << remapMXPPWMChannel(port->channel);
+    uint16_t specialFunctions =
+        digitalSystem->readEnableMXPSpecialFunction(status);
+    digitalSystem->writeEnableMXPSpecialFunction(specialFunctions & ~bitToUnset,
+                                                 status);
+  }
+}
+
+HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
+  return channel < kNumPWMChannels && channel >= 0;
+}
+
+void HAL_SetPWMConfig(HAL_DigitalHandle pwmPortHandle, double max,
+                      double deadbandMax, double center, double deadbandMin,
+                      double min, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // calculate the loop time in milliseconds
+  double loopTime =
+      HAL_GetPWMLoopTiming(status) / (kSystemClockTicksPerMicrosecond * 1e3);
+  if (*status != 0) return;
+
+  int32_t maxPwm = static_cast<int32_t>((max - kDefaultPwmCenter) / loopTime +
+                                        kDefaultPwmStepsDown - 1);
+  int32_t deadbandMaxPwm = static_cast<int32_t>(
+      (deadbandMax - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
+  int32_t centerPwm = static_cast<int32_t>(
+      (center - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
+  int32_t deadbandMinPwm = static_cast<int32_t>(
+      (deadbandMin - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
+  int32_t minPwm = static_cast<int32_t>((min - kDefaultPwmCenter) / loopTime +
+                                        kDefaultPwmStepsDown - 1);
+
+  port->maxPwm = maxPwm;
+  port->deadbandMaxPwm = deadbandMaxPwm;
+  port->deadbandMinPwm = deadbandMinPwm;
+  port->centerPwm = centerPwm;
+  port->minPwm = minPwm;
+  port->configSet = true;
+}
+
+void HAL_SetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t maxPwm,
+                         int32_t deadbandMaxPwm, int32_t centerPwm,
+                         int32_t deadbandMinPwm, int32_t minPwm,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  port->maxPwm = maxPwm;
+  port->deadbandMaxPwm = deadbandMaxPwm;
+  port->deadbandMinPwm = deadbandMinPwm;
+  port->centerPwm = centerPwm;
+  port->minPwm = minPwm;
+}
+
+void HAL_GetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t* maxPwm,
+                         int32_t* deadbandMaxPwm, int32_t* centerPwm,
+                         int32_t* deadbandMinPwm, int32_t* minPwm,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  *maxPwm = port->maxPwm;
+  *deadbandMaxPwm = port->deadbandMaxPwm;
+  *deadbandMinPwm = port->deadbandMinPwm;
+  *centerPwm = port->centerPwm;
+  *minPwm = port->minPwm;
+}
+
+void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
+                                 HAL_Bool eliminateDeadband, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  port->eliminateDeadband = eliminateDeadband;
+}
+
+HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
+                                     int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return port->eliminateDeadband;
+}
+
+void HAL_SetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t value,
+                   int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (port->channel < tPWM::kNumHdrRegisters) {
+    pwmSystem->writeHdr(port->channel, value, status);
+  } else {
+    pwmSystem->writeMXP(port->channel - tPWM::kNumHdrRegisters, value, status);
+  }
+}
+
+void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
+                     int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  DigitalPort* dPort = port.get();
+
+  if (speed < -1.0) {
+    speed = -1.0;
+  } else if (speed > 1.0) {
+    speed = 1.0;
+  } else if (!std::isfinite(speed)) {
+    speed = 0.0;
+  }
+
+  // calculate the desired output pwm value by scaling the speed appropriately
+  int32_t rawValue;
+  if (speed == 0.0) {
+    rawValue = GetCenterPwm(dPort);
+  } else if (speed > 0.0) {
+    rawValue = static_cast<int32_t>(
+        speed * static_cast<double>(GetPositiveScaleFactor(dPort)) +
+        static_cast<double>(GetMinPositivePwm(dPort)) + 0.5);
+  } else {
+    rawValue = static_cast<int32_t>(
+        speed * static_cast<double>(GetNegativeScaleFactor(dPort)) +
+        static_cast<double>(GetMaxNegativePwm(dPort)) + 0.5);
+  }
+
+  if (!((rawValue >= GetMinNegativePwm(dPort)) &&
+        (rawValue <= GetMaxPositivePwm(dPort))) ||
+      rawValue == kPwmDisabled) {
+    *status = HAL_PWM_SCALE_ERROR;
+    return;
+  }
+
+  HAL_SetPWMRaw(pwmPortHandle, rawValue, status);
+}
+
+void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
+                        int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+  DigitalPort* dPort = port.get();
+
+  if (pos < 0.0) {
+    pos = 0.0;
+  } else if (pos > 1.0) {
+    pos = 1.0;
+  }
+
+  // note, need to perform the multiplication below as floating point before
+  // converting to int
+  int32_t rawValue = static_cast<int32_t>(
+      (pos * static_cast<double>(GetFullRangeScaleFactor(dPort))) +
+      GetMinNegativePwm(dPort));
+
+  if (rawValue == kPwmDisabled) {
+    *status = HAL_PWM_SCALE_ERROR;
+    return;
+  }
+
+  HAL_SetPWMRaw(pwmPortHandle, rawValue, status);
+}
+
+void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  HAL_SetPWMRaw(pwmPortHandle, kPwmDisabled, status);
+}
+
+int32_t HAL_GetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  if (port->channel < tPWM::kNumHdrRegisters) {
+    return pwmSystem->readHdr(port->channel, status);
+  } else {
+    return pwmSystem->readMXP(port->channel - tPWM::kNumHdrRegisters, status);
+  }
+}
+
+double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return 0;
+  }
+
+  int32_t value = HAL_GetPWMRaw(pwmPortHandle, status);
+  if (*status != 0) return 0;
+  DigitalPort* dPort = port.get();
+
+  if (value == kPwmDisabled) {
+    return 0.0;
+  } else if (value > GetMaxPositivePwm(dPort)) {
+    return 1.0;
+  } else if (value < GetMinNegativePwm(dPort)) {
+    return -1.0;
+  } else if (value > GetMinPositivePwm(dPort)) {
+    return static_cast<double>(value - GetMinPositivePwm(dPort)) /
+           static_cast<double>(GetPositiveScaleFactor(dPort));
+  } else if (value < GetMaxNegativePwm(dPort)) {
+    return static_cast<double>(value - GetMaxNegativePwm(dPort)) /
+           static_cast<double>(GetNegativeScaleFactor(dPort));
+  } else {
+    return 0.0;
+  }
+}
+
+double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return 0;
+  }
+
+  int32_t value = HAL_GetPWMRaw(pwmPortHandle, status);
+  if (*status != 0) return 0;
+  DigitalPort* dPort = port.get();
+
+  if (value < GetMinNegativePwm(dPort)) {
+    return 0.0;
+  } else if (value > GetMaxPositivePwm(dPort)) {
+    return 1.0;
+  } else {
+    return static_cast<double>(value - GetMinNegativePwm(dPort)) /
+           static_cast<double>(GetFullRangeScaleFactor(dPort));
+  }
+}
+
+void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  pwmSystem->writeZeroLatch(port->channel, true, status);
+  pwmSystem->writeZeroLatch(port->channel, false, status);
+}
+
+void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
+                           int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (port->channel < tPWM::kNumPeriodScaleHdrElements) {
+    pwmSystem->writePeriodScaleHdr(port->channel, squelchMask, status);
+  } else {
+    pwmSystem->writePeriodScaleMXP(
+        port->channel - tPWM::kNumPeriodScaleHdrElements, squelchMask, status);
+  }
+}
+
+int32_t HAL_GetPWMLoopTiming(int32_t* status) {
+  initializeDigital(status);
+  if (*status != 0) return 0;
+  return pwmSystem->readLoopTiming(status);
+}
+
+uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
+  initializeDigital(status);
+  if (*status != 0) return 0;
+
+  uint64_t upper1 = pwmSystem->readCycleStartTimeUpper(status);
+  uint32_t lower = pwmSystem->readCycleStartTime(status);
+  uint64_t upper2 = pwmSystem->readCycleStartTimeUpper(status);
+  if (*status != 0) return 0;
+  if (upper1 != upper2) {
+    // Rolled over between the lower call, reread lower
+    lower = pwmSystem->readCycleStartTime(status);
+    if (*status != 0) return 0;
+  }
+  return (upper2 << 32) + lower;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/Ports.cpp b/hal/src/main/native/athena/Ports.cpp
new file mode 100644
index 0000000..9a52736
--- /dev/null
+++ b/hal/src/main/native/athena/Ports.cpp
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Ports.h"
+
+#include "PortsInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializePorts() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+int32_t HAL_GetNumAccumulators(void) { return kNumAccumulators; }
+int32_t HAL_GetNumAnalogTriggers(void) { return kNumAnalogTriggers; }
+int32_t HAL_GetNumAnalogInputs(void) { return kNumAnalogInputs; }
+int32_t HAL_GetNumAnalogOutputs(void) { return kNumAnalogOutputs; }
+int32_t HAL_GetNumCounters(void) { return kNumCounters; }
+int32_t HAL_GetNumDigitalHeaders(void) { return kNumDigitalHeaders; }
+int32_t HAL_GetNumPWMHeaders(void) { return kNumPWMHeaders; }
+int32_t HAL_GetNumDigitalChannels(void) { return kNumDigitalChannels; }
+int32_t HAL_GetNumPWMChannels(void) { return kNumPWMChannels; }
+int32_t HAL_GetNumDigitalPWMOutputs(void) { return kNumDigitalPWMOutputs; }
+int32_t HAL_GetNumEncoders(void) { return kNumEncoders; }
+int32_t HAL_GetNumInterrupts(void) { return kNumInterrupts; }
+int32_t HAL_GetNumRelayChannels(void) { return kNumRelayChannels; }
+int32_t HAL_GetNumRelayHeaders(void) { return kNumRelayHeaders; }
+int32_t HAL_GetNumPCMModules(void) { return kNumPCMModules; }
+int32_t HAL_GetNumSolenoidChannels(void) { return kNumSolenoidChannels; }
+int32_t HAL_GetNumPDPModules(void) { return kNumPDPModules; }
+int32_t HAL_GetNumPDPChannels(void) { return kNumPDPChannels; }
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/PortsInternal.h b/hal/src/main/native/athena/PortsInternal.h
new file mode 100644
index 0000000..b3eb6b0
--- /dev/null
+++ b/hal/src/main/native/athena/PortsInternal.h
@@ -0,0 +1,39 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/ChipObject.h"
+
+namespace hal {
+
+constexpr int32_t kNumAccumulators = tAccumulator::kNumSystems;
+constexpr int32_t kNumAnalogTriggers = tAnalogTrigger::kNumSystems;
+constexpr int32_t kNumAnalogInputs = 8;
+constexpr int32_t kNumAnalogOutputs = tAO::kNumMXPRegisters;
+constexpr int32_t kNumCounters = tCounter::kNumSystems;
+constexpr int32_t kNumDigitalHeaders = 10;
+constexpr int32_t kNumDigitalMXPChannels = 16;
+constexpr int32_t kNumDigitalSPIPortChannels = 5;
+constexpr int32_t kNumPWMHeaders = tPWM::kNumHdrRegisters;
+constexpr int32_t kNumDigitalChannels =
+    kNumDigitalHeaders + kNumDigitalMXPChannels + kNumDigitalSPIPortChannels;
+constexpr int32_t kNumPWMChannels = tPWM::kNumMXPRegisters + kNumPWMHeaders;
+constexpr int32_t kNumDigitalPWMOutputs =
+    tDIO::kNumPWMDutyCycleAElements + tDIO::kNumPWMDutyCycleBElements;
+constexpr int32_t kNumEncoders = tEncoder::kNumSystems;
+constexpr int32_t kNumInterrupts = tInterrupt::kNumSystems;
+constexpr int32_t kNumRelayChannels = 8;
+constexpr int32_t kNumRelayHeaders = kNumRelayChannels / 2;
+constexpr int32_t kNumPCMModules = 63;
+constexpr int32_t kNumSolenoidChannels = 8;
+constexpr int32_t kNumPDPModules = 63;
+constexpr int32_t kNumPDPChannels = 16;
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/Power.cpp b/hal/src/main/native/athena/Power.cpp
new file mode 100644
index 0000000..2cf4d33
--- /dev/null
+++ b/hal/src/main/native/athena/Power.cpp
@@ -0,0 +1,111 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Power.h"
+
+#include <memory>
+
+#include "HALInitializer.h"
+#include "hal/ChipObject.h"
+
+using namespace hal;
+
+namespace hal {
+
+static std::unique_ptr<tPower> power{nullptr};
+
+static void initializePower(int32_t* status) {
+  hal::init::CheckInit();
+  if (power == nullptr) {
+    power.reset(tPower::create(status));
+  }
+}
+
+}  // namespace hal
+
+namespace hal {
+namespace init {
+void InitializePower() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+double HAL_GetVinVoltage(int32_t* status) {
+  initializePower(status);
+  return power->readVinVoltage(status) / 4.096 * 0.025733 - 0.029;
+}
+
+double HAL_GetVinCurrent(int32_t* status) {
+  initializePower(status);
+  return power->readVinCurrent(status) / 4.096 * 0.017042 - 0.071;
+}
+
+double HAL_GetUserVoltage6V(int32_t* status) {
+  initializePower(status);
+  return power->readUserVoltage6V(status) / 4.096 * 0.007019 - 0.014;
+}
+
+double HAL_GetUserCurrent6V(int32_t* status) {
+  initializePower(status);
+  return power->readUserCurrent6V(status) / 4.096 * 0.005566 - 0.009;
+}
+
+HAL_Bool HAL_GetUserActive6V(int32_t* status) {
+  initializePower(status);
+  return power->readStatus_User6V(status) == 4;
+}
+
+int32_t HAL_GetUserCurrentFaults6V(int32_t* status) {
+  initializePower(status);
+  return static_cast<int32_t>(
+      power->readFaultCounts_OverCurrentFaultCount6V(status));
+}
+
+double HAL_GetUserVoltage5V(int32_t* status) {
+  initializePower(status);
+  return power->readUserVoltage5V(status) / 4.096 * 0.005962 - 0.013;
+}
+
+double HAL_GetUserCurrent5V(int32_t* status) {
+  initializePower(status);
+  return power->readUserCurrent5V(status) / 4.096 * 0.001996 - 0.002;
+}
+
+HAL_Bool HAL_GetUserActive5V(int32_t* status) {
+  initializePower(status);
+  return power->readStatus_User5V(status) == 4;
+}
+
+int32_t HAL_GetUserCurrentFaults5V(int32_t* status) {
+  initializePower(status);
+  return static_cast<int32_t>(
+      power->readFaultCounts_OverCurrentFaultCount5V(status));
+}
+
+double HAL_GetUserVoltage3V3(int32_t* status) {
+  initializePower(status);
+  return power->readUserVoltage3V3(status) / 4.096 * 0.004902 - 0.01;
+}
+
+double HAL_GetUserCurrent3V3(int32_t* status) {
+  initializePower(status);
+  return power->readUserCurrent3V3(status) / 4.096 * 0.002486 - 0.003;
+}
+
+HAL_Bool HAL_GetUserActive3V3(int32_t* status) {
+  initializePower(status);
+  return power->readStatus_User3V3(status) == 4;
+}
+
+int32_t HAL_GetUserCurrentFaults3V3(int32_t* status) {
+  initializePower(status);
+  return static_cast<int32_t>(
+      power->readFaultCounts_OverCurrentFaultCount3V3(status));
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/Relay.cpp b/hal/src/main/native/athena/Relay.cpp
new file mode 100644
index 0000000..9f7d6c0
--- /dev/null
+++ b/hal/src/main/native/athena/Relay.cpp
@@ -0,0 +1,143 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Relay.h"
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/handles/IndexedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+
+struct Relay {
+  uint8_t channel;
+  bool fwd;
+};
+
+}  // namespace
+
+static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
+                             HAL_HandleEnum::Relay>* relayHandles;
+
+// Create a mutex to protect changes to the relay values
+static wpi::mutex digitalRelayMutex;
+
+namespace hal {
+namespace init {
+void InitializeRelay() {
+  static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
+                               HAL_HandleEnum::Relay>
+      rH;
+  relayHandles = &rH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  initializeDigital(status);
+
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  if (!fwd) channel += kNumRelayHeaders;  // add 4 to reverse channels
+
+  auto handle = relayHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = relayHandles->Get(handle);
+  if (port == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  if (!fwd) {
+    // Subtract number of headers to put channel in range
+    channel -= kNumRelayHeaders;
+
+    port->fwd = false;  // set to reverse
+  } else {
+    port->fwd = true;  // set to forward
+  }
+
+  port->channel = static_cast<uint8_t>(channel);
+  return handle;
+}
+
+void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle) {
+  // no status, so no need to check for a proper free.
+  relayHandles->Free(relayPortHandle);
+}
+
+HAL_Bool HAL_CheckRelayChannel(int32_t channel) {
+  // roboRIO only has 4 headers, and the FPGA has
+  // seperate functions for forward and reverse,
+  // instead of seperate channel IDs
+  return channel < kNumRelayHeaders && channel >= 0;
+}
+
+void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
+                  int32_t* status) {
+  auto port = relayHandles->Get(relayPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  std::lock_guard<wpi::mutex> lock(digitalRelayMutex);
+  uint8_t relays = 0;
+  if (port->fwd) {
+    relays = relaySystem->readValue_Forward(status);
+  } else {
+    relays = relaySystem->readValue_Reverse(status);
+  }
+
+  if (*status != 0) return;  // bad status read
+
+  if (on) {
+    relays |= 1 << port->channel;
+  } else {
+    relays &= ~(1 << port->channel);
+  }
+
+  if (port->fwd) {
+    relaySystem->writeValue_Forward(relays, status);
+  } else {
+    relaySystem->writeValue_Reverse(relays, status);
+  }
+}
+
+HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status) {
+  auto port = relayHandles->Get(relayPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  uint8_t relays = 0;
+  if (port->fwd) {
+    relays = relaySystem->readValue_Forward(status);
+  } else {
+    relays = relaySystem->readValue_Reverse(status);
+  }
+
+  return (relays & (1 << port->channel)) != 0;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp
new file mode 100644
index 0000000..ddced41
--- /dev/null
+++ b/hal/src/main/native/athena/SPI.cpp
@@ -0,0 +1,634 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/SPI.h"
+
+#include <fcntl.h>
+#include <linux/spi/spidev.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <array>
+#include <atomic>
+#include <cstring>
+
+#include <wpi/mutex.h>
+#include <wpi/raw_ostream.h>
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "hal/DIO.h"
+#include "hal/HAL.h"
+#include "hal/handles/HandlesInternal.h"
+
+using namespace hal;
+
+static int32_t m_spiCS0Handle{0};
+static int32_t m_spiCS1Handle{0};
+static int32_t m_spiCS2Handle{0};
+static int32_t m_spiCS3Handle{0};
+static int32_t m_spiMXPHandle{0};
+
+static constexpr int32_t kSpiMaxHandles = 5;
+
+// Indices 0-3 are for onboard CS0-CS2. Index 4 is for MXP.
+static std::array<wpi::mutex, kSpiMaxHandles> spiHandleMutexes;
+static std::array<wpi::mutex, kSpiMaxHandles> spiApiMutexes;
+static std::array<wpi::mutex, kSpiMaxHandles> spiAccumulatorMutexes;
+
+// MXP SPI does not count towards this
+static std::atomic<int32_t> spiPortCount{0};
+
+static HAL_DigitalHandle digitalHandles[9]{HAL_kInvalidHandle};
+
+static wpi::mutex spiAutoMutex;
+static int32_t spiAutoPort = kSpiMaxHandles;
+static std::atomic_bool spiAutoRunning{false};
+static std::unique_ptr<tDMAManager> spiAutoDMA;
+
+static bool SPIInUseByAuto(HAL_SPIPort port) {
+  // SPI engine conflicts with any other chip selects on the same SPI device.
+  // 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);
+  return (spiAutoPort >= 0 && spiAutoPort <= 3 && port >= 0 && port <= 3) ||
+         (spiAutoPort == 4 && port == 4);
+}
+
+namespace hal {
+namespace init {
+void InitializeSPI() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+static void CommonSPIPortInit(int32_t* status) {
+  // All false cases will set
+  if (spiPortCount.fetch_add(1) == 0) {
+    // Have not been initialized yet
+    initializeDigital(status);
+    if (*status != 0) return;
+    // MISO
+    if ((digitalHandles[3] = HAL_InitializeDIOPort(createPortHandleForSPI(29),
+                                                   false, status)) ==
+        HAL_kInvalidHandle) {
+      std::printf("Failed to allocate DIO 29 (MISO)\n");
+      return;
+    }
+    // MOSI
+    if ((digitalHandles[4] = HAL_InitializeDIOPort(createPortHandleForSPI(30),
+                                                   false, status)) ==
+        HAL_kInvalidHandle) {
+      std::printf("Failed to allocate DIO 30 (MOSI)\n");
+      HAL_FreeDIOPort(digitalHandles[3]);  // free the first port allocated
+      return;
+    }
+  }
+}
+
+static void CommonSPIPortFree(void) {
+  if (spiPortCount.fetch_sub(1) == 1) {
+    // Clean up SPI Handles
+    HAL_FreeDIOPort(digitalHandles[3]);
+    HAL_FreeDIOPort(digitalHandles[4]);
+  }
+}
+
+void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
+  hal::init::CheckInit();
+  if (port < 0 || port >= kSpiMaxHandles) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  int handle;
+  if (HAL_GetSPIHandle(port) != 0) return;
+  switch (port) {
+    case HAL_SPI_kOnboardCS0:
+      CommonSPIPortInit(status);
+      if (*status != 0) return;
+      // CS0 is not a DIO port, so nothing to allocate
+      handle = open("/dev/spidev0.0", O_RDWR);
+      if (handle < 0) {
+        std::printf("Failed to open SPI port %d: %s\n", port,
+                    std::strerror(errno));
+        CommonSPIPortFree();
+        return;
+      }
+      HAL_SetSPIHandle(HAL_SPI_kOnboardCS0, handle);
+      break;
+    case HAL_SPI_kOnboardCS1:
+      CommonSPIPortInit(status);
+      if (*status != 0) return;
+      // CS1, Allocate
+      if ((digitalHandles[0] = HAL_InitializeDIOPort(createPortHandleForSPI(26),
+                                                     false, status)) ==
+          HAL_kInvalidHandle) {
+        std::printf("Failed to allocate DIO 26 (CS1)\n");
+        CommonSPIPortFree();
+        return;
+      }
+      handle = open("/dev/spidev0.1", O_RDWR);
+      if (handle < 0) {
+        std::printf("Failed to open SPI port %d: %s\n", port,
+                    std::strerror(errno));
+        CommonSPIPortFree();
+        HAL_FreeDIOPort(digitalHandles[0]);
+        return;
+      }
+      HAL_SetSPIHandle(HAL_SPI_kOnboardCS1, handle);
+      break;
+    case HAL_SPI_kOnboardCS2:
+      CommonSPIPortInit(status);
+      if (*status != 0) return;
+      // CS2, Allocate
+      if ((digitalHandles[1] = HAL_InitializeDIOPort(createPortHandleForSPI(27),
+                                                     false, status)) ==
+          HAL_kInvalidHandle) {
+        std::printf("Failed to allocate DIO 27 (CS2)\n");
+        CommonSPIPortFree();
+        return;
+      }
+      handle = open("/dev/spidev0.2", O_RDWR);
+      if (handle < 0) {
+        std::printf("Failed to open SPI port %d: %s\n", port,
+                    std::strerror(errno));
+        CommonSPIPortFree();
+        HAL_FreeDIOPort(digitalHandles[1]);
+        return;
+      }
+      HAL_SetSPIHandle(HAL_SPI_kOnboardCS2, handle);
+      break;
+    case HAL_SPI_kOnboardCS3:
+      CommonSPIPortInit(status);
+      if (*status != 0) return;
+      // CS3, Allocate
+      if ((digitalHandles[2] = HAL_InitializeDIOPort(createPortHandleForSPI(28),
+                                                     false, status)) ==
+          HAL_kInvalidHandle) {
+        std::printf("Failed to allocate DIO 28 (CS3)\n");
+        CommonSPIPortFree();
+        return;
+      }
+      handle = open("/dev/spidev0.3", O_RDWR);
+      if (handle < 0) {
+        std::printf("Failed to open SPI port %d: %s\n", port,
+                    std::strerror(errno));
+        CommonSPIPortFree();
+        HAL_FreeDIOPort(digitalHandles[2]);
+        return;
+      }
+      HAL_SetSPIHandle(HAL_SPI_kOnboardCS3, handle);
+      break;
+    case HAL_SPI_kMXP:
+      initializeDigital(status);
+      if (*status != 0) return;
+      if ((digitalHandles[5] = HAL_InitializeDIOPort(createPortHandleForSPI(14),
+                                                     false, status)) ==
+          HAL_kInvalidHandle) {
+        wpi::outs() << "Failed to allocate DIO 14\n";
+        return;
+      }
+      if ((digitalHandles[6] = HAL_InitializeDIOPort(createPortHandleForSPI(15),
+                                                     false, status)) ==
+          HAL_kInvalidHandle) {
+        wpi::outs() << "Failed to allocate DIO 15\n";
+        HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
+        return;
+      }
+      if ((digitalHandles[7] = HAL_InitializeDIOPort(createPortHandleForSPI(16),
+                                                     false, status)) ==
+          HAL_kInvalidHandle) {
+        wpi::outs() << "Failed to allocate DIO 16\n";
+        HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
+        HAL_FreeDIOPort(digitalHandles[6]);  // free the second port allocated
+        return;
+      }
+      if ((digitalHandles[8] = HAL_InitializeDIOPort(createPortHandleForSPI(17),
+                                                     false, status)) ==
+          HAL_kInvalidHandle) {
+        wpi::outs() << "Failed to allocate DIO 17\n";
+        HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
+        HAL_FreeDIOPort(digitalHandles[6]);  // free the second port allocated
+        HAL_FreeDIOPort(digitalHandles[7]);  // free the third port allocated
+        return;
+      }
+      digitalSystem->writeEnableMXPSpecialFunction(
+          digitalSystem->readEnableMXPSpecialFunction(status) | 0x00F0, status);
+      handle = open("/dev/spidev1.0", O_RDWR);
+      if (handle < 0) {
+        std::printf("Failed to open SPI port %d: %s\n", port,
+                    std::strerror(errno));
+        HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
+        HAL_FreeDIOPort(digitalHandles[6]);  // free the second port allocated
+        HAL_FreeDIOPort(digitalHandles[7]);  // free the third port allocated
+        HAL_FreeDIOPort(digitalHandles[8]);  // free the fourth port allocated
+        return;
+      }
+      HAL_SetSPIHandle(HAL_SPI_kMXP, handle);
+      break;
+    default:
+      *status = PARAMETER_OUT_OF_RANGE;
+      break;
+  }
+}
+
+int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend,
+                           uint8_t* dataReceived, int32_t size) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return -1;
+  }
+
+  if (SPIInUseByAuto(port)) return -1;
+
+  struct spi_ioc_transfer xfer;
+  std::memset(&xfer, 0, sizeof(xfer));
+  xfer.tx_buf = (__u64)dataToSend;
+  xfer.rx_buf = (__u64)dataReceived;
+  xfer.len = size;
+
+  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
+}
+
+int32_t HAL_WriteSPI(HAL_SPIPort port, const uint8_t* dataToSend,
+                     int32_t sendSize) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return -1;
+  }
+
+  if (SPIInUseByAuto(port)) return -1;
+
+  struct spi_ioc_transfer xfer;
+  std::memset(&xfer, 0, sizeof(xfer));
+  xfer.tx_buf = (__u64)dataToSend;
+  xfer.len = sendSize;
+
+  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
+}
+
+int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return -1;
+  }
+
+  if (SPIInUseByAuto(port)) return -1;
+
+  struct spi_ioc_transfer xfer;
+  std::memset(&xfer, 0, sizeof(xfer));
+  xfer.rx_buf = (__u64)buffer;
+  xfer.len = count;
+
+  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
+}
+
+void HAL_CloseSPI(HAL_SPIPort port) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return;
+  }
+
+  int32_t status = 0;
+  HAL_FreeSPIAuto(port, &status);
+
+  {
+    std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+    close(HAL_GetSPIHandle(port));
+  }
+
+  HAL_SetSPIHandle(port, 0);
+  if (port < 4) {
+    CommonSPIPortFree();
+  }
+
+  switch (port) {
+    // Case 0 does not need to do anything
+    case 1:
+      HAL_FreeDIOPort(digitalHandles[0]);
+      break;
+    case 2:
+      HAL_FreeDIOPort(digitalHandles[1]);
+      break;
+    case 3:
+      HAL_FreeDIOPort(digitalHandles[2]);
+      break;
+    case 4:
+      HAL_FreeDIOPort(digitalHandles[5]);
+      HAL_FreeDIOPort(digitalHandles[6]);
+      HAL_FreeDIOPort(digitalHandles[7]);
+      HAL_FreeDIOPort(digitalHandles[8]);
+      break;
+    default:
+      break;
+  }
+}
+
+void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+}
+
+void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
+                    HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return;
+  }
+
+  uint8_t mode = 0;
+  mode |= (!msbFirst ? 8 : 0);
+  mode |= (clkIdleHigh ? 2 : 0);
+  mode |= (sampleOnTrailing ? 1 : 0);
+
+  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MODE, &mode);
+}
+
+void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  if (port < 4) {
+    spiSystem->writeChipSelectActiveHigh_Hdr(
+        spiSystem->readChipSelectActiveHigh_Hdr(status) | (1 << port), status);
+  } else {
+    spiSystem->writeChipSelectActiveHigh_MXP(1, status);
+  }
+}
+
+void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiApiMutexes[port]);
+  if (port < 4) {
+    spiSystem->writeChipSelectActiveHigh_Hdr(
+        spiSystem->readChipSelectActiveHigh_Hdr(status) & ~(1 << port), status);
+  } else {
+    spiSystem->writeChipSelectActiveHigh_MXP(0, status);
+  }
+}
+
+int32_t HAL_GetSPIHandle(HAL_SPIPort port) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return 0;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiHandleMutexes[port]);
+  switch (port) {
+    case 0:
+      return m_spiCS0Handle;
+    case 1:
+      return m_spiCS1Handle;
+    case 2:
+      return m_spiCS2Handle;
+    case 3:
+      return m_spiCS3Handle;
+    case 4:
+      return m_spiMXPHandle;
+    default:
+      return 0;
+  }
+}
+
+void HAL_SetSPIHandle(HAL_SPIPort port, int32_t handle) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiHandleMutexes[port]);
+  switch (port) {
+    case 0:
+      m_spiCS0Handle = handle;
+      break;
+    case 1:
+      m_spiCS1Handle = handle;
+      break;
+    case 2:
+      m_spiCS2Handle = handle;
+      break;
+    case 3:
+      m_spiCS3Handle = handle;
+      break;
+    case 4:
+      m_spiMXPHandle = handle;
+      break;
+    default:
+      break;
+  }
+}
+
+void HAL_InitSPIAuto(HAL_SPIPort port, int32_t bufferSize, int32_t* status) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  // FPGA only has one auto SPI engine
+  if (spiAutoPort != kSpiMaxHandles) {
+    *status = RESOURCE_IS_ALLOCATED;
+    return;
+  }
+
+  // remember the initialized port for other entry points
+  spiAutoPort = port;
+
+  // configure the correct chip select
+  if (port < 4) {
+    spiSystem->writeAutoSPI1Select(false, status);
+    spiSystem->writeAutoChipSelect(port, status);
+  } else {
+    spiSystem->writeAutoSPI1Select(true, status);
+    spiSystem->writeAutoChipSelect(0, status);
+  }
+
+  // configure DMA
+  tDMAChannelDescriptor desc;
+  spiSystem->getSystemInterface()->getDmaDescriptor(g_SpiAutoData_index, &desc);
+  spiAutoDMA = std::make_unique<tDMAManager>(desc.channel, bufferSize, status);
+}
+
+void HAL_FreeSPIAuto(HAL_SPIPort port, int32_t* status) {
+  if (port < 0 || port >= kSpiMaxHandles) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  if (spiAutoPort != port) return;
+  spiAutoPort = kSpiMaxHandles;
+
+  // disable by setting to internal clock and setting rate=0
+  spiSystem->writeAutoRate(0, status);
+  spiSystem->writeAutoTriggerConfig_ExternalClock(false, status);
+
+  // stop the DMA
+  spiAutoDMA->stop(status);
+
+  spiAutoDMA.reset(nullptr);
+
+  spiAutoRunning = false;
+}
+
+void HAL_StartSPIAutoRate(HAL_SPIPort port, double period, int32_t* status) {
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  // FPGA only has one auto SPI engine
+  if (port != spiAutoPort) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  spiAutoRunning = true;
+
+  // start the DMA
+  spiAutoDMA->start(status);
+
+  // auto rate is in microseconds
+  spiSystem->writeAutoRate(period * 1000000, status);
+
+  // disable the external clock
+  spiSystem->writeAutoTriggerConfig_ExternalClock(false, status);
+}
+
+void HAL_StartSPIAutoTrigger(HAL_SPIPort port, HAL_Handle digitalSourceHandle,
+                             HAL_AnalogTriggerType analogTriggerType,
+                             HAL_Bool triggerRising, HAL_Bool triggerFalling,
+                             int32_t* status) {
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  // FPGA only has one auto SPI engine
+  if (port != spiAutoPort) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  spiAutoRunning = true;
+
+  // start the DMA
+  spiAutoDMA->start(status);
+
+  // get channel routing
+  bool routingAnalogTrigger = false;
+  uint8_t routingChannel = 0;
+  uint8_t routingModule = 0;
+  if (!remapDigitalSource(digitalSourceHandle, analogTriggerType,
+                          routingChannel, routingModule,
+                          routingAnalogTrigger)) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // configure external trigger and enable it
+  tSPI::tAutoTriggerConfig config;
+  config.ExternalClock = 1;
+  config.FallingEdge = triggerFalling ? 1 : 0;
+  config.RisingEdge = triggerRising ? 1 : 0;
+  config.ExternalClockSource_AnalogTrigger = routingAnalogTrigger ? 1 : 0;
+  config.ExternalClockSource_Module = routingModule;
+  config.ExternalClockSource_Channel = routingChannel;
+  spiSystem->writeAutoTriggerConfig(config, status);
+}
+
+void HAL_StopSPIAuto(HAL_SPIPort port, int32_t* status) {
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  // FPGA only has one auto SPI engine
+  if (port != spiAutoPort) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  // disable by setting to internal clock and setting rate=0
+  spiSystem->writeAutoRate(0, status);
+  spiSystem->writeAutoTriggerConfig_ExternalClock(false, status);
+
+  // stop the DMA
+  spiAutoDMA->stop(status);
+
+  spiAutoRunning = false;
+}
+
+void HAL_SetSPIAutoTransmitData(HAL_SPIPort port, const uint8_t* dataToSend,
+                                int32_t dataSize, int32_t zeroSize,
+                                int32_t* status) {
+  if (dataSize < 0 || dataSize > 16) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  if (zeroSize < 0 || zeroSize > 127) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  // FPGA only has one auto SPI engine
+  if (port != spiAutoPort) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  // set tx data registers
+  for (int32_t i = 0; i < dataSize; ++i)
+    spiSystem->writeAutoTx(i >> 2, i & 3, dataToSend[i], status);
+
+  // set byte counts
+  tSPI::tAutoByteCount config;
+  config.ZeroByteCount = static_cast<unsigned>(zeroSize) & 0x7f;
+  config.TxByteCount = static_cast<unsigned>(dataSize) & 0xf;
+  spiSystem->writeAutoByteCount(config, status);
+}
+
+void HAL_ForceSPIAutoRead(HAL_SPIPort port, int32_t* status) {
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  // FPGA only has one auto SPI engine
+  if (port != spiAutoPort) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  spiSystem->strobeAutoForceOne(status);
+}
+
+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);
+  // FPGA only has one auto SPI engine
+  if (port != spiAutoPort) {
+    *status = INCOMPATIBLE_STATE;
+    return 0;
+  }
+
+  size_t numRemaining = 0;
+  // timeout is in ms
+  spiAutoDMA->read(buffer, numToRead, timeout * 1000, &numRemaining, status);
+  return numRemaining;
+}
+
+int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status) {
+  std::lock_guard<wpi::mutex> lock(spiAutoMutex);
+  // FPGA only has one auto SPI engine
+  if (port != spiAutoPort) {
+    *status = INCOMPATIBLE_STATE;
+    return 0;
+  }
+
+  return spiSystem->readTransferSkippedFullCount(status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/SerialPort.cpp b/hal/src/main/native/athena/SerialPort.cpp
new file mode 100644
index 0000000..d2597a9
--- /dev/null
+++ b/hal/src/main/native/athena/SerialPort.cpp
@@ -0,0 +1,174 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/SerialPort.h"
+
+#include <string>
+
+#include "HALInitializer.h"
+#include "hal/cpp/SerialHelper.h"
+#include "visa/visa.h"
+
+static int32_t resourceManagerHandle{0};
+static HAL_SerialPort portHandles[4];
+
+namespace hal {
+namespace init {
+void InitializeSerialPort() {}
+}  // namespace init
+}  // 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::SerialHelper serialHelper;
+
+  portName = serialHelper.GetVISASerialPortName(port, status);
+
+  if (*status < 0) {
+    return;
+  }
+
+  *status = viOpen(resourceManagerHandle, const_cast<char*>(portName.c_str()),
+                   VI_NULL, VI_NULL,
+                   reinterpret_cast<ViSession*>(&portHandles[port]));
+  if (*status > 0) *status = 0;
+}
+
+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,
+                           int32_t* status) {
+  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_STOP_BITS, stopBits);
+  if (*status > 0) *status = 0;
+}
+
+void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode,
+                            int32_t* status) {
+  *status = viSetAttribute(portHandles[port], VI_ATTR_WR_BUF_OPER_MODE, mode);
+  if (*status > 0) *status = 0;
+}
+
+void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
+                              int32_t* status) {
+  *status = viSetAttribute(portHandles[port], VI_ATTR_ASRL_FLOW_CNTRL, flow);
+  if (*status > 0) *status = 0;
+}
+
+void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout,
+                          int32_t* status) {
+  *status = viSetAttribute(portHandles[port], VI_ATTR_TMO_VALUE,
+                           static_cast<uint32_t>(timeout * 1e3));
+  if (*status > 0) *status = 0;
+}
+
+void HAL_EnableSerialTermination(HAL_SerialPort port, 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;
+}
+
+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,
+                                  int32_t* status) {
+  *status = viSetBuf(portHandles[port], VI_WRITE_BUF, size);
+  if (*status > 0) *status = 0;
+}
+
+int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status) {
+  int32_t bytes = 0;
+
+  *status = viGetAttribute(portHandles[port], VI_ATTR_ASRL_AVAIL_NUM, &bytes);
+  if (*status > 0) *status = 0;
+  return bytes;
+}
+
+int32_t HAL_ReadSerial(HAL_SerialPort port, char* buffer, int32_t count,
+                       int32_t* status) {
+  uint32_t retCount = 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);
+  }
+
+  if (*status == VI_ERROR_TMO || *status > 0) *status = 0;
+  return static_cast<int32_t>(retCount);
+}
+
+int32_t HAL_WriteSerial(HAL_SerialPort port, const char* buffer, int32_t count,
+                        int32_t* status) {
+  uint32_t retCount = 0;
+
+  *status =
+      viWrite(portHandles[port], (ViPBuf)buffer, count, (ViPUInt32)&retCount);
+
+  if (*status > 0) *status = 0;
+  return static_cast<int32_t>(retCount);
+}
+
+void HAL_FlushSerial(HAL_SerialPort port, int32_t* status) {
+  *status = viFlush(portHandles[port], VI_WRITE_BUF);
+  if (*status > 0) *status = 0;
+}
+
+void HAL_ClearSerial(HAL_SerialPort port, int32_t* status) {
+  *status = viClear(portHandles[port]);
+  if (*status > 0) *status = 0;
+}
+
+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/Solenoid.cpp b/hal/src/main/native/athena/Solenoid.cpp
new file mode 100644
index 0000000..c53db11
--- /dev/null
+++ b/hal/src/main/native/athena/Solenoid.cpp
@@ -0,0 +1,191 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Solenoid.h"
+
+#include <FRC_NetworkCommunication/LoadOut.h>
+
+#include "HALInitializer.h"
+#include "PCMInternal.h"
+#include "PortsInternal.h"
+#include "ctre/PCM.h"
+#include "hal/ChipObject.h"
+#include "hal/Errors.h"
+#include "hal/Ports.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/IndexedHandleResource.h"
+
+namespace {
+
+struct Solenoid {
+  uint8_t module;
+  uint8_t channel;
+};
+
+}  // namespace
+
+using namespace hal;
+
+static IndexedHandleResource<HAL_SolenoidHandle, Solenoid,
+                             kNumPCMModules * kNumSolenoidChannels,
+                             HAL_HandleEnum::Solenoid>* solenoidHandles;
+
+namespace hal {
+namespace init {
+void InitializeSolenoid() {
+  static IndexedHandleResource<HAL_SolenoidHandle, Solenoid,
+                               kNumPCMModules * kNumSolenoidChannels,
+                               HAL_HandleEnum::Solenoid>
+      sH;
+  solenoidHandles = &sH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle,
+                                              int32_t* status) {
+  hal::init::CheckInit();
+  int16_t channel = getPortHandleChannel(portHandle);
+  int16_t module = getPortHandleModule(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  // initializePCM will check the module
+  if (!HAL_CheckSolenoidChannel(channel)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  initializePCM(module, status);
+  if (*status != 0) {
+    return HAL_kInvalidHandle;
+  }
+
+  auto handle = solenoidHandles->Allocate(
+      module * kNumSolenoidChannels + channel, status);
+  if (*status != 0) {
+    return HAL_kInvalidHandle;
+  }
+  auto solenoidPort = solenoidHandles->Get(handle);
+  if (solenoidPort == nullptr) {  // would only occur on thread issues
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  solenoidPort->module = static_cast<uint8_t>(module);
+  solenoidPort->channel = static_cast<uint8_t>(channel);
+
+  return handle;
+}
+
+void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle) {
+  solenoidHandles->Free(solenoidPortHandle);
+}
+
+HAL_Bool HAL_CheckSolenoidModule(int32_t module) {
+  return module < kNumPCMModules && module >= 0;
+}
+
+HAL_Bool HAL_CheckSolenoidChannel(int32_t channel) {
+  return channel < kNumSolenoidChannels && channel >= 0;
+}
+
+HAL_Bool HAL_GetSolenoid(HAL_SolenoidHandle solenoidPortHandle,
+                         int32_t* status) {
+  auto port = solenoidHandles->Get(solenoidPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  bool value;
+
+  *status = PCM_modules[port->module]->GetSolenoid(port->channel, value);
+
+  return value;
+}
+
+int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status) {
+  if (!checkPCMInit(module, status)) return 0;
+  uint8_t value;
+
+  *status = PCM_modules[module]->GetAllSolenoids(value);
+
+  return value;
+}
+
+void HAL_SetSolenoid(HAL_SolenoidHandle solenoidPortHandle, HAL_Bool value,
+                     int32_t* status) {
+  auto port = solenoidHandles->Get(solenoidPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  *status = PCM_modules[port->module]->SetSolenoid(port->channel, value);
+}
+
+void HAL_SetAllSolenoids(int32_t module, int32_t state, int32_t* status) {
+  if (!checkPCMInit(module, status)) return;
+
+  *status = PCM_modules[module]->SetAllSolenoids(state);
+}
+
+int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status) {
+  if (!checkPCMInit(module, status)) return 0;
+  uint8_t value;
+
+  *status = PCM_modules[module]->GetSolenoidBlackList(value);
+
+  return value;
+}
+HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status) {
+  if (!checkPCMInit(module, status)) return 0;
+  bool value;
+
+  *status = PCM_modules[module]->GetSolenoidStickyFault(value);
+
+  return value;
+}
+HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status) {
+  if (!checkPCMInit(module, status)) return false;
+  bool value;
+
+  *status = PCM_modules[module]->GetSolenoidFault(value);
+
+  return value;
+}
+void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status) {
+  if (!checkPCMInit(module, status)) return;
+
+  *status = PCM_modules[module]->ClearStickyFaults();
+}
+
+void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
+                            int32_t durMS, int32_t* status) {
+  auto port = solenoidHandles->Get(solenoidPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  *status =
+      PCM_modules[port->module]->SetOneShotDurationMs(port->channel, durMS);
+}
+
+void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status) {
+  auto port = solenoidHandles->Get(solenoidPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  *status = PCM_modules[port->module]->FireOneShotSolenoid(port->channel);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/athena/Threads.cpp b/hal/src/main/native/athena/Threads.cpp
new file mode 100644
index 0000000..95d1f59
--- /dev/null
+++ b/hal/src/main/native/athena/Threads.cpp
@@ -0,0 +1,93 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Threads.h"
+
+#include <pthread.h>
+#include <sched.h>
+
+#include "hal/Errors.h"
+
+namespace hal {
+namespace init {
+void InitializeThreads() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
+                              int32_t* status) {
+  sched_param sch;
+  int policy;
+  int success = pthread_getschedparam(
+      *reinterpret_cast<const pthread_t*>(handle), &policy, &sch);
+  if (success == 0) {
+    *status = 0;
+  } else {
+    *status = HAL_THREAD_PRIORITY_ERROR;
+    return -1;
+  }
+  if (policy == SCHED_FIFO || policy == SCHED_RR) {
+    *isRealTime = true;
+    return sch.sched_priority;
+  } else {
+    *isRealTime = false;
+    // 0 is the only suppored priority for non-realtime, so scale to 1
+    return 1;
+  }
+}
+
+int32_t HAL_GetCurrentThreadPriority(HAL_Bool* isRealTime, int32_t* status) {
+  auto thread = pthread_self();
+  return HAL_GetThreadPriority(&thread, isRealTime, status);
+}
+
+HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
+                               int32_t priority, int32_t* status) {
+  if (handle == nullptr) {
+    *status = NULL_PARAMETER;
+    return false;
+  }
+
+  int scheduler = realTime ? SCHED_FIFO : SCHED_OTHER;
+  if (realTime) {
+    // We don't support setting priorities for non RT threads
+    // so we don't need to check for proper range
+    if (priority < sched_get_priority_min(scheduler) ||
+        priority > sched_get_priority_max(scheduler)) {
+      *status = HAL_THREAD_PRIORITY_RANGE_ERROR;
+      return false;
+    }
+  }
+
+  sched_param sch;
+  int policy;
+  pthread_getschedparam(*reinterpret_cast<const pthread_t*>(handle), &policy,
+                        &sch);
+  if (scheduler == SCHED_FIFO || scheduler == SCHED_RR)
+    sch.sched_priority = priority;
+  else
+    // Only need to set 0 priority for non RT thread
+    sch.sched_priority = 0;
+  if (pthread_setschedparam(*reinterpret_cast<const pthread_t*>(handle),
+                            scheduler, &sch)) {
+    *status = HAL_THREAD_PRIORITY_ERROR;
+    return false;
+  } else {
+    *status = 0;
+    return true;
+  }
+}
+
+HAL_Bool HAL_SetCurrentThreadPriority(HAL_Bool realTime, int32_t priority,
+                                      int32_t* status) {
+  auto thread = pthread_self();
+  return HAL_SetThreadPriority(&thread, realTime, priority, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/cpp/SerialHelper.cpp b/hal/src/main/native/athena/cpp/SerialHelper.cpp
new file mode 100644
index 0000000..98b22db
--- /dev/null
+++ b/hal/src/main/native/athena/cpp/SerialHelper.cpp
@@ -0,0 +1,333 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/cpp/SerialHelper.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+
+#include <wpi/FileSystem.h>
+#include <wpi/StringRef.h>
+
+#include "../visa/visa.h"
+#include "hal/Errors.h"
+
+constexpr const char* OnboardResourceVISA = "ASRL1::INSTR";
+constexpr const char* MxpResourceVISA = "ASRL2::INSTR";
+
+constexpr const char* OnboardResourceOS = "/dev/ttyS0";
+constexpr const char* MxpResourceOS = "/dev/ttyS1";
+
+namespace hal {
+
+std::string SerialHelper::m_usbNames[2]{"", ""};
+
+wpi::mutex SerialHelper::m_nameMutex;
+
+SerialHelper::SerialHelper() {
+  viOpenDefaultRM(reinterpret_cast<ViSession*>(&m_resourceHandle));
+}
+
+std::string SerialHelper::GetVISASerialPortName(HAL_SerialPort port,
+                                                int32_t* status) {
+  if (port == HAL_SerialPort::HAL_SerialPort_Onboard) {
+    return OnboardResourceVISA;
+  } else if (port == HAL_SerialPort::HAL_SerialPort_MXP) {
+    return MxpResourceVISA;
+  }
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return error
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+  }
+
+  int32_t visaIndex = GetIndexForPort(port, status);
+  if (visaIndex == -1) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+    // Error
+  } else {
+    return m_visaResource[visaIndex].str();
+  }
+}
+
+std::string SerialHelper::GetOSSerialPortName(HAL_SerialPort port,
+                                              int32_t* status) {
+  if (port == HAL_SerialPort::HAL_SerialPort_Onboard) {
+    return OnboardResourceOS;
+  } else if (port == HAL_SerialPort::HAL_SerialPort_MXP) {
+    return MxpResourceOS;
+  }
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return error
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+  }
+
+  int32_t osIndex = GetIndexForPort(port, status);
+  if (osIndex == -1) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+    // Error
+  } else {
+    return m_osResource[osIndex].str();
+  }
+}
+
+std::vector<std::string> SerialHelper::GetVISASerialPortList(int32_t* status) {
+  std::vector<std::string> retVec;
+
+  // Always add 2 onboard ports
+  retVec.emplace_back(OnboardResourceVISA);
+  retVec.emplace_back(MxpResourceVISA);
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return only onboard list
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = 0;
+    return retVec;
+  }
+
+  for (auto& i : m_visaResource) {
+    retVec.emplace_back(i.str());
+  }
+
+  return retVec;
+}
+
+std::vector<std::string> SerialHelper::GetOSSerialPortList(int32_t* status) {
+  std::vector<std::string> retVec;
+
+  // Always add 2 onboard ports
+  retVec.emplace_back(OnboardResourceOS);
+  retVec.emplace_back(MxpResourceOS);
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return only onboard list
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = 0;
+    return retVec;
+  }
+
+  for (auto& i : m_osResource) {
+    retVec.emplace_back(i.str());
+  }
+
+  return retVec;
+}
+
+void SerialHelper::SortHubPathVector() {
+  m_sortedHubPath.clear();
+  m_sortedHubPath = m_unsortedHubPath;
+  std::sort(m_sortedHubPath.begin(), m_sortedHubPath.end(),
+            [](const wpi::SmallVectorImpl<char>& lhs,
+               const wpi::SmallVectorImpl<char>& rhs) -> int {
+              wpi::StringRef lhsRef(lhs.begin(), lhs.size());
+              wpi::StringRef rhsRef(rhs.begin(), rhs.size());
+              return lhsRef.compare(rhsRef);
+            });
+}
+
+void SerialHelper::CoiteratedSort(
+    wpi::SmallVectorImpl<wpi::SmallString<16>>& vec) {
+  wpi::SmallVector<wpi::SmallString<16>, 4> sortedVec;
+  for (auto& str : m_sortedHubPath) {
+    for (size_t i = 0; i < m_unsortedHubPath.size(); i++) {
+      if (wpi::StringRef{m_unsortedHubPath[i].begin(),
+                         m_unsortedHubPath[i].size()}
+              .equals(wpi::StringRef{str.begin(), str.size()})) {
+        sortedVec.push_back(vec[i]);
+        break;
+      }
+    }
+  }
+  vec = sortedVec;
+}
+
+void SerialHelper::QueryHubPaths(int32_t* status) {
+  // VISA resource matching string
+  const char* str = "?*";
+  // Items needed for VISA
+  ViUInt32 retCnt = 0;
+  ViFindList viList = 0;
+  ViChar desc[VI_FIND_BUFLEN];
+  *status = viFindRsrc(m_resourceHandle, const_cast<char*>(str), &viList,
+                       &retCnt, desc);
+
+  if (*status < 0) {
+    // Handle the bad status elsewhere
+    // Note let positive statii (warnings) continue
+    goto done;
+  }
+  // Status might be positive, so reset it to 0
+  *status = 0;
+
+  // Storage buffer for Visa call
+  char osName[256];
+
+  // Loop through all returned VISA objects.
+  // Increment the internal VISA ptr every loop
+  for (size_t i = 0; i < retCnt; i++, viFindNext(viList, desc)) {
+    // Ignore any matches to the 2 onboard ports
+    if (std::strcmp(OnboardResourceVISA, desc) == 0 ||
+        std::strcmp(MxpResourceVISA, desc) == 0) {
+      continue;
+    }
+
+    // Open the resource, grab its interface name, and close it.
+    ViSession vSession;
+    *status = viOpen(m_resourceHandle, desc, VI_NULL, VI_NULL, &vSession);
+    if (*status < 0) goto done;
+    *status = 0;
+
+    *status = viGetAttribute(vSession, VI_ATTR_INTF_INST_NAME, &osName);
+    // Ignore an error here, as we want to close the session on an error
+    // Use a seperate close variable so we can check
+    ViStatus closeStatus = viClose(vSession);
+    if (*status < 0) goto done;
+    if (closeStatus < 0) goto done;
+    *status = 0;
+
+    // split until (/dev/
+    wpi::StringRef devNameRef = wpi::StringRef{osName}.split("(/dev/").second;
+    // String not found, continue
+    if (devNameRef.equals("")) continue;
+
+    // Split at )
+    wpi::StringRef matchString = devNameRef.split(')').first;
+    if (matchString.equals(devNameRef)) continue;
+
+    // Search directories to get a list of system accessors
+    // The directories we need are not symbolic, so we can safely
+    // disable symbolic links.
+    std::error_code ec;
+    for (auto p = wpi::sys::fs::recursive_directory_iterator(
+             "/sys/devices/soc0", ec, false);
+         p != wpi::sys::fs::recursive_directory_iterator(); p.increment(ec)) {
+      if (ec) break;
+      wpi::StringRef path{p->path()};
+      if (path.find("amba") == wpi::StringRef::npos) continue;
+      if (path.find("usb") == wpi::StringRef::npos) continue;
+      if (path.find(matchString) == wpi::StringRef::npos) continue;
+
+      wpi::SmallVector<wpi::StringRef, 16> pathSplitVec;
+      // Split path into individual directories
+      path.split(pathSplitVec, '/', -1, false);
+
+      // Find each individual item index
+      int findusb = -1;
+      int findtty = -1;
+      int findregex = -1;
+      for (size_t i = 0; i < pathSplitVec.size(); i++) {
+        if (findusb == -1 && pathSplitVec[i].equals("usb1")) {
+          findusb = i;
+        }
+        if (findtty == -1 && pathSplitVec[i].equals("tty")) {
+          findtty = i;
+        }
+        if (findregex == -1 && pathSplitVec[i].equals(matchString)) {
+          findregex = i;
+        }
+      }
+
+      // Get the index for our device
+      int hubIndex = findtty;
+      if (findtty == -1) hubIndex = findregex;
+
+      int devStart = findusb + 1;
+
+      if (hubIndex < devStart) continue;
+
+      // Add our devices to our list
+      m_unsortedHubPath.emplace_back(
+          wpi::StringRef{pathSplitVec[hubIndex - 2]});
+      m_visaResource.emplace_back(desc);
+      m_osResource.emplace_back(
+          wpi::StringRef{osName}.split("(").second.split(")").first);
+      break;
+    }
+  }
+
+  SortHubPathVector();
+
+  CoiteratedSort(m_visaResource);
+  CoiteratedSort(m_osResource);
+done:
+  viClose(viList);
+}
+
+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::string portString = m_usbNames[port - 2];
+
+  wpi::SmallVector<int32_t, 4> indices;
+
+  // If port has not been assigned, find the one to assign
+  if (portString.empty()) {
+    for (size_t i = 0; i < 2; i++) {
+      // Remove all used ports
+      auto idx = std::find(m_sortedHubPath.begin(), m_sortedHubPath.end(),
+                           m_usbNames[i]);
+      if (idx != m_sortedHubPath.end()) {
+        // found
+        m_sortedHubPath.erase(idx);
+      }
+      if (m_usbNames[i] == "") {
+        indices.push_back(i);
+      }
+    }
+
+    int32_t idx = -1;
+    for (size_t i = 0; i < indices.size(); i++) {
+      if (indices[i] == port - 2) {
+        idx = i;
+        break;
+      }
+    }
+
+    if (idx == -1) {
+      *status = HAL_SERIAL_PORT_NOT_FOUND;
+      return -1;
+    }
+
+    if (idx >= static_cast<int32_t>(m_sortedHubPath.size())) {
+      *status = HAL_SERIAL_PORT_NOT_FOUND;
+      return -1;
+    }
+
+    portString = m_sortedHubPath[idx].str();
+    m_usbNames[port - 2] = portString;
+  }
+
+  int retIndex = -1;
+
+  for (size_t i = 0; i < m_sortedHubPath.size(); i++) {
+    if (m_sortedHubPath[i].equals(portString)) {
+      retIndex = i;
+      break;
+    }
+  }
+
+  return retIndex;
+}
+
+}  // namespace hal
diff --git a/hal/src/main/native/athena/ctre/CtreCanNode.cpp b/hal/src/main/native/athena/ctre/CtreCanNode.cpp
new file mode 100644
index 0000000..bd3c9e8
--- /dev/null
+++ b/hal/src/main/native/athena/ctre/CtreCanNode.cpp
@@ -0,0 +1,157 @@
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+
+#include "CtreCanNode.h"
+#include "FRC_NetworkCommunication/CANSessionMux.h"
+#include <string.h> // memset
+
+static const UINT32 kFullMessageIDMask = 0x1fffffff;
+
+CtreCanNode::CtreCanNode(UINT8 deviceNumber)
+{
+	_deviceNumber = deviceNumber;
+}
+CtreCanNode::~CtreCanNode()
+{
+}
+void CtreCanNode::RegisterRx(uint32_t arbId)
+{
+	/* no need to do anything, we just use new API to poll last received message */
+}
+/**
+ * Schedule a CAN Frame for periodic transmit.
+ * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
+ * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
+ * @param dlc 		Number of bytes to transmit (0 to 8).
+ * @param initialFrame	Ptr to the frame data to schedule for transmitting.  Passing null will result
+ *						in defaulting to zero data value.
+ */
+void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs, uint32_t dlc, const uint8_t * initialFrame)
+{
+	int32_t status = 0;
+	if(dlc > 8)
+		dlc = 8;
+	txJob_t job = {0};
+	job.arbId = arbId;
+	job.periodMs = periodMs;
+	job.dlc = dlc;
+	if(initialFrame){
+		/* caller wants to specify original data */
+		memcpy(job.toSend, initialFrame, dlc);
+	}
+	_txJobs[arbId] = job;
+	FRC_NetworkCommunication_CANSessionMux_sendMessage(	job.arbId,
+														job.toSend,
+														job.dlc,
+														job.periodMs,
+														&status);
+}
+/**
+ * Schedule a CAN Frame for periodic transmit.  Assume eight byte DLC and zero value for initial transmission.
+ * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
+ * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
+ */
+void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs)
+{
+	RegisterTx(arbId,periodMs, 8, 0);
+}
+/**
+ * Remove a CAN frame Arbid to stop transmission.
+ * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
+ */
+void CtreCanNode::UnregisterTx(uint32_t arbId)
+{
+	/* set period to zero */
+	ChangeTxPeriod(arbId, 0);
+	/* look and remove */
+	txJobs_t::iterator iter = _txJobs.find(arbId);
+	if(iter != _txJobs.end()) {
+		_txJobs.erase(iter);
+	}
+}
+static int64_t GetTimeMs() {
+	std::chrono::time_point < std::chrono::system_clock > now;
+	now = std::chrono::system_clock::now();
+	auto duration = now.time_since_epoch();
+	auto millis = std::chrono::duration_cast < std::chrono::milliseconds
+					> (duration).count();
+	return (int64_t) millis;
+}
+CTR_Code CtreCanNode::GetRx(uint32_t arbId,uint8_t * dataBytes, uint32_t timeoutMs)
+{
+	CTR_Code retval = CTR_OKAY;
+	int32_t status = 0;
+	uint8_t len = 0;
+	uint32_t timeStamp;
+	/* cap timeout at 999ms */
+	if(timeoutMs > 999)
+		timeoutMs = 999;
+	FRC_NetworkCommunication_CANSessionMux_receiveMessage(&arbId,kFullMessageIDMask,dataBytes,&len,&timeStamp,&status);
+	std::lock_guard<wpi::mutex> lock(_lck);
+	if(status == 0){
+		/* fresh update */
+		rxEvent_t & r = _rxRxEvents[arbId]; /* lookup entry or make a default new one with all zeroes */
+		r.time = GetTimeMs();
+		memcpy(r.bytes,  dataBytes,  8);	/* fill in databytes */
+	}else{
+		/* did not get the message */
+		rxRxEvents_t::iterator i = _rxRxEvents.find(arbId);
+		if(i == _rxRxEvents.end()){
+			/* we've never gotten this mesage */
+			retval = CTR_RxTimeout;
+			/* fill caller's buffer with zeros */
+			memset(dataBytes,0,8);
+		}else{
+			/* we've gotten this message before but not recently */
+			memcpy(dataBytes,i->second.bytes,8);
+			/* get the time now */
+			int64_t now = GetTimeMs(); /* get now */
+			/* how long has it been? */
+			int64_t temp = now - i->second.time; /* temp = now - last */
+			if (temp > ((int64_t) timeoutMs)) {
+					retval = CTR_RxTimeout;
+			} else {
+					/* our last update was recent enough */
+			}
+		}
+	}
+
+	return retval;
+}
+void CtreCanNode::FlushTx(uint32_t arbId)
+{
+	int32_t status = 0;
+	txJobs_t::iterator iter = _txJobs.find(arbId);
+	if(iter != _txJobs.end())
+		FRC_NetworkCommunication_CANSessionMux_sendMessage(	iter->second.arbId,
+															iter->second.toSend,
+															iter->second.dlc,
+															iter->second.periodMs,
+															&status);
+}
+/**
+ * Change the transmit period of an already scheduled CAN frame.
+ * This keeps the frame payload contents the same without caller having to perform
+ * a read-modify-write.
+ * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
+ * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
+ * @return true if scheduled job was found and updated, false if there was no preceding job for the specified arbID.
+ */
+bool CtreCanNode::ChangeTxPeriod(uint32_t arbId, uint32_t periodMs)
+{
+	int32_t status = 0;
+	/* lookup the data bytes and period for this message */
+	txJobs_t::iterator iter = _txJobs.find(arbId);
+	if(iter != _txJobs.end()) {
+		/* modify th periodMs */
+		iter->second.periodMs = periodMs;
+		/* reinsert into scheduler with the same data bytes, only the period changed. */
+		FRC_NetworkCommunication_CANSessionMux_sendMessage(	iter->second.arbId,
+															iter->second.toSend,
+															iter->second.dlc,
+															iter->second.periodMs,
+															&status);
+		return true;
+	}
+	return false;
+}
+
diff --git a/hal/src/main/native/athena/ctre/CtreCanNode.h b/hal/src/main/native/athena/ctre/CtreCanNode.h
new file mode 100644
index 0000000..f00060d
--- /dev/null
+++ b/hal/src/main/native/athena/ctre/CtreCanNode.h
@@ -0,0 +1,134 @@
+#ifndef CtreCanNode_H_
+#define CtreCanNode_H_
+#include "ctre.h"				//BIT Defines + Typedefs
+#include <map>
+#include <string.h> // memcpy
+#include <sys/time.h>
+#include <wpi/mutex.h>
+class CtreCanNode
+{
+public:
+	CtreCanNode(UINT8 deviceNumber);
+    ~CtreCanNode();
+
+	UINT8 GetDeviceNumber()
+	{
+		return _deviceNumber;
+	}
+protected:
+
+
+	template <typename T> class txTask{
+		public:
+			uint32_t arbId;
+			T * toSend;
+			T * operator -> ()
+			{
+				return toSend;
+			}
+			T & operator*()
+			{
+				return *toSend;
+			}
+			bool IsEmpty()
+			{
+				if(toSend == 0)
+					return true;
+				return false;
+			}
+	};
+	template <typename T> class recMsg{
+		public:
+			uint32_t arbId;
+			uint8_t bytes[8];
+			CTR_Code err;
+			T * operator -> ()
+			{
+				return (T *)bytes;
+			}
+			T & operator*()
+			{
+				return *(T *)bytes;
+			}
+	};
+	UINT8 _deviceNumber;
+	void RegisterRx(uint32_t arbId);
+	/**
+	 * Schedule a CAN Frame for periodic transmit.  Assume eight byte DLC and zero value for initial transmission.
+	 * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
+	 * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
+	 */
+	void RegisterTx(uint32_t arbId, uint32_t periodMs);
+	/**
+	 * Schedule a CAN Frame for periodic transmit.
+	 * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
+	 * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
+	 * @param dlc 		Number of bytes to transmit (0 to 8).
+	 * @param initialFrame	Ptr to the frame data to schedule for transmitting.  Passing null will result
+	 *						in defaulting to zero data value.
+	 */
+	void RegisterTx(uint32_t arbId, uint32_t periodMs, uint32_t dlc, const uint8_t * initialFrame);
+	void UnregisterTx(uint32_t arbId);
+
+	CTR_Code GetRx(uint32_t arbId,uint8_t * dataBytes,uint32_t timeoutMs);
+	void FlushTx(uint32_t arbId);
+	bool ChangeTxPeriod(uint32_t arbId, uint32_t periodMs);
+
+	template<typename T> txTask<T> GetTx(uint32_t arbId)
+	{
+		txTask<T> retval = {0, nullptr};
+		txJobs_t::iterator i = _txJobs.find(arbId);
+		if(i != _txJobs.end()){
+			retval.arbId = i->second.arbId;
+			retval.toSend = (T*)i->second.toSend;
+		}
+		return retval;
+	}
+	template<class T> void FlushTx(T & par)
+	{
+		FlushTx(par.arbId);
+	}
+
+	template<class T> recMsg<T> GetRx(uint32_t arbId, uint32_t timeoutMs)
+	{
+		recMsg<T> retval;
+		retval.err = GetRx(arbId,retval.bytes, timeoutMs);
+		return retval;
+	}
+
+private:
+
+	class txJob_t {
+		public:
+			uint32_t arbId;
+			uint8_t toSend[8];
+			uint32_t periodMs;
+			uint8_t dlc;
+	};
+
+	class rxEvent_t{
+		public:
+			uint8_t bytes[8];
+			int64_t time;
+			rxEvent_t()
+			{
+				bytes[0] = 0;
+				bytes[1] = 0;
+				bytes[2] = 0;
+				bytes[3] = 0;
+				bytes[4] = 0;
+				bytes[5] = 0;
+				bytes[6] = 0;
+				bytes[7] = 0;
+			}
+	};
+
+	typedef std::map<uint32_t,txJob_t> txJobs_t;
+	txJobs_t _txJobs;
+
+	typedef std::map<uint32_t,rxEvent_t> rxRxEvents_t;
+	rxRxEvents_t _rxRxEvents;
+
+	wpi::mutex _lck;
+};
+#endif
diff --git a/hal/src/main/native/athena/ctre/PCM.cpp b/hal/src/main/native/athena/ctre/PCM.cpp
new file mode 100644
index 0000000..e05d4d4
--- /dev/null
+++ b/hal/src/main/native/athena/ctre/PCM.cpp
@@ -0,0 +1,574 @@
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+
+#include "PCM.h"
+#include "FRC_NetworkCommunication/CANSessionMux.h"
+#include <string.h> // memset
+/* This can be a constant, as long as nobody needs to update solenoids within
+    1/50 of a second. */
+static const INT32 kCANPeriod = 20;
+
+#define STATUS_1  			0x9041400
+#define STATUS_SOL_FAULTS  	0x9041440
+#define STATUS_DEBUG  		0x9041480
+
+#define EXPECTED_RESPONSE_TIMEOUT_MS	(50)
+#define GET_PCM_STATUS()			CtreCanNode::recMsg<PcmStatus_t> 		rx = GetRx<PcmStatus_t>			(STATUS_1|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
+#define GET_PCM_SOL_FAULTS()		CtreCanNode::recMsg<PcmStatusFault_t> 	rx = GetRx<PcmStatusFault_t>	(STATUS_SOL_FAULTS|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
+#define GET_PCM_DEBUG()				CtreCanNode::recMsg<PcmDebug_t> 		rx = GetRx<PcmDebug_t>			(STATUS_DEBUG|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
+
+#define CONTROL_1 			0x09041C00	/* PCM_Control */
+#define CONTROL_2 			0x09041C40	/* PCM_SupplemControl */
+#define CONTROL_3 			0x09041C80	/* PcmControlSetOneShotDur_t */
+
+/* encoder/decoders */
+typedef struct _PcmStatus_t{
+	/* Byte 0 */
+	unsigned SolenoidBits:8;
+	/* Byte 1 */
+	unsigned compressorOn:1;
+	unsigned stickyFaultFuseTripped:1;
+	unsigned stickyFaultCompCurrentTooHigh:1;
+	unsigned faultFuseTripped:1;
+	unsigned faultCompCurrentTooHigh:1;
+	unsigned faultHardwareFailure:1;
+	unsigned isCloseloopEnabled:1;
+	unsigned pressureSwitchEn:1;
+	/* Byte 2*/
+	unsigned battVoltage:8;
+	/* Byte 3 */
+	unsigned solenoidVoltageTop8:8;
+	/* Byte 4 */
+	unsigned compressorCurrentTop6:6;
+	unsigned solenoidVoltageBtm2:2;
+	/* Byte 5 */
+	unsigned StickyFault_dItooHigh :1;
+	unsigned Fault_dItooHigh :1;
+	unsigned moduleEnabled:1;
+	unsigned closedLoopOutput:1;
+	unsigned compressorCurrentBtm4:4;
+	/* Byte 6 */
+	unsigned tokenSeedTop8:8;
+	/* Byte 7 */
+	unsigned tokenSeedBtm8:8;
+}PcmStatus_t;
+
+typedef struct _PcmControl_t{
+	/* Byte 0 */
+	unsigned tokenTop8:8;
+	/* Byte 1 */
+	unsigned tokenBtm8:8;
+	/* Byte 2 */
+	unsigned solenoidBits:8;
+	/* Byte 3*/
+	unsigned reserved:4;
+	unsigned closeLoopOutput:1;
+	unsigned compressorOn:1;
+	unsigned closedLoopEnable:1;
+	unsigned clearStickyFaults:1;
+	/* Byte 4 */
+	unsigned OneShotField_h8:8;
+	/* Byte 5 */
+	unsigned OneShotField_l8:8;
+}PcmControl_t;
+
+typedef struct _PcmControlSetOneShotDur_t{
+	uint8_t sol10MsPerUnit[8];
+}PcmControlSetOneShotDur_t;
+
+typedef struct _PcmStatusFault_t{
+	/* Byte 0 */
+	unsigned SolenoidBlacklist:8;
+	/* Byte 1 */
+	unsigned reserved_bit0 :1;
+	unsigned reserved_bit1 :1;
+	unsigned reserved_bit2 :1;
+	unsigned reserved_bit3 :1;
+	unsigned StickyFault_CompNoCurrent :1;
+	unsigned Fault_CompNoCurrent :1;
+	unsigned StickyFault_SolenoidJumper :1;
+	unsigned Fault_SolenoidJumper :1;
+}PcmStatusFault_t;
+
+typedef struct _PcmDebug_t{
+	unsigned tokFailsTop8:8;
+	unsigned tokFailsBtm8:8;
+	unsigned lastFailedTokTop8:8;
+	unsigned lastFailedTokBtm8:8;
+	unsigned tokSuccessTop8:8;
+	unsigned tokSuccessBtm8:8;
+}PcmDebug_t;
+
+
+/* PCM Constructor - Clears all vars, establishes default settings, starts PCM background process
+ *
+ * @Return	-	void
+ *
+ * @Param 	-	deviceNumber	- 	Device ID of PCM to be controlled
+ */
+PCM::PCM(UINT8 deviceNumber): CtreCanNode(deviceNumber)
+{
+	RegisterRx(STATUS_1 | deviceNumber );
+	RegisterRx(STATUS_SOL_FAULTS | deviceNumber );
+	RegisterRx(STATUS_DEBUG | deviceNumber );
+	RegisterTx(CONTROL_1 | deviceNumber, kCANPeriod);
+	/* enable close loop */
+	SetClosedLoopControl(1);
+}
+/* PCM D'tor
+ */
+PCM::~PCM()
+{
+
+}
+
+/* Set PCM solenoid state
+ *
+ * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
+ *
+ * @Param 	-	idx			- 	ID of solenoid (0-7)
+ * @Param 	-	en			- 	Enable / Disable identified solenoid
+ */
+CTR_Code PCM::SetSolenoid(unsigned char idx, bool en)
+{
+	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
+	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
+	if (en)
+		toFill->solenoidBits |= (1ul << (idx));
+	else
+		toFill->solenoidBits &= ~(1ul << (idx));
+	FlushTx(toFill);
+	return CTR_OKAY;
+}
+
+/* Set all PCM solenoid states
+ *
+ * @Return	-	CTR_Code	-	Error code (if any) for setting solenoids
+ * @Param 	-	state			Bitfield to set all solenoids to
+ */
+CTR_Code PCM::SetAllSolenoids(UINT8 state) {
+	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
+	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
+	toFill->solenoidBits = state;
+	FlushTx(toFill);
+	return CTR_OKAY;
+}
+
+/* Clears PCM sticky faults (indicators of past faults
+ *
+ * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
+ *
+ * @Param 	-	clr		- 	Clear / do not clear faults
+ */
+CTR_Code PCM::ClearStickyFaults()
+{
+	int32_t status = 0;
+	uint8_t pcmSupplemControl[] = { 0, 0, 0, 0x80 }; /* only bit set is ClearStickyFaults */
+	FRC_NetworkCommunication_CANSessionMux_sendMessage(CONTROL_2  | GetDeviceNumber(), pcmSupplemControl, sizeof(pcmSupplemControl), 0, &status);
+	if(status)
+		return CTR_TxFailed;
+	return CTR_OKAY;
+}
+
+/* Enables PCM Closed Loop Control of Compressor via pressure switch
+ *
+ * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
+ *
+ * @Param 	-	en		- 	Enable / Disable Closed Loop Control
+ */
+CTR_Code PCM::SetClosedLoopControl(bool en)
+{
+	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
+	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
+	toFill->closedLoopEnable = en;
+	FlushTx(toFill);
+	return CTR_OKAY;
+}
+/* Get solenoid Blacklist status
+ * @Return	-	CTR_Code	-	Error code (if any)
+ * @Param	-	idx			-	ID of solenoid [0,7] to fire one shot pulse.
+ */
+CTR_Code PCM::FireOneShotSolenoid(UINT8 idx)
+{
+	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
+	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
+	/* grab field as it is now */
+	uint16_t oneShotField;
+	oneShotField = toFill->OneShotField_h8;
+	oneShotField <<= 8;
+	oneShotField |= toFill->OneShotField_l8;
+	/* get the caller's channel */
+	uint16_t shift = 2*idx;
+	uint16_t mask = 3; /* two bits wide */
+	uint8_t chBits = (oneShotField >> shift) & mask;
+	/* flip it */
+	chBits = (chBits)%3 + 1;
+	/* clear out 2bits for this channel*/
+	oneShotField &= ~(mask << shift);
+	/* put new field in */
+	oneShotField |= chBits << shift;
+	/* apply field as it is now */
+	toFill->OneShotField_h8 = oneShotField >> 8;
+	toFill->OneShotField_l8 = oneShotField;
+	FlushTx(toFill);
+	return CTR_OKAY;
+}
+/* Configure the pulse width of a solenoid channel for one-shot pulse.
+ * Preprogrammed pulsewidth is 10ms resolution and can be between 10ms and
+ * 2.55s.
+ *
+ * @Return	-	CTR_Code	-	Error code (if any)
+ * @Param	-	idx			-	ID of solenoid [0,7] to configure.
+ * @Param	-	durMs		-	pulse width in ms.
+ */
+CTR_Code PCM::SetOneShotDurationMs(UINT8 idx,uint32_t durMs)
+{
+	/* sanity check caller's param */
+	if(idx > 7)
+		return CTR_InvalidParamValue;
+	/* get latest tx frame */
+	CtreCanNode::txTask<PcmControlSetOneShotDur_t> toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
+	if(toFill.IsEmpty()){
+		/* only send this out if caller wants to do one-shots */
+		RegisterTx(CONTROL_3 | _deviceNumber, kCANPeriod);
+		/* grab it */
+		toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
+	}
+	toFill->sol10MsPerUnit[idx] = std::min(durMs/10,(uint32_t)0xFF);
+	/* apply the new data bytes */
+	FlushTx(toFill);
+	return CTR_OKAY;
+}
+
+/* Get solenoid state
+ *
+ * @Return	-	True/False	-	True if solenoid enabled, false otherwise
+ *
+ * @Param 	-	idx		- 	ID of solenoid (0-7) to return status of
+ */
+CTR_Code PCM::GetSolenoid(UINT8 idx, bool &status)
+{
+	GET_PCM_STATUS();
+	status = (rx->SolenoidBits & (1ul<<(idx)) ) ? 1 : 0;
+	return rx.err;
+}
+
+/* Get solenoid state for all solenoids on the PCM
+ *
+ * @Return	-	Bitfield of solenoid states
+ */
+CTR_Code PCM::GetAllSolenoids(UINT8 &status)
+{
+	GET_PCM_STATUS();
+	status = rx->SolenoidBits;
+	return rx.err;
+}
+
+/* Get pressure switch state
+ *
+ * @Return	-	True/False	-	True if pressure adequate, false if low
+ */
+CTR_Code PCM::GetPressure(bool &status)
+{
+	GET_PCM_STATUS();
+	status = (rx->pressureSwitchEn ) ? 1 : 0;
+	return rx.err;
+}
+
+/* Get compressor state
+ *
+ * @Return	-	True/False	-	True if enabled, false if otherwise
+ */
+CTR_Code PCM::GetCompressor(bool &status)
+{
+	GET_PCM_STATUS();
+	status = (rx->compressorOn);
+	return rx.err;
+}
+
+/* Get closed loop control state
+ *
+ * @Return	-	True/False	-	True if closed loop enabled, false if otherwise
+ */
+CTR_Code PCM::GetClosedLoopControl(bool &status)
+{
+	GET_PCM_STATUS();
+	status = (rx->isCloseloopEnabled);
+	return rx.err;
+}
+
+/* Get compressor current draw
+ *
+ * @Return	-	Amperes	-	Compressor current
+ */
+CTR_Code PCM::GetCompressorCurrent(float &status)
+{
+	GET_PCM_STATUS();
+	uint32_t temp =(rx->compressorCurrentTop6);
+	temp <<= 4;
+	temp |=  rx->compressorCurrentBtm4;
+	status = temp * 0.03125; /* 5.5 fixed pt value in Amps */
+	return rx.err;
+}
+
+/* Get voltage across solenoid rail
+ *
+ * @Return	-	Volts	-	Voltage across solenoid rail
+ */
+CTR_Code PCM::GetSolenoidVoltage(float &status)
+{
+	GET_PCM_STATUS();
+	uint32_t raw =(rx->solenoidVoltageTop8);
+	raw <<= 2;
+	raw |=  rx->solenoidVoltageBtm2;
+	status = (double) raw * 0.03125; /* 5.5 fixed pt value in Volts */
+	return rx.err;
+}
+
+/* Get hardware fault value
+ *
+ * @Return	-	True/False	-	True if hardware failure detected, false if otherwise
+ */
+CTR_Code PCM::GetHardwareFault(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->faultHardwareFailure;
+	return rx.err;
+}
+
+/* Get compressor fault value
+ *
+ * @Return	-	True/False	-	True if shorted compressor detected, false if otherwise
+ */
+CTR_Code PCM::GetCompressorCurrentTooHighFault(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->faultCompCurrentTooHigh;
+	return rx.err;
+}
+CTR_Code PCM::GetCompressorShortedStickyFault(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->StickyFault_dItooHigh;
+	return rx.err;
+}
+CTR_Code PCM::GetCompressorShortedFault(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->Fault_dItooHigh;
+	return rx.err;
+}
+CTR_Code PCM::GetCompressorNotConnectedStickyFault(bool &status)
+{
+	GET_PCM_SOL_FAULTS();
+	status = rx->StickyFault_CompNoCurrent;
+	return rx.err;
+}
+CTR_Code PCM::GetCompressorNotConnectedFault(bool &status)
+{
+	GET_PCM_SOL_FAULTS();
+	status = rx->Fault_CompNoCurrent;
+	return rx.err;
+}
+
+/* Get solenoid fault value
+ *
+ * @Return	-	True/False	-	True if shorted solenoid detected, false if otherwise
+ */
+CTR_Code PCM::GetSolenoidFault(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->faultFuseTripped;
+	return rx.err;
+}
+
+/* Get compressor sticky fault value
+ *
+ * @Return	-	True/False	-	True if solenoid had previously been shorted
+ * 								(and sticky fault was not cleared), false if otherwise
+ */
+CTR_Code PCM::GetCompressorCurrentTooHighStickyFault(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->stickyFaultCompCurrentTooHigh;
+	return rx.err;
+}
+
+/* Get solenoid sticky fault value
+ *
+ * @Return	-	True/False	-	True if compressor had previously been shorted
+ * 								(and sticky fault was not cleared), false if otherwise
+ */
+CTR_Code PCM::GetSolenoidStickyFault(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->stickyFaultFuseTripped;
+	return rx.err;
+}
+/* Get battery voltage
+ *
+ * @Return	-	Volts	-	Voltage across PCM power ports
+ */
+CTR_Code PCM::GetBatteryVoltage(float &status)
+{
+	GET_PCM_STATUS();
+	status = (float)rx->battVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
+	return rx.err;
+}
+/* Return status of module enable/disable
+ *
+ * @Return	-	bool		-	Returns TRUE if PCM is enabled, FALSE if disabled
+ */
+CTR_Code PCM::isModuleEnabled(bool &status)
+{
+	GET_PCM_STATUS();
+	status = rx->moduleEnabled;
+	return rx.err;
+}
+/* Get number of total failed PCM Control Frame
+ *
+ * @Return	-	Failed Control Frames	-	Number of failed control frames (tokenization fails)
+ *
+ * @WARNING	-	Return only valid if [SeekDebugFrames] is enabled
+ * 				See function SeekDebugFrames
+ * 				See function EnableSeekDebugFrames
+ */
+CTR_Code PCM::GetNumberOfFailedControlFrames(UINT16 &status)
+{
+	GET_PCM_DEBUG();
+	status = rx->tokFailsTop8;
+	status <<= 8;
+	status |= rx->tokFailsBtm8;
+	return rx.err;
+}
+/* Get raw Solenoid Blacklist
+ *
+ * @Return	-	BINARY	-	Raw binary breakdown of Solenoid Blacklist
+ * 							BIT7 = Solenoid 1, BIT6 = Solenoid 2, etc.
+ *
+ * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
+ * 				See function SeekStatusFaultFrames
+ * 				See function EnableSeekStatusFaultFrames
+ */
+CTR_Code PCM::GetSolenoidBlackList(UINT8 &status)
+{
+	GET_PCM_SOL_FAULTS();
+	status = rx->SolenoidBlacklist;
+	return rx.err;
+}
+/* Get solenoid Blacklist status
+ * - Blacklisted solenoids cannot be enabled until PCM is power cycled
+ *
+ * @Return	-	True/False	-	True if Solenoid is blacklisted, false if otherwise
+ *
+ * @Param	-	idx			-	ID of solenoid [0,7]
+ *
+ * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
+ * 				See function SeekStatusFaultFrames
+ * 				See function EnableSeekStatusFaultFrames
+ */
+CTR_Code PCM::IsSolenoidBlacklisted(UINT8 idx, bool &status)
+{
+	GET_PCM_SOL_FAULTS();
+	status = (rx->SolenoidBlacklist & (1ul<<(idx)) )? 1 : 0;
+	return rx.err;
+}
+//------------------ C interface --------------------------------------------//
+extern "C" {
+	void * c_PCM_Init(void) {
+		return new PCM();
+	}
+	CTR_Code c_SetSolenoid(void * handle, unsigned char idx, INT8 param) {
+		return ((PCM*) handle)->SetSolenoid(idx, param);
+	}
+	CTR_Code c_SetAllSolenoids(void * handle, UINT8 state) {
+		return ((PCM*) handle)->SetAllSolenoids(state);
+	}
+	CTR_Code c_SetClosedLoopControl(void * handle, INT8 param) {
+		return ((PCM*) handle)->SetClosedLoopControl(param);
+	}
+	CTR_Code c_ClearStickyFaults(void * handle, INT8 param) {
+		return ((PCM*) handle)->ClearStickyFaults();
+	}
+	CTR_Code c_GetSolenoid(void * handle, UINT8 idx, INT8 * status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetSolenoid(idx, bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetAllSolenoids(void * handle, UINT8 * status) {
+		return ((PCM*) handle)->GetAllSolenoids(*status);
+	}
+	CTR_Code c_GetPressure(void * handle, INT8 * status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetPressure(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetCompressor(void * handle, INT8 * status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetCompressor(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetClosedLoopControl(void * handle, INT8 * status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetClosedLoopControl(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetCompressorCurrent(void * handle, float * status) {
+		CTR_Code retval = ((PCM*) handle)->GetCompressorCurrent(*status);
+		return retval;
+	}
+	CTR_Code c_GetSolenoidVoltage(void * handle, float*status) {
+		return ((PCM*) handle)->GetSolenoidVoltage(*status);
+	}
+	CTR_Code c_GetHardwareFault(void * handle, INT8*status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetHardwareFault(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetCompressorFault(void * handle, INT8*status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighFault(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetSolenoidFault(void * handle, INT8*status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetSolenoidFault(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetCompressorStickyFault(void * handle, INT8*status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighStickyFault(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetSolenoidStickyFault(void * handle, INT8*status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->GetSolenoidStickyFault(bstatus);
+		*status = bstatus;
+		return retval;
+	}
+	CTR_Code c_GetBatteryVoltage(void * handle, float*status) {
+		CTR_Code retval = ((PCM*) handle)->GetBatteryVoltage(*status);
+		return retval;
+	}
+	void c_SetDeviceNumber_PCM(void * handle, UINT8 deviceNumber) {
+	}
+	CTR_Code c_GetNumberOfFailedControlFrames(void * handle, UINT16*status) {
+		return ((PCM*) handle)->GetNumberOfFailedControlFrames(*status);
+	}
+	CTR_Code c_GetSolenoidBlackList(void * handle, UINT8 *status) {
+		return ((PCM*) handle)->GetSolenoidBlackList(*status);
+	}
+	CTR_Code c_IsSolenoidBlacklisted(void * handle, UINT8 idx, INT8*status) {
+		bool bstatus;
+		CTR_Code retval = ((PCM*) handle)->IsSolenoidBlacklisted(idx, bstatus);
+		*status = bstatus;
+		return retval;
+	}
+}
diff --git a/hal/src/main/native/athena/ctre/PCM.h b/hal/src/main/native/athena/ctre/PCM.h
new file mode 100644
index 0000000..b485219
--- /dev/null
+++ b/hal/src/main/native/athena/ctre/PCM.h
@@ -0,0 +1,226 @@
+#ifndef PCM_H_
+#define PCM_H_
+#include "ctre.h"				//BIT Defines + Typedefs
+#include "CtreCanNode.h"
+class PCM : public CtreCanNode
+{
+public:
+    PCM(UINT8 deviceNumber=0);
+    ~PCM();
+
+    /* Set PCM solenoid state
+     *
+     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
+     * @Param 	-	idx			- 	ID of solenoid (0-7)
+     * @Param 	-	en			- 	Enable / Disable identified solenoid
+     */
+    CTR_Code 	SetSolenoid(unsigned char idx, bool en);
+
+    /* Set all PCM solenoid states
+     *
+     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoids
+     * @Param 	-	state			Bitfield to set all solenoids to
+     */
+    CTR_Code 	SetAllSolenoids(UINT8 state);
+
+    /* Enables PCM Closed Loop Control of Compressor via pressure switch
+     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
+     * @Param 	-	en		- 	Enable / Disable Closed Loop Control
+     */
+    CTR_Code 	SetClosedLoopControl(bool en);
+
+    /* Clears PCM sticky faults (indicators of past faults
+     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
+     */
+    CTR_Code 	ClearStickyFaults();
+
+    /* Get solenoid state
+     *
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param 	-	idx		- 	ID of solenoid (0-7) to return if solenoid is on.
+     * @Param	-	status	-	true if solenoid enabled, false otherwise
+     */
+    CTR_Code 	GetSolenoid(UINT8 idx, bool &status);
+
+    /* Get state of all solenoids
+     *
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status	-	bitfield of solenoid states
+     */
+    CTR_Code 	GetAllSolenoids(UINT8 &status);
+
+    /* Get pressure switch state
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if pressure adequate, false if low
+     */
+    CTR_Code 	GetPressure(bool &status);
+
+    /* Get compressor state
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if compress ouput is on, false if otherwise
+     */
+    CTR_Code	GetCompressor(bool &status);
+
+    /* Get closed loop control state
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status	-	True if closed loop enabled, false if otherwise
+     */
+    CTR_Code 	GetClosedLoopControl(bool &status);
+
+    /* Get compressor current draw
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	Compressor current returned in Amperes (A)
+     */
+    CTR_Code 	GetCompressorCurrent(float &status);
+
+    /* Get voltage across solenoid rail
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	Voltage across solenoid rail in Volts (V)
+     */
+    CTR_Code 	GetSolenoidVoltage(float &status);
+
+    /* Get hardware fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if hardware failure detected, false if otherwise
+     */
+    CTR_Code 	GetHardwareFault(bool &status);
+
+    /* Get compressor fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if abnormally high compressor current detected, false if otherwise
+     */
+    CTR_Code 	GetCompressorCurrentTooHighFault(bool &status);
+
+    /* Get solenoid fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if shorted solenoid detected, false if otherwise
+     */
+    CTR_Code 	GetSolenoidFault(bool &status);
+
+    /* Get compressor sticky fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if solenoid had previously been shorted
+     * 								(and sticky fault was not cleared), false if otherwise
+     */
+    CTR_Code 	GetCompressorCurrentTooHighStickyFault(bool &status);
+    /* Get compressor shorted sticky fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if compressor output is shorted, false if otherwise
+     */
+    CTR_Code 	GetCompressorShortedStickyFault(bool &status);
+    /* Get compressor shorted fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if compressor output is shorted, false if otherwise
+     */
+    CTR_Code 	GetCompressorShortedFault(bool &status);
+    /* Get compressor is not connected sticky fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if compressor current is too low,
+     * 					indicating compressor is not connected, false if otherwise
+     */
+    CTR_Code 	GetCompressorNotConnectedStickyFault(bool &status);
+    /* Get compressor is not connected fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if compressor current is too low,
+     * 					indicating compressor is not connected, false if otherwise
+     */
+    CTR_Code 	GetCompressorNotConnectedFault(bool &status);
+
+    /* Get solenoid sticky fault value
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	True if compressor had previously been shorted
+     * 								(and sticky fault was not cleared), false if otherwise
+     */
+    CTR_Code 	GetSolenoidStickyFault(bool &status);
+
+    /* Get battery voltage
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	Voltage across PCM power ports in Volts (V)
+     */
+    CTR_Code 	GetBatteryVoltage(float &status);
+
+    /* Set PCM Device Number and according CAN frame IDs
+     * @Return	-	void
+     * @Param	-	deviceNumber	-	Device number of PCM to control
+     */
+    void	SetDeviceNumber(UINT8 deviceNumber);
+    /* Get number of total failed PCM Control Frame
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	Number of failed control frames (tokenization fails)
+     * @WARNING	-	Return only valid if [SeekDebugFrames] is enabled
+     * 				See function SeekDebugFrames
+     * 				See function EnableSeekDebugFrames
+     */
+	CTR_Code GetNumberOfFailedControlFrames(UINT16 &status);
+
+    /* Get raw Solenoid Blacklist
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	Raw binary breakdown of Solenoid Blacklist
+     * 								BIT7 = Solenoid 1, BIT6 = Solenoid 2, etc.
+     * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
+     * 				See function SeekStatusFaultFrames
+     * 				See function EnableSeekStatusFaultFrames
+     */
+    CTR_Code 	GetSolenoidBlackList(UINT8 &status);
+
+    /* Get solenoid Blacklist status
+     * - Blacklisted solenoids cannot be enabled until PCM is power cycled
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	idx			-	ID of solenoid [0,7]
+     * @Param	-	status		-	True if Solenoid is blacklisted, false if otherwise
+     * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
+     * 				See function SeekStatusFaultFrames
+     * 				See function EnableSeekStatusFaultFrames
+     */
+    CTR_Code 	IsSolenoidBlacklisted(UINT8 idx, bool &status);
+
+    /* Return status of module enable/disable
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	status		-	Returns TRUE if PCM is enabled, FALSE if disabled
+     */
+    CTR_Code	isModuleEnabled(bool &status);
+
+    /* Get solenoid Blacklist status
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	idx			-	ID of solenoid [0,7] to fire one shot pulse.
+     */
+    CTR_Code FireOneShotSolenoid(UINT8 idx);
+
+    /* Configure the pulse width of a solenoid channel for one-shot pulse.
+	 * Preprogrammed pulsewidth is 10ms resolute and can be between 20ms and 5.1s.
+     * @Return	-	CTR_Code	-	Error code (if any)
+     * @Param	-	idx			-	ID of solenoid [0,7] to configure.
+     * @Param	-	durMs		-	pulse width in ms.
+     */
+    CTR_Code SetOneShotDurationMs(UINT8 idx,uint32_t durMs);
+
+};
+//------------------ C interface --------------------------------------------//
+extern "C" {
+	void * c_PCM_Init(void);
+	CTR_Code c_SetSolenoid(void * handle,unsigned char idx,INT8 param);
+	CTR_Code c_SetAllSolenoids(void * handle,UINT8 state);
+	CTR_Code c_SetClosedLoopControl(void * handle,INT8 param);
+	CTR_Code c_ClearStickyFaults(void * handle,INT8 param);
+	CTR_Code c_GetSolenoid(void * handle,UINT8 idx,INT8 * status);
+	CTR_Code c_GetAllSolenoids(void * handle,UINT8 * status);
+	CTR_Code c_GetPressure(void * handle,INT8 * status);
+	CTR_Code c_GetCompressor(void * handle,INT8 * status);
+	CTR_Code c_GetClosedLoopControl(void * handle,INT8 * status);
+	CTR_Code c_GetCompressorCurrent(void * handle,float * status);
+	CTR_Code c_GetSolenoidVoltage(void * handle,float*status);
+	CTR_Code c_GetHardwareFault(void * handle,INT8*status);
+	CTR_Code c_GetCompressorFault(void * handle,INT8*status);
+	CTR_Code c_GetSolenoidFault(void * handle,INT8*status);
+	CTR_Code c_GetCompressorStickyFault(void * handle,INT8*status);
+	CTR_Code c_GetSolenoidStickyFault(void * handle,INT8*status);
+	CTR_Code c_GetBatteryVoltage(void * handle,float*status);
+	void c_SetDeviceNumber_PCM(void * handle,UINT8 deviceNumber);
+	void c_EnableSeekStatusFrames(void * handle,INT8 enable);
+	void c_EnableSeekStatusFaultFrames(void * handle,INT8 enable);
+	void c_EnableSeekDebugFrames(void * handle,INT8 enable);
+	CTR_Code c_GetNumberOfFailedControlFrames(void * handle,UINT16*status);
+	CTR_Code c_GetSolenoidBlackList(void * handle,UINT8 *status);
+	CTR_Code c_IsSolenoidBlacklisted(void * handle,UINT8 idx,INT8*status);
+}
+#endif
diff --git a/hal/src/main/native/athena/ctre/ctre.h b/hal/src/main/native/athena/ctre/ctre.h
new file mode 100644
index 0000000..90d33c1
--- /dev/null
+++ b/hal/src/main/native/athena/ctre/ctre.h
@@ -0,0 +1,55 @@
+/**
+ * @file ctre.h
+ * Common header for all CTRE HAL modules.
+ */
+#ifndef CTRE_H
+#define CTRE_H
+
+//Bit Defines
+#define BIT0 0x01
+#define BIT1 0x02
+#define BIT2 0x04
+#define BIT3 0x08
+#define BIT4 0x10
+#define BIT5 0x20
+#define BIT6 0x40
+#define BIT7 0x80
+#define BIT8  0x0100
+#define BIT9  0x0200
+#define BIT10 0x0400
+#define BIT11 0x0800
+#define BIT12 0x1000
+#define BIT13 0x2000
+#define BIT14 0x4000
+#define BIT15 0x8000
+
+//Signed
+typedef	signed char	INT8;
+typedef	signed short	INT16;
+typedef	signed int	INT32;
+typedef	signed long long INT64;
+
+//Unsigned
+typedef	unsigned char	UINT8;
+typedef	unsigned short	UINT16;
+typedef	unsigned int	UINT32;
+typedef	unsigned long long UINT64;
+
+//Other
+typedef	unsigned char	UCHAR;
+typedef unsigned short	USHORT;
+typedef	unsigned int	UINT;
+typedef unsigned long	ULONG;
+
+typedef enum {
+		CTR_OKAY,				//!< No Error - Function executed as expected
+		CTR_RxTimeout,			//!< CAN frame has not been received within specified period of time.
+		CTR_TxTimeout,			//!< Not used.
+		CTR_InvalidParamValue, 	//!< Caller passed an invalid param
+		CTR_UnexpectedArbId,	//!< Specified CAN Id is invalid.
+		CTR_TxFailed,			//!< Could not transmit the CAN frame.
+		CTR_SigNotUpdated,		//!< Have not received an value response for signal.
+		CTR_BufferFull,			//!< Caller attempted to insert data into a buffer that is full.
+}CTR_Code;
+
+#endif /* CTRE_H */
diff --git a/hal/src/main/native/athena/frccansae/CANDeviceInterface.h b/hal/src/main/native/athena/frccansae/CANDeviceInterface.h
new file mode 100644
index 0000000..8fe4235
--- /dev/null
+++ b/hal/src/main/native/athena/frccansae/CANDeviceInterface.h
@@ -0,0 +1,156 @@
+#ifndef __CAN_DEVICE_INTERFACE_H__
+#define __CAN_DEVICE_INTERFACE_H__
+
+#define MAX_STRING_LEN 64
+
+#define SUPPORT_UNIQUE_ID	(1) /* depends entirely on old vs new build */
+#define USE_NTH_ORDER		(0) /* zero to user deviceId */
+#define SUPPORT_MOTOR_CONTROLLER_PROFILE	(1)
+namespace CANDeviceInterface1
+{
+
+struct PIDSlot
+{
+	// Proportional gain
+	float pGain;
+	// Integral gain
+	float iGain;
+	// Differential gain
+	float dGain;
+	// Feed-forward gain
+	float fGain;
+	// Integral zone
+	float iZone;
+	// Closed-loop ramp rate
+	float clRampRate;
+};
+
+struct DeviceDescriptor
+{
+   // The full device ID, including the device number, manufacturer, and device type.
+   // The mask of a message the device supports is 0x1FFF003F.
+   unsigned int deviceID;
+#if SUPPORT_UNIQUE_ID != 0
+   // This is the ID that uniquely identifies the device node in the UI.
+   // The purpose of this is to be able to track the device across renames or deviceID changes.
+   unsigned int uniqueID;
+#endif
+   // An dynamically assigned ID that will make setting deviceIDs robust,
+   //  Never again will you need to isolate a CAN node just to fix it's ID.
+   unsigned int dynamicID;
+   // User visible name.  This can be customized by the user, but should have a
+   // reasonable default.
+   char name[MAX_STRING_LEN];
+   // This is a user visible model name that should match the can_devices.ini section.
+   char model[MAX_STRING_LEN];
+   // This is a version number that represents the version of firmware currently
+   // installed on the device.
+   char currentVersion[MAX_STRING_LEN];
+   // Hardware revision.
+   char hardwareRev[MAX_STRING_LEN];
+   // Bootloader version.  Will not change for the life of the product, but additional
+   // field upgrade features could be added in newer hardware.
+   char bootloaderRev[MAX_STRING_LEN];
+   // Manufacture Date.  Could be a calender date or just the FRC season year.
+   // Also helps troubleshooting "old ones" vs "new ones".
+   char manufactureDate[MAX_STRING_LEN];
+   // General status of the hardware.  For example if the device is in bootloader
+   // due to a bad flash UI could emphasize that.
+   char softwareStatus[MAX_STRING_LEN];
+   // Is the LED currently on?
+   bool led;
+	// Reserved fields for future use by CTRE.  Not touched by frccansae
+   unsigned int dynFlags;
+   unsigned int flags; 		/* bitfield */
+   unsigned int ptrToString;
+   //unsigned int reserved0;
+   //unsigned int reserved1;
+   //unsigned int reserved2;
+#if SUPPORT_MOTOR_CONTROLLER_PROFILE != 0
+	// Motor controller properties (ignored if SupportsMotorControllerProperties is false or unset for this model)
+	unsigned int brakeMode; // 0=Coast, 1=Brake
+	unsigned int limitSwitchFwdMode; // 0=disabled, 1=Normally Closed, 2=Normally Open
+	unsigned int limitSwitchRevMode; // 0=disabled, 1=Normally Closed, 2=Normally Open
+	// Limit-switch soft limits
+	bool bFwdSoftLimitEnable;
+	bool bRevSoftLimitEnable;
+	float softLimitFwd;
+	float softLimitRev;
+	// PID constants for slot 0
+	struct PIDSlot slot0;
+	// PID constants for slot 1
+	struct PIDSlot slot1;
+#endif
+};
+
+#define kLimitSwitchMode_Disabled		(0)
+#define kLimitSwitchMode_NormallyClosed	(1)
+#define kLimitSwitchMode_NormallyOpen	(2)
+
+// Interface functions that must be implemented by the CAN Firmware Update Library
+
+// Returns the number of devices that will be returned in a call to
+// getListOfDevices().  The calling library will use this info to allocate enough
+// memory to accept all device info.
+int getNumberOfDevices();
+
+// Return info about discovered devices.  The array of structs should be
+// populated before returning.  The numDescriptors input describes how many
+// elements were allocated to prevent memory corruption.  The number of devices
+// populated should be returned from this function as well.
+int getListOfDevices(DeviceDescriptor *devices, int numDescriptors);
+
+// When the user requests to update the firmware of a device a thread will be
+// spawned and this function is called from that thread.  This function should
+// complete the firmware update process before returning.  The image
+// contents and size are directly from the file selected by the user.  The
+// error message string can be filled with a NULL-terminated message to show the
+// user if there was a problem updating firmware.  The error message is only
+// displayed if a non-zero value is returned from this function.
+int updateFirmware(const DeviceDescriptor *device, const unsigned char *imageContents, unsigned int imageSize, char *errorMessage, int errorMessageMaxSize);
+
+// This function is called periodically from the UI thread while the firmware
+// update is in progress.  The percentComplete parameter should the filled in
+// with the current progress of the firmware update process to update a progress
+// bar in the UI.
+void checkUpdateProgress(const DeviceDescriptor *device, int *percentComplete);
+
+// This is called when the user selects a new ID to assign on the bus and
+// chooses to save.  The newDeviceID is really just the device number. The
+// manufacturer and device type will remain unchanged.  If a problem is detected
+// when assigning a new ID, this function should return a non-zero value.
+int assignBroadcastDeviceID(unsigned int newDeviceID);
+// The device descriptor should be updated with the new device ID.  The name may
+// also change in the descriptor and will be updated in the UI immediately.
+// Be sure to modify the descriptor first since the refresh from the UI is
+// asynchronous.
+int assignDeviceID(DeviceDescriptor *device, unsigned int newDeviceID);
+
+// This entry-point will get called when the user chooses to change the value
+// of the device's LED.  This will allow the user to identify devices which
+// support dynamic addresses or are otherwise unknown.  If this function returns
+// a non-zero value, the UI will report an error.
+int saveLightLed(const DeviceDescriptor *device, bool newLEDStatus);
+
+// This entry-point will get called when the user chooses to change the alias
+// of the device with the device specified.  If this function returns a non-
+// zero value, the UI will report an error.  The device descriptor must be
+// updated with the new name that was selected. If a different name is saved
+// to the descriptor than the user specified, this will require a manual
+// refresh by the user.  This is reported as CAR #505139
+int saveDeviceName(DeviceDescriptor *device, const char *newName);
+
+// This entry-point will get called when the user changes any of the motor
+// controller specific properties. If this function returns a non-zero value,
+// the UI will report an error.  The device descriptor may be updated with
+// coerced values.
+int saveMotorParameters(DeviceDescriptor *device);
+
+// Run some sort of self-test functionality on the device.  This can be anything
+// and the results will be displayed to the user.  A non-zero return value
+// indicates an error.
+int selfTest(const DeviceDescriptor *device, char *detailedResults, int detailedResultsMaxSize);
+
+} /* CANDeviceInterface */
+
+#endif /* __CAN_DEVICE_INTERFACE_H__ */
diff --git a/hal/src/main/native/athena/visa/visa.h b/hal/src/main/native/athena/visa/visa.h
new file mode 100644
index 0000000..3c6ad30
--- /dev/null
+++ b/hal/src/main/native/athena/visa/visa.h
@@ -0,0 +1,1064 @@
+/*---------------------------------------------------------------------------*/
+/* 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
new file mode 100644
index 0000000..ef089dd
--- /dev/null
+++ b/hal/src/main/native/athena/visa/visatype.h
@@ -0,0 +1,201 @@
+/*---------------------------------------------------------------------------*/
+/* 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/cpp/fpga_clock.cpp b/hal/src/main/native/cpp/cpp/fpga_clock.cpp
new file mode 100644
index 0000000..751eae1
--- /dev/null
+++ b/hal/src/main/native/cpp/cpp/fpga_clock.cpp
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/cpp/fpga_clock.h"
+
+#include <wpi/raw_ostream.h>
+
+#include "hal/HAL.h"
+
+namespace hal {
+const fpga_clock::time_point fpga_clock::min_time =
+    fpga_clock::time_point(fpga_clock::duration(
+        std::numeric_limits<fpga_clock::duration::rep>::min()));
+
+fpga_clock::time_point fpga_clock::now() noexcept {
+  int32_t status = 0;
+  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";
+    wpi::errs().flush();
+    return epoch();
+  }
+  return time_point(std::chrono::microseconds(currentTime));
+}
+}  // namespace hal
diff --git a/hal/src/main/native/cpp/handles/HandlesInternal.cpp b/hal/src/main/native/cpp/handles/HandlesInternal.cpp
new file mode 100644
index 0000000..45ffb31
--- /dev/null
+++ b/hal/src/main/native/cpp/handles/HandlesInternal.cpp
@@ -0,0 +1,95 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/handles/HandlesInternal.h"
+
+#include <algorithm>
+
+#include <wpi/SmallVector.h>
+#include <wpi/mutex.h>
+
+namespace hal {
+static wpi::SmallVector<HandleBase*, 32>* globalHandles = nullptr;
+static wpi::mutex globalHandleMutex;
+HandleBase::HandleBase() {
+  static wpi::SmallVector<HandleBase*, 32> gH;
+  std::lock_guard<wpi::mutex> lock(globalHandleMutex);
+  if (!globalHandles) {
+    globalHandles = &gH;
+  }
+
+  auto index = std::find(globalHandles->begin(), globalHandles->end(), this);
+  if (index == globalHandles->end()) {
+    globalHandles->push_back(this);
+  } else {
+    *index = this;
+  }
+}
+HandleBase::~HandleBase() {
+  std::lock_guard<wpi::mutex> lock(globalHandleMutex);
+  auto index = std::find(globalHandles->begin(), globalHandles->end(), this);
+  if (index != globalHandles->end()) {
+    *index = nullptr;
+  }
+}
+void HandleBase::ResetHandles() {
+  m_version++;
+  if (m_version > 255) {
+    m_version = 0;
+  }
+}
+void HandleBase::ResetGlobalHandles() {
+  std::unique_lock<wpi::mutex> lock(globalHandleMutex);
+  for (auto&& i : *globalHandles) {
+    if (i != nullptr) {
+      lock.unlock();
+      i->ResetHandles();
+      lock.lock();
+    }
+  }
+}
+HAL_PortHandle createPortHandle(uint8_t channel, uint8_t module) {
+  // set last 8 bits, then shift to first 8 bits
+  HAL_PortHandle handle = static_cast<HAL_PortHandle>(HAL_HandleEnum::Port);
+  handle = handle << 24;
+  // shift module and add to 3rd set of 8 bits
+  int32_t temp = module;
+  temp = (temp << 8) & 0xff00;
+  handle += temp;
+  // add channel to last 8 bits
+  handle += channel;
+  return handle;
+}
+HAL_PortHandle createPortHandleForSPI(uint8_t channel) {
+  // set last 8 bits, then shift to first 8 bits
+  HAL_PortHandle handle = static_cast<HAL_PortHandle>(HAL_HandleEnum::Port);
+  handle = handle << 16;
+  // set second set up bits to 1
+  int32_t temp = 1;
+  temp = (temp << 8) & 0xff00;
+  handle += temp;
+  // shift to last set of bits
+  handle = handle << 8;
+  // add channel to last 8 bits
+  handle += channel;
+  return handle;
+}
+HAL_Handle createHandle(int16_t index, HAL_HandleEnum handleType,
+                        int16_t version) {
+  if (index < 0) return HAL_kInvalidHandle;
+  uint8_t hType = static_cast<uint8_t>(handleType);
+  if (hType == 0 || hType > 127) return HAL_kInvalidHandle;
+  // set last 8 bits, then shift to first 8 bits
+  HAL_Handle handle = hType;
+  handle = handle << 8;
+  handle += static_cast<uint8_t>(version);
+  handle = handle << 16;
+  // add index to set last 16 bits
+  handle += index;
+  return handle;
+}
+}  // namespace hal
diff --git a/hal/src/main/native/cpp/jni/AccelerometerJNI.cpp b/hal/src/main/native/cpp/jni/AccelerometerJNI.cpp
new file mode 100644
index 0000000..6d0d256
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/AccelerometerJNI.cpp
@@ -0,0 +1,75 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "edu_wpi_first_hal_AccelerometerJNI.h"
+#include "hal/Accelerometer.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_AccelerometerJNI
+ * Method:    setAccelerometerActive
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_AccelerometerJNI_setAccelerometerActive
+  (JNIEnv*, jclass, jboolean active)
+{
+  HAL_SetAccelerometerActive(active);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AccelerometerJNI
+ * Method:    setAccelerometerRange
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_AccelerometerJNI_setAccelerometerRange
+  (JNIEnv*, jclass, jint range)
+{
+  HAL_SetAccelerometerRange((HAL_AccelerometerRange)range);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AccelerometerJNI
+ * Method:    getAccelerometerX
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_AccelerometerJNI_getAccelerometerX
+  (JNIEnv*, jclass)
+{
+  return HAL_GetAccelerometerX();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AccelerometerJNI
+ * Method:    getAccelerometerY
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_AccelerometerJNI_getAccelerometerY
+  (JNIEnv*, jclass)
+{
+  return HAL_GetAccelerometerY();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AccelerometerJNI
+ * Method:    getAccelerometerZ
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_AccelerometerJNI_getAccelerometerZ
+  (JNIEnv*, jclass)
+{
+  return HAL_GetAccelerometerZ();
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
new file mode 100644
index 0000000..74c1b49
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
@@ -0,0 +1,248 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#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
+ * Method:    initializeAnalogGyro
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    setupAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    freeAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    setAnalogGyroParameters
+ * Signature: (IDDI)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    setAnalogGyroVoltsPerDegreePerSecond
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    resetAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    calibrateAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    setAnalogGyroDeadband
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroAngle
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroRate
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroOffset
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroCenter
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/AnalogJNI.cpp b/hal/src/main/native/cpp/jni/AnalogJNI.cpp
new file mode 100644
index 0000000..3b2aa2d
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/AnalogJNI.cpp
@@ -0,0 +1,722 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_AnalogJNI.h"
+#include "hal/AnalogAccumulator.h"
+#include "hal/AnalogInput.h"
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    initializeAnalogInputPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    freeAnalogInputPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    initializeAnalogOutputPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    freeAnalogOutputPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_AnalogJNI_freeAnalogOutputPort
+  (JNIEnv* env, jclass, jint id)
+{
+  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << id;
+  HAL_FreeAnalogOutputPort((HAL_AnalogOutputHandle)id);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    checkAnalogModule
+ * Signature: (B)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    checkAnalogInputChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    checkAnalogOutputChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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:    setAnalogOutput
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogOutput
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_AnalogJNI_getAnalogOutput
+  (JNIEnv* env, jclass, jint id)
+{
+  int32_t status = 0;
+  double val = HAL_GetAnalogOutput((HAL_AnalogOutputHandle)id, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogSampleRate
+ * Signature: (D)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogSampleRate
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_AnalogJNI_getAnalogSampleRate
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double returnValue = HAL_GetAnalogSampleRate(&status);
+  ANALOGJNI_LOG(logDEBUG) << "Status = " << status;
+  ANALOGJNI_LOG(logDEBUG) << "SampleRate = " << returnValue;
+  CheckStatus(env, status);
+  return returnValue;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogAverageBits
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogAverageBits
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogOversampleBits
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogOversampleBits
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogValue
+ * Signature: (I)S
+ */
+JNIEXPORT jshort JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogAverageValue
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogVoltsToValue
+ * Signature: (ID)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogAverageVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogLSBWeight
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogOffset
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    isAccumulatorChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    initAccumulator
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    resetAccumulator
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAccumulatorCenter
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAccumulatorDeadband
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAccumulatorValue
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAccumulatorCount
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAccumulatorOutput
+ * Signature: (ILjava/lang/Object;)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    initializeAnalogTrigger
+ * Signature: (ILjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    cleanAnalogTrigger
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogTriggerLimitsRaw
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+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);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogTriggerLimitsVoltage
+ * Signature: (IDD)V
+ */
+JNIEXPORT void JNICALL
+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);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogTriggerAveraged
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    setAnalogTriggerFiltered
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogTriggerInWindow
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogTriggerTriggerState
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogTriggerOutput
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+  CheckStatus(env, status);
+  return val;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/CANAPIJNI.cpp b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
new file mode 100644
index 0000000..bcb285c
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
@@ -0,0 +1,241 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include <wpi/SmallString.h>
+#include <wpi/jni_util.h>
+#include <wpi/raw_ostream.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_CANAPIJNI.h"
+#include "hal/CAN.h"
+#include "hal/CANAPI.h"
+#include "hal/Errors.h"
+#include "hal/cpp/Log.h"
+
+using namespace frc;
+using namespace wpi::java;
+
+extern "C" {
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    initializeCAN
+ * Signature: (III)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_initializeCAN
+  (JNIEnv* env, jclass, jint manufacturer, jint deviceId, jint deviceType)
+{
+  int32_t status = 0;
+  auto handle =
+      HAL_InitializeCAN(static_cast<HAL_CANManufacturer>(manufacturer),
+                        static_cast<int32_t>(deviceId),
+                        static_cast<HAL_CANDeviceType>(deviceType), &status);
+
+  CheckStatusForceThrow(env, status);
+  return handle;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    cleanCAN
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_cleanCAN
+  (JNIEnv* env, jclass, jint handle)
+{
+  HAL_CleanCAN(static_cast<HAL_CANHandle>(handle));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    writeCANPacket
+ * Signature: (I[BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacket
+  (JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId)
+{
+  auto halHandle = static_cast<HAL_CANHandle>(handle);
+  JByteArrayRef arr{env, data};
+  auto arrRef = arr.array();
+  int32_t status = 0;
+  HAL_WriteCANPacket(halHandle, reinterpret_cast<const uint8_t*>(arrRef.data()),
+                     arrRef.size(), apiId, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    writeCANPacketRepeating
+ * Signature: (I[BII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketRepeating
+  (JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId,
+   jint timeoutMs)
+{
+  auto halHandle = static_cast<HAL_CANHandle>(handle);
+  JByteArrayRef arr{env, data};
+  auto arrRef = arr.array();
+  int32_t status = 0;
+  HAL_WriteCANPacketRepeating(halHandle,
+                              reinterpret_cast<const uint8_t*>(arrRef.data()),
+                              arrRef.size(), apiId, timeoutMs, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    stopCANPacketRepeating
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_stopCANPacketRepeating
+  (JNIEnv* env, jclass, jint handle, jint apiId)
+{
+  auto halHandle = static_cast<HAL_CANHandle>(handle);
+  int32_t status = 0;
+  HAL_StopCANPacketRepeating(halHandle, apiId, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    readCANPacketNew
+ * Signature: (IILjava/lang/Object;)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_readCANPacketNew
+  (JNIEnv* env, jclass, jint handle, jint apiId, 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_ReadCANPacketNew(halHandle, apiId, dataTemp, &dataLength, &timestamp,
+                       &status);
+  if (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    readCANPacketLatest
+ * Signature: (IILjava/lang/Object;)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_readCANPacketLatest
+  (JNIEnv* env, jclass, jint handle, jint apiId, 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_ReadCANPacketLatest(halHandle, apiId, dataTemp, &dataLength, &timestamp,
+                          &status);
+  if (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CANAPIJNI
+ * Method:    readCANPacketTimeout
+ * Signature: (IIILjava/lang/Object;)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CANAPIJNI_readCANPacketTimeout
+  (JNIEnv* env, jclass, jint handle, jint apiId, jint timeoutMs, 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_ReadCANPacketTimeout(halHandle, apiId, dataTemp, &dataLength, &timestamp,
+                           timeoutMs, &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;
+}
+
+/*
+ * 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
new file mode 100644
index 0000000..0f46d15
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/CANJNI.cpp
@@ -0,0 +1,158 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include <wpi/SmallString.h>
+#include <wpi/jni_util.h>
+#include <wpi/raw_ostream.h>
+
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_can_CANJNI
+ * Method:    FRCNetCommCANSessionMuxSendMessage
+ * Signature: (I[BI)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_can_CANJNI
+ * Method:    FRCNetCommCANSessionMuxReceiveMessage
+ * Signature: (Ljava/lang/Object;ILjava/lang/Object;)[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_edu_wpi_first_hal_can_CANJNI_FRCNetCommCANSessionMuxReceiveMessage
+  (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 =
+      reinterpret_cast<uint32_t*>(env->GetDirectBufferAddress(timeStamp));
+
+  uint8_t dataSize = 0;
+  uint8_t buffer[8];
+
+  int32_t status = 0;
+  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),
+                                       static_cast<size_t>(dataSize)});
+}
+
+/*
+ * Class:     edu_wpi_first_hal_can_CANJNI
+ * Method:    GetCANStatus
+ * Signature: (Ljava/lang/Object;)V
+ */
+JNIEXPORT void JNICALL
+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;
+  uint32_t receiveErrorCount = 0;
+  uint32_t transmitErrorCount = 0;
+  int32_t status = 0;
+  HAL_CAN_GetCANStatus(&percentBusUtilization, &busOffCount, &txFullCount,
+                       &receiveErrorCount, &transmitErrorCount, &status);
+
+  if (!CheckStatus(env, status)) return;
+
+  SetCanStatusObject(env, canStatus, percentBusUtilization, busOffCount,
+                     txFullCount, receiveErrorCount, transmitErrorCount);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/CompressorJNI.cpp b/hal/src/main/native/cpp/jni/CompressorJNI.cpp
new file mode 100644
index 0000000..e38abb5
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/CompressorJNI.cpp
@@ -0,0 +1,234 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_CompressorJNI.h"
+#include "hal/Compressor.h"
+#include "hal/Ports.h"
+#include "hal/Solenoid.h"
+#include "hal/cpp/Log.h"
+
+using namespace frc;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    initializeCompressor
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_initializeCompressor
+  (JNIEnv* env, jclass, jbyte module)
+{
+  int32_t status = 0;
+  auto handle = HAL_InitializeCompressor(module, &status);
+  CheckStatusRange(env, status, 0, HAL_GetNumPCMModules(), module);
+
+  return (jint)handle;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    checkCompressorModule
+ * Signature: (B)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_checkCompressorModule
+  (JNIEnv* env, jclass, jbyte module)
+{
+  return HAL_CheckCompressorModule(module);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressor
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressor
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressor((HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    setCompressorClosedLoopControl
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_setCompressorClosedLoopControl
+  (JNIEnv* env, jclass, jint compressorHandle, jboolean value)
+{
+  int32_t status = 0;
+  HAL_SetCompressorClosedLoopControl((HAL_CompressorHandle)compressorHandle,
+                                     value, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorClosedLoopControl
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorClosedLoopControl
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorClosedLoopControl(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorPressureSwitch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorPressureSwitch
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorPressureSwitch(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorCurrent
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  double val =
+      HAL_GetCompressorCurrent((HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorCurrentTooHighFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorCurrentTooHighFault
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorCurrentTooHighFault(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorCurrentTooHighStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorCurrentTooHighStickyFault
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorCurrentTooHighStickyFault(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorShortedStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorShortedStickyFault
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorShortedStickyFault(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorShortedFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorShortedFault
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorShortedFault(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorNotConnectedStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorNotConnectedStickyFault
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorNotConnectedStickyFault(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    getCompressorNotConnectedFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_getCompressorNotConnectedFault
+  (JNIEnv* env, jclass, jint compressorHandle)
+{
+  int32_t status = 0;
+  bool val = HAL_GetCompressorNotConnectedFault(
+      (HAL_CompressorHandle)compressorHandle, &status);
+  CheckStatus(env, status);
+  return val;
+}
+/*
+ * Class:     edu_wpi_first_hal_CompressorJNI
+ * Method:    clearAllPCMStickyFaults
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CompressorJNI_clearAllPCMStickyFaults
+  (JNIEnv* env, jclass, jbyte module)
+{
+  int32_t status = 0;
+  HAL_ClearAllPCMStickyFaults(static_cast<int32_t>(module), &status);
+  CheckStatus(env, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/ConstantsJNI.cpp b/hal/src/main/native/cpp/jni/ConstantsJNI.cpp
new file mode 100644
index 0000000..3db8f5a
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/ConstantsJNI.cpp
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#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
+ * Method:    getSystemClockTicksPerMicrosecond
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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
new file mode 100644
index 0000000..70ec5be
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/CounterJNI.cpp
@@ -0,0 +1,476 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include "HALUtil.h"
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    initializeCounter
+ * Signature: (ILjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    freeCounter
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterAverageSize
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterUpSource
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CounterJNI_setCounterUpSource
+  (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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterUpSourceEdge
+ * Signature: (IZZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    clearCounterUpSource
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterDownSource
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CounterJNI_setCounterDownSource
+  (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 "
+                                  "TwoPulse and ExternalDirection modes.");
+    return;
+  }
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterDownSourceEdge
+ * Signature: (IZZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    clearCounterDownSource
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterUpDownMode
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterExternalDirectionMode
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterSemiPeriodMode
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterPulseLengthMode
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    getCounterSamplesToAverage
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterSamplesToAverage
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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;
+  }
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    resetCounter
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    getCounter
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    getCounterPeriod
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterMaxPeriod
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterUpdateWhenEmpty
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    getCounterStopped
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    getCounterDirection
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CounterJNI
+ * Method:    setCounterReverseDirection
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/DIOJNI.cpp b/hal/src/main/native/cpp/jni/DIOJNI.cpp
new file mode 100644
index 0000000..e21edcf
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/DIOJNI.cpp
@@ -0,0 +1,319 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_DIOJNI.h"
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    initializeDIOPort
+ * Signature: (IZ)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    checkDIOChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    freeDIOPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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:    setDIO
+ * Signature: (IS)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    setDIODirection
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    getDIO
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    getDIODirection
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    pulse
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    isPulsing
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    isAnyPulsing
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    getLoopTiming
+ * Signature: ()S
+ */
+JNIEXPORT jshort JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    allocateDigitalPWM
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    freeDigitalPWM
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    setDigitalPWMRate
+ * Signature: (D)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    setDigitalPWMDutyCycle
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DIOJNI
+ * Method:    setDigitalPWMOutputChannel
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/DigitalGlitchFilterJNI.cpp b/hal/src/main/native/cpp/jni/DigitalGlitchFilterJNI.cpp
new file mode 100644
index 0000000..3e39ac0
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/DigitalGlitchFilterJNI.cpp
@@ -0,0 +1,78 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_DigitalGlitchFilterJNI.h"
+#include "hal/DIO.h"
+
+using namespace frc;
+
+/*
+ * Class:     edu_wpi_first_hal_DigitalGlitchFilterJNI
+ * Method:    setFilterSelect
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DigitalGlitchFilterJNI_setFilterSelect
+  (JNIEnv* env, jclass, jint id, jint filter_index)
+{
+  int32_t status = 0;
+
+  HAL_SetFilterSelect(static_cast<HAL_DigitalHandle>(id), filter_index,
+                      &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DigitalGlitchFilterJNI
+ * Method:    getFilterSelect
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_DigitalGlitchFilterJNI_getFilterSelect
+  (JNIEnv* env, jclass, jint id)
+{
+  int32_t status = 0;
+
+  jint result =
+      HAL_GetFilterSelect(static_cast<HAL_DigitalHandle>(id), &status);
+  CheckStatus(env, status);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DigitalGlitchFilterJNI
+ * Method:    setFilterPeriod
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DigitalGlitchFilterJNI_setFilterPeriod
+  (JNIEnv* env, jclass, jint filter_index, jint fpga_cycles)
+{
+  int32_t status = 0;
+
+  HAL_SetFilterPeriod(filter_index, fpga_cycles, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DigitalGlitchFilterJNI
+ * Method:    getFilterPeriod
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_DigitalGlitchFilterJNI_getFilterPeriod
+  (JNIEnv* env, jclass, jint filter_index)
+{
+  int32_t status = 0;
+
+  jint result = HAL_GetFilterPeriod(filter_index, &status);
+  CheckStatus(env, status);
+  return result;
+}
diff --git a/hal/src/main/native/cpp/jni/EncoderJNI.cpp b/hal/src/main/native/cpp/jni/EncoderJNI.cpp
new file mode 100644
index 0000000..10c4332
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/EncoderJNI.cpp
@@ -0,0 +1,488 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include "HALUtil.h"
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    initializeEncoder
+ * Signature: (IIIIZI)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_EncoderJNI_initializeEncoder
+  (JNIEnv* env, jclass, jint digitalSourceHandleA, jint analogTriggerTypeA,
+   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,
+      (HAL_AnalogTriggerType)analogTriggerTypeA,
+      (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    freeEncoder
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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:    getEncoder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderRaw
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncodingScaleFactor
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    resetEncoder
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderPeriod
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    setEncoderMaxPeriod
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderStopped
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderDirection
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderDistance
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderRate
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    setEncoderMinRate
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    setEncoderDistancePerPulse
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    setEncoderReverseDirection
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    setEncoderSamplesToAverage
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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;
+  }
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderSamplesToAverage
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    setEncoderIndexSource
+ * Signature: (IIII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_EncoderJNI_setEncoderIndexSource
+  (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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderFPGAIndex
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderEncodingScale
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderDecodingScaleFactor
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderDistancePerPulse
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_EncoderJNI
+ * Method:    getEncoderEncodingType
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/HAL.cpp b/hal/src/main/native/cpp/jni/HAL.cpp
new file mode 100644
index 0000000..cc5f7cf
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/HAL.cpp
@@ -0,0 +1,482 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/HAL.h"
+
+#include <jni.h>
+
+#include <cassert>
+#include <cstring>
+
+#include <wpi/jni_util.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_HAL.h"
+#include "hal/DriverStation.h"
+#include "hal/cpp/Log.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" {
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    initialize
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_HAL_initialize
+  (JNIEnv*, jclass, jint timeout, jint mode)
+{
+  return HAL_Initialize(timeout, mode);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    observeUserProgramStarting
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_observeUserProgramStarting
+  (JNIEnv*, jclass)
+{
+  HAL_ObserveUserProgramStarting();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    observeUserProgramDisabled
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_observeUserProgramDisabled
+  (JNIEnv*, jclass)
+{
+  HAL_ObserveUserProgramDisabled();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    observeUserProgramAutonomous
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_observeUserProgramAutonomous
+  (JNIEnv*, jclass)
+{
+  HAL_ObserveUserProgramAutonomous();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    observeUserProgramTeleop
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_observeUserProgramTeleop
+  (JNIEnv*, jclass)
+{
+  HAL_ObserveUserProgramTeleop();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    observeUserProgramTest
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_observeUserProgramTest
+  (JNIEnv*, jclass)
+{
+  HAL_ObserveUserProgramTest();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    report
+ * Signature: (IIILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HAL_report
+  (JNIEnv* paramEnv, jclass, jint paramResource, jint paramInstanceNumber,
+   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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    nativeGetControlWord
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+  std::memset(&controlWord, 0, sizeof(HAL_ControlWord));
+  HAL_GetControlWord(&controlWord);
+  jint retVal = 0;
+  std::memcpy(&retVal, &controlWord, sizeof(HAL_ControlWord));
+  return retVal;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    nativeGetAllianceStation
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getJoystickAxes
+ * Signature: (B[F)S
+ */
+JNIEXPORT jshort JNICALL
+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);
+
+  jsize javaSize = env->GetArrayLength(axesArray);
+  if (axes.count > javaSize) {
+    wpi::SmallString<128> errStr;
+    wpi::raw_svector_ostream oss{errStr};
+    oss << "Native array size larger then passed in java array size "
+        << "Native Size: " << static_cast<int>(axes.count)
+        << " Java Size: " << static_cast<int>(javaSize);
+
+    ThrowIllegalArgumentException(env, errStr.str());
+    return 0;
+  }
+
+  env->SetFloatArrayRegion(axesArray, 0, axes.count, axes.axes);
+
+  return axes.count;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getJoystickPOVs
+ * Signature: (B[S)S
+ */
+JNIEXPORT jshort JNICALL
+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);
+
+  jsize javaSize = env->GetArrayLength(povsArray);
+  if (povs.count > javaSize) {
+    wpi::SmallString<128> errStr;
+    wpi::raw_svector_ostream oss{errStr};
+    oss << "Native array size larger then passed in java array size "
+        << "Native Size: " << static_cast<int>(povs.count)
+        << " Java Size: " << static_cast<int>(javaSize);
+
+    ThrowIllegalArgumentException(env, errStr.str());
+    return 0;
+  }
+
+  env->SetShortArrayRegion(povsArray, 0, povs.count, povs.povs);
+
+  return povs.count;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getJoystickButtons
+ * Signature: (BLjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    setJoystickOutputs
+ * Signature: (BISS)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HAL_setJoystickOutputs
+  (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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getJoystickIsXbox
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HAL_getJoystickIsXbox
+  (JNIEnv*, jclass, jbyte port)
+{
+  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickIsXbox";
+  return HAL_GetJoystickIsXbox(port);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getJoystickType
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HAL_getJoystickType
+  (JNIEnv*, jclass, jbyte port)
+{
+  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickType";
+  return HAL_GetJoystickType(port);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getJoystickName
+ * Signature: (B)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+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);
+  return str;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getJoystickAxisType
+ * Signature: (BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HAL_getJoystickAxisType
+  (JNIEnv*, jclass, jbyte joystickNum, jbyte axis)
+{
+  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickAxisType";
+  return HAL_GetJoystickAxisType(joystickNum, axis);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    isNewControlData
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_HAL_isNewControlData
+  (JNIEnv*, jclass)
+{
+  return static_cast<jboolean>(HAL_IsNewControlData());
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    waitForDSData
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_waitForDSData
+  (JNIEnv* env, jclass)
+{
+  HAL_WaitForDSData();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    releaseDSMutex
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_releaseDSMutex
+  (JNIEnv* env, jclass)
+{
+  HAL_ReleaseDSMutex();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    waitForDSDataTimeout
+ * Signature: (D)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_HAL_waitForDSDataTimeout
+  (JNIEnv*, jclass, jdouble timeout)
+{
+  return static_cast<jboolean>(HAL_WaitForDSDataTimeout(timeout));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getMatchTime
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_HAL_getMatchTime
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  return HAL_GetMatchTime(&status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getSystemActive
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_HAL_getSystemActive
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  bool val = HAL_GetSystemActive(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getBrownedOut
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_HAL_getBrownedOut
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  bool val = HAL_GetBrownedOut(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getMatchInfo
+ * Signature: (Ljava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HAL_getMatchInfo
+  (JNIEnv* env, jclass, jobject info)
+{
+  HAL_MatchInfo matchInfo;
+  auto status = HAL_GetMatchInfo(&matchInfo);
+  if (status == 0) {
+    SetMatchInfoObject(env, info, matchInfo);
+  }
+  return status;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    sendError
+ * Signature: (ZIZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HAL_sendError
+  (JNIEnv* env, jclass, jboolean isError, jint errorCode, jboolean isLVCode,
+   jstring details, jstring location, jstring callStack, jboolean printMsg)
+{
+  JStringRef detailsStr{env, details};
+  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);
+  return returnValue;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getPortWithModule
+ * Signature: (BB)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    getPort
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/HALUtil.cpp b/hal/src/main/native/cpp/jni/HALUtil.cpp
new file mode 100644
index 0000000..72eb22c
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/HALUtil.cpp
@@ -0,0 +1,469 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HALUtil.h"
+
+#include <jni.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+#include <wpi/SmallString.h>
+#include <wpi/jni_util.h>
+#include <wpi/raw_ostream.h>
+
+#include "edu_wpi_first_hal_HALUtil.h"
+#include "hal/CAN.h"
+#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)
+#define kRIOStatusOperationTimedOut -52007
+#define kRIOStatusFeatureNotSupported (kRioStatusOffset - 193)
+#define kRIOStatusResourceNotInitialized -52010
+
+static JavaVM* jvm = nullptr;
+static JException illegalArgExCls;
+static JException boundaryExCls;
+static JException allocationExCls;
+static JException halHandleExCls;
+static JException canInvalidBufferExCls;
+static JException canMessageNotFoundExCls;
+static JException canMessageNotAllowedExCls;
+static JException canNotInitializedExCls;
+static JException uncleanStatusExCls;
+static JClass pwmConfigDataResultCls;
+static JClass canStatusCls;
+static JClass matchInfoDataCls;
+static JClass accumulatorResultCls;
+static JClass canDataCls;
+
+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}};
+
+static const JExceptionInit exceptions[] = {
+    {"java/lang/IllegalArgumentException", &illegalArgExCls},
+    {"edu/wpi/first/hal/util/BoundaryException", &boundaryExCls},
+    {"edu/wpi/first/hal/util/AllocationException", &allocationExCls},
+    {"edu/wpi/first/hal/util/HalHandleException", &halHandleExCls},
+    {"edu/wpi/first/hal/can/CANInvalidBufferException", &canInvalidBufferExCls},
+    {"edu/wpi/first/hal/can/CANMessageNotFoundException",
+     &canMessageNotFoundExCls},
+    {"edu/wpi/first/hal/can/CANMessageNotAllowedException",
+     &canMessageNotAllowedExCls},
+    {"edu/wpi/first/hal/can/CANNotInitializedException",
+     &canNotInitializedExCls},
+    {"edu/wpi/first/hal/util/UncleanStatusException", &uncleanStatusExCls}};
+
+namespace frc {
+
+void ThrowUncleanStatusException(JNIEnv* env, wpi::StringRef msg,
+                                 int32_t status) {
+  static jmethodID func =
+      env->GetMethodID(uncleanStatusExCls, "<init>", "(ILjava/lang/String;)V");
+
+  jobject exception =
+      env->NewObject(uncleanStatusExCls, func, static_cast<jint>(status),
+                     MakeJString(env, msg));
+  env->Throw(static_cast<jthrowable>(exception));
+}
+
+void ThrowAllocationException(JNIEnv* env, int32_t minRange, int32_t maxRange,
+                              int32_t requestedValue, int32_t status) {
+  const char* message = HAL_GetErrorMessage(status);
+  wpi::SmallString<1024> buf;
+  wpi::raw_svector_ostream oss(buf);
+  oss << " Code: " << status << ". " << message
+      << ", Minimum Value: " << minRange << ", Maximum Value: " << maxRange
+      << ", Requested Value: " << requestedValue;
+  env->ThrowNew(allocationExCls, buf.c_str());
+  allocationExCls.Throw(env, buf.c_str());
+}
+
+void ThrowHalHandleException(JNIEnv* env, int32_t status) {
+  const char* message = HAL_GetErrorMessage(status);
+  wpi::SmallString<1024> buf;
+  wpi::raw_svector_ostream oss(buf);
+  oss << " Code: " << status << ". " << message;
+  halHandleExCls.Throw(env, buf.c_str());
+}
+
+void ReportError(JNIEnv* env, int32_t status, bool doThrow) {
+  if (status == 0) return;
+  if (status == HAL_HANDLE_ERROR) {
+    ThrowHalHandleException(env, status);
+  }
+  const char* message = HAL_GetErrorMessage(status);
+  if (doThrow && status < 0) {
+    wpi::SmallString<1024> buf;
+    wpi::raw_svector_ostream oss(buf);
+    oss << " Code: " << status << ". " << message;
+    ThrowUncleanStatusException(env, buf.c_str(), status);
+  } else {
+    std::string func;
+    auto stack = GetJavaStackTrace(env, &func, "edu.wpi.first.wpilibj");
+    HAL_SendError(1, status, 0, message, func.c_str(), stack.c_str(), 1);
+  }
+}
+
+void ThrowError(JNIEnv* env, int32_t status, int32_t minRange, int32_t maxRange,
+                int32_t requestedValue) {
+  if (status == 0) return;
+  if (status == NO_AVAILABLE_RESOURCES || status == RESOURCE_IS_ALLOCATED ||
+      status == RESOURCE_OUT_OF_RANGE) {
+    ThrowAllocationException(env, minRange, maxRange, requestedValue, status);
+  }
+  if (status == HAL_HANDLE_ERROR) {
+    ThrowHalHandleException(env, status);
+  }
+  const char* message = HAL_GetErrorMessage(status);
+  wpi::SmallString<1024> buf;
+  wpi::raw_svector_ostream oss(buf);
+  oss << " Code: " << status << ". " << message;
+  ThrowUncleanStatusException(env, buf.c_str(), status);
+}
+
+void ReportCANError(JNIEnv* env, int32_t status, int message_id) {
+  if (status >= 0) return;
+  switch (status) {
+    case kRioStatusSuccess:
+      // Everything is ok... don't throw.
+      break;
+    case HAL_ERR_CANSessionMux_InvalidBuffer:
+    case kRIOStatusBufferInvalidSize: {
+      static jmethodID invalidBufConstruct = nullptr;
+      if (!invalidBufConstruct)
+        invalidBufConstruct =
+            env->GetMethodID(canInvalidBufferExCls, "<init>", "()V");
+      jobject exception =
+          env->NewObject(canInvalidBufferExCls, invalidBufConstruct);
+      env->Throw(static_cast<jthrowable>(exception));
+      break;
+    }
+    case HAL_ERR_CANSessionMux_MessageNotFound:
+    case kRIOStatusOperationTimedOut: {
+      static jmethodID messageNotFoundConstruct = nullptr;
+      if (!messageNotFoundConstruct)
+        messageNotFoundConstruct =
+            env->GetMethodID(canMessageNotFoundExCls, "<init>", "()V");
+      jobject exception =
+          env->NewObject(canMessageNotFoundExCls, messageNotFoundConstruct);
+      env->Throw(static_cast<jthrowable>(exception));
+      break;
+    }
+    case HAL_ERR_CANSessionMux_NotAllowed:
+    case kRIOStatusFeatureNotSupported: {
+      wpi::SmallString<100> buf;
+      wpi::raw_svector_ostream oss(buf);
+      oss << "MessageID = " << message_id;
+      canMessageNotAllowedExCls.Throw(env, buf.c_str());
+      break;
+    }
+    case HAL_ERR_CANSessionMux_NotInitialized:
+    case kRIOStatusResourceNotInitialized: {
+      static jmethodID notInitConstruct = nullptr;
+      if (!notInitConstruct)
+        notInitConstruct =
+            env->GetMethodID(canNotInitializedExCls, "<init>", "()V");
+      jobject exception =
+          env->NewObject(canNotInitializedExCls, notInitConstruct);
+      env->Throw(static_cast<jthrowable>(exception));
+      break;
+    }
+    default: {
+      wpi::SmallString<100> buf;
+      wpi::raw_svector_ostream oss(buf);
+      oss << "Fatal status code detected: " << status;
+      uncleanStatusExCls.Throw(env, buf.c_str());
+      break;
+    }
+  }
+}
+
+void ThrowIllegalArgumentException(JNIEnv* env, wpi::StringRef msg) {
+  illegalArgExCls.Throw(env, msg);
+}
+
+void ThrowBoundaryException(JNIEnv* env, double value, double lower,
+                            double upper) {
+  static jmethodID getMessage = nullptr;
+  if (!getMessage)
+    getMessage = env->GetStaticMethodID(boundaryExCls, "getMessage",
+                                        "(DDD)Ljava/lang/String;");
+
+  static jmethodID constructor = nullptr;
+  if (!constructor)
+    constructor =
+        env->GetMethodID(boundaryExCls, "<init>", "(Ljava/lang/String;)V");
+
+  jobject msg = env->CallStaticObjectMethod(
+      boundaryExCls, getMessage, static_cast<jdouble>(value),
+      static_cast<jdouble>(lower), static_cast<jdouble>(upper));
+  jobject ex = env->NewObject(boundaryExCls, constructor, msg);
+  env->Throw(static_cast<jthrowable>(ex));
+}
+
+jobject CreatePWMConfigDataResult(JNIEnv* env, int32_t maxPwm,
+                                  int32_t deadbandMaxPwm, int32_t centerPwm,
+                                  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);
+}
+
+void SetCanStatusObject(JNIEnv* env, jobject canStatus,
+                        float percentBusUtilization, uint32_t busOffCount,
+                        uint32_t txFullCount, uint32_t receiveErrorCount,
+                        uint32_t transmitErrorCount) {
+  static jmethodID func =
+      env->GetMethodID(canStatusCls, "setStatus", "(DIIII)V");
+  env->CallVoidMethod(canStatus, func, (jdouble)percentBusUtilization,
+                      (jint)busOffCount, (jint)txFullCount,
+                      (jint)receiveErrorCount, (jint)transmitErrorCount);
+}
+
+void SetMatchInfoObject(JNIEnv* env, jobject matchStatus,
+                        const HAL_MatchInfo& matchInfo) {
+  static jmethodID func =
+      env->GetMethodID(matchInfoDataCls, "setData",
+                       "(Ljava/lang/String;Ljava/lang/String;III)V");
+
+  env->CallVoidMethod(
+      matchStatus, func, MakeJString(env, matchInfo.eventName),
+      MakeJString(env, wpi::StringRef{reinterpret_cast<const char*>(
+                                          matchInfo.gameSpecificMessage),
+                                      matchInfo.gameSpecificMessageSize}),
+      (jint)matchInfo.matchNumber, (jint)matchInfo.replayNumber,
+      (jint)matchInfo.matchType);
+}
+
+void SetAccumulatorResultObject(JNIEnv* env, jobject accumulatorResult,
+                                int64_t value, int64_t count) {
+  static jmethodID func =
+      env->GetMethodID(accumulatorResultCls, "set", "(JJ)V");
+
+  env->CallVoidMethod(accumulatorResult, func, (jlong)value, (jlong)count);
+}
+
+jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
+                            uint64_t timestamp) {
+  static jmethodID func = env->GetMethodID(canDataCls, "setData", "(IJ)[B");
+
+  jbyteArray retVal = static_cast<jbyteArray>(
+      env->CallObjectMethod(canData, func, (jint)length, (jlong)timestamp));
+  return retVal;
+}
+
+JavaVM* GetJVM() { return jvm; }
+
+}  // namespace frc
+
+namespace sim {
+jint SimOnLoad(JavaVM* vm, void* reserved);
+void SimOnUnload(JavaVM* vm, void* reserved);
+}  // namespace sim
+
+using namespace frc;
+
+extern "C" {
+
+//
+// indicate JNI version support desired and load classes
+//
+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;
+
+  for (auto& c : classes) {
+    *c.cls = JClass(env, c.name);
+    if (!*c.cls) return JNI_ERR;
+  }
+
+  for (auto& c : exceptions) {
+    *c.cls = JException(env, c.name);
+    if (!*c.cls) return JNI_ERR;
+  }
+
+  return sim::SimOnLoad(vm, reserved);
+}
+
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
+  sim::SimOnUnload(vm, reserved);
+
+  JNIEnv* env;
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
+    return;
+  // Delete global references
+
+  for (auto& c : classes) {
+    c.cls->free(env);
+  }
+  for (auto& c : exceptions) {
+    c.cls->free(env);
+  }
+  jvm = nullptr;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getFPGAVersion
+ * Signature: ()S
+ */
+JNIEXPORT jshort JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getFPGARevision
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getFPGATime
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getHALRuntimeType
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getFPGAButton
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getHALErrorMessage
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_edu_wpi_first_hal_HALUtil_getHALErrorMessage
+  (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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getHALErrno
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_HALUtil_getHALErrno
+  (JNIEnv*, jclass)
+{
+  return errno;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HALUtil
+ * Method:    getHALstrerror
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_edu_wpi_first_hal_HALUtil_getHALstrerror
+  (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);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/HALUtil.h b/hal/src/main/native/cpp/jni/HALUtil.h
new file mode 100644
index 0000000..8197e1a
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/HALUtil.h
@@ -0,0 +1,74 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#ifndef HAL_HAL_SRC_MAIN_NATIVE_CPP_JNI_HALUTIL_H_
+#define HAL_HAL_SRC_MAIN_NATIVE_CPP_JNI_HALUTIL_H_
+
+#include <jni.h>
+#include <stdint.h>
+
+#include <wpi/StringRef.h>
+
+struct HAL_MatchInfo;
+
+namespace frc {
+
+void ReportError(JNIEnv* env, int32_t status, bool doThrow = true);
+
+void ThrowError(JNIEnv* env, int32_t status, int32_t minRange, int32_t maxRange,
+                int32_t requestedValue);
+
+inline bool CheckStatus(JNIEnv* env, int32_t status, bool doThrow = true) {
+  if (status != 0) ReportError(env, status, doThrow);
+  return status == 0;
+}
+
+inline bool CheckStatusRange(JNIEnv* env, int32_t status, int32_t minRange,
+                             int32_t maxRange, int32_t requestedValue) {
+  if (status != 0) ThrowError(env, status, minRange, maxRange, requestedValue);
+  return status == 0;
+}
+
+inline bool CheckStatusForceThrow(JNIEnv* env, int32_t status) {
+  if (status != 0) ThrowError(env, status, 0, 0, 0);
+  return status == 0;
+}
+
+void ReportCANError(JNIEnv* env, int32_t status, int32_t message_id);
+
+inline bool CheckCANStatus(JNIEnv* env, int32_t status, int32_t message_id) {
+  if (status != 0) ReportCANError(env, status, message_id);
+  return status == 0;
+}
+
+void ThrowIllegalArgumentException(JNIEnv* env, wpi::StringRef msg);
+void ThrowBoundaryException(JNIEnv* env, double value, double lower,
+                            double upper);
+
+jobject CreatePWMConfigDataResult(JNIEnv* env, int32_t maxPwm,
+                                  int32_t deadbandMaxPwm, int32_t centerPwm,
+                                  int32_t deadbandMinPwm, int32_t minPwm);
+
+void SetCanStatusObject(JNIEnv* env, jobject canStatus,
+                        float percentBusUtilization, uint32_t busOffCount,
+                        uint32_t txFullCount, uint32_t receiveErrorCount,
+                        uint32_t transmitErrorCount);
+
+void SetMatchInfoObject(JNIEnv* env, jobject matchStatus,
+                        const HAL_MatchInfo& matchInfo);
+
+void SetAccumulatorResultObject(JNIEnv* env, jobject accumulatorResult,
+                                int64_t value, int64_t count);
+
+jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
+                            uint64_t timestamp);
+
+JavaVM* GetJVM();
+
+}  // namespace frc
+
+#endif  // HAL_HAL_SRC_MAIN_NATIVE_CPP_JNI_HALUTIL_H_
diff --git a/hal/src/main/native/cpp/jni/I2CJNI.cpp b/hal/src/main/native/cpp/jni/I2CJNI.cpp
new file mode 100644
index 0000000..9dafd4a
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/I2CJNI.cpp
@@ -0,0 +1,221 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include <wpi/jni_util.h>
+
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CInitialize
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CTransaction
+ * Signature: (IBLjava/lang/Object;BLjava/lang/Object;B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_I2CJNI_i2CTransaction
+  (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CTransactionB
+ * Signature: (IB[BB[BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_I2CJNI_i2CTransactionB
+  (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*>(
+                             JByteArrayRef(env, dataToSend).array().data()),
+                         sendSize, recvBuf.data(), receiveSize);
+  env->SetByteArrayRegion(dataReceived, 0, receiveSize,
+                          reinterpret_cast<const jbyte*>(recvBuf.data()));
+  I2CJNI_LOG(logDEBUG) << "ReturnValue = " << returnValue;
+  return returnValue;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CWrite
+ * Signature: (IBLjava/lang/Object;B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_I2CJNI_i2CWrite
+  (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CWriteB
+ * Signature: (IB[BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_I2CJNI_i2CWriteB
+  (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CRead
+ * Signature: (IBLjava/lang/Object;B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_I2CJNI_i2CRead
+  (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CReadB
+ * Signature: (IB[BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_I2CJNI_i2CReadB
+  (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_I2CJNI
+ * Method:    i2CClose
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_I2CJNI_i2CClose
+  (JNIEnv*, jclass, jint port)
+{
+  I2CJNI_LOG(logDEBUG) << "Calling I2CJNI i2CClose";
+  HAL_CloseI2C(static_cast<HAL_I2CPort>(port));
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/InterruptJNI.cpp b/hal/src/main/native/cpp/jni/InterruptJNI.cpp
new file mode 100644
index 0000000..2dd4abf
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/InterruptJNI.cpp
@@ -0,0 +1,375 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <atomic>
+#include <cassert>
+#include <thread>
+
+#include <wpi/SafeThread.h>
+#include <wpi/mutex.h>
+
+#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
+// invocation, which is both time inefficient and causes issues with Eclipse
+// (which tries to keep a thread list up-to-date and thus gets swamped).
+//
+// Instead, this class attaches just once.  When a hardware notification
+// occurs, a condition variable wakes up this thread and this thread actually
+// makes the call into Java.
+//
+// We don't want to use a FIFO here. If the user code takes too long to
+// process, we will just ignore the redundant wakeup.
+class InterruptThreadJNI : public wpi::SafeThread {
+ public:
+  void Main();
+
+  bool m_notify = false;
+  uint32_t m_mask = 0;
+  jobject m_func = nullptr;
+  jmethodID m_mid;
+  jobject m_param = nullptr;
+};
+
+class InterruptJNI : public wpi::SafeThreadOwner<InterruptThreadJNI> {
+ public:
+  void SetFunc(JNIEnv* env, jobject func, jmethodID mid, jobject param);
+
+  void Notify(uint32_t mask) {
+    auto thr = GetThread();
+    if (!thr) return;
+    thr->m_notify = true;
+    thr->m_mask = mask;
+    thr->m_cond.notify_one();
+  }
+};
+
+void InterruptJNI::SetFunc(JNIEnv* env, jobject func, jmethodID mid,
+                           jobject param) {
+  auto thr = GetThread();
+  if (!thr) return;
+  // free global references
+  if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
+  if (thr->m_param) env->DeleteGlobalRef(thr->m_param);
+  // create global references
+  thr->m_func = env->NewGlobalRef(func);
+  thr->m_param = param ? env->NewGlobalRef(param) : nullptr;
+  thr->m_mid = mid;
+}
+
+void InterruptThreadJNI::Main() {
+  JNIEnv* env;
+  JavaVMAttachArgs args;
+  args.version = JNI_VERSION_1_2;
+  args.name = const_cast<char*>("Interrupt");
+  args.group = nullptr;
+  jint rs = GetJVM()->AttachCurrentThreadAsDaemon(
+      reinterpret_cast<void**>(&env), &args);
+  if (rs != JNI_OK) return;
+
+  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;
+    if (!m_func) continue;
+    jobject func = m_func;
+    jmethodID mid = m_mid;
+    uint32_t mask = m_mask;
+    jobject param = m_param;
+    lock.unlock();  // don't hold mutex during callback execution
+    env->CallVoidMethod(func, mid, static_cast<jint>(mask), param);
+    if (env->ExceptionCheck()) {
+      env->ExceptionDescribe();
+      env->ExceptionClear();
+    }
+    lock.lock();
+  }
+
+  // free global references
+  if (m_func) env->DeleteGlobalRef(m_func);
+  if (m_param) env->DeleteGlobalRef(m_param);
+
+  GetJVM()->DetachCurrentThread();
+}
+
+void interruptHandler(uint32_t mask, void* param) {
+  static_cast<InterruptJNI*>(param)->Notify(mask);
+}
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    initializeInterrupts
+ * Signature: (Z)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    cleanInterrupts
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+  if (param) {
+    delete static_cast<InterruptJNI*>(param);
+  }
+
+  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
+
+  // ignore status, as an invalid handle just needs to be ignored.
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    waitForInterrupt
+ * Signature: (IDZ)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_InterruptJNI_waitForInterrupt
+  (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    enableInterrupts
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    disableInterrupts
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    readInterruptRisingTimestamp
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    readInterruptFallingTimestamp
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    requestInterrupts
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_InterruptJNI_requestInterrupts
+  (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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    attachInterruptHandler
+ * Signature: (ILjava/lang/Object;Ljava/lang/Object;)V
+ */
+JNIEXPORT void JNICALL
+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;
+  }
+
+  InterruptJNI* intr = new InterruptJNI;
+  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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_InterruptJNI
+ * Method:    setInterruptUpSourceEdge
+ * Signature: (IZZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_InterruptJNI_setInterruptUpSourceEdge
+  (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);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/NotifierJNI.cpp b/hal/src/main/native/cpp/jni/NotifierJNI.cpp
new file mode 100644
index 0000000..61fe32f
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/NotifierJNI.cpp
@@ -0,0 +1,157 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+#include <cstdio>
+
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_NotifierJNI
+ * Method:    initializeNotifier
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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
+  }
+
+  return (jint)notifierHandle;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_NotifierJNI
+ * Method:    stopNotifier
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_NotifierJNI
+ * Method:    cleanNotifier
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_NotifierJNI
+ * Method:    updateNotifierAlarm
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_NotifierJNI
+ * Method:    cancelNotifierAlarm
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_NotifierJNI
+ * Method:    waitForNotifierAlarm
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+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;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/PDPJNI.cpp b/hal/src/main/native/cpp/jni/PDPJNI.cpp
new file mode 100644
index 0000000..e8173be
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/PDPJNI.cpp
@@ -0,0 +1,174 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_PDPJNI.h"
+#include "hal/PDP.h"
+#include "hal/Ports.h"
+
+using namespace frc;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    initializePDP
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PDPJNI_initializePDP
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  auto handle = HAL_InitializePDP(module, &status);
+  CheckStatusRange(env, status, 0, HAL_GetNumPDPModules(), module);
+  return static_cast<jint>(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    checkPDPChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PDPJNI_checkPDPChannel
+  (JNIEnv* env, jclass, jint channel)
+{
+  return HAL_CheckPDPChannel(channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    checkPDPModule
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PDPJNI_checkPDPModule
+  (JNIEnv* env, jclass, jint module)
+{
+  return HAL_CheckPDPModule(module);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    getPDPTemperature
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PDPJNI_getPDPTemperature
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double temperature = HAL_GetPDPTemperature(handle, &status);
+  CheckStatus(env, status, false);
+  return temperature;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    getPDPVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PDPJNI_getPDPVoltage
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double voltage = HAL_GetPDPVoltage(handle, &status);
+  CheckStatus(env, status, false);
+  return voltage;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    getPDPChannelCurrent
+ * Signature: (BI)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PDPJNI_getPDPChannelCurrent
+  (JNIEnv* env, jclass, jbyte channel, jint handle)
+{
+  int32_t status = 0;
+  double current = HAL_GetPDPChannelCurrent(handle, channel, &status);
+  CheckStatus(env, status, false);
+  return current;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    getPDPTotalCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PDPJNI_getPDPTotalCurrent
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double current = HAL_GetPDPTotalCurrent(handle, &status);
+  CheckStatus(env, status, false);
+  return current;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    getPDPTotalPower
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PDPJNI_getPDPTotalPower
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double power = HAL_GetPDPTotalPower(handle, &status);
+  CheckStatus(env, status, false);
+  return power;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    getPDPTotalEnergy
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PDPJNI_getPDPTotalEnergy
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double energy = HAL_GetPDPTotalEnergy(handle, &status);
+  CheckStatus(env, status, false);
+  return energy;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    resetPDPTotalEnergy
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PDPJNI_resetPDPTotalEnergy
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_ResetPDPTotalEnergy(handle, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PDPJNI
+ * Method:    clearPDPStickyFaults
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PDPJNI_clearPDPStickyFaults
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_ClearPDPStickyFaults(handle, &status);
+  CheckStatus(env, status, false);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/PWMJNI.cpp b/hal/src/main/native/cpp/jni/PWMJNI.cpp
new file mode 100644
index 0000000..1509f94
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/PWMJNI.cpp
@@ -0,0 +1,330 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_PWMJNI.h"
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    initializePWMPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    checkPWMChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    freePWMPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMConfigRaw
+ * Signature: (IIIIII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PWMJNI_setPWMConfigRaw
+  (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);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMConfig
+ * Signature: (IDDDDD)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PWMJNI_setPWMConfig
+  (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);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    getPWMConfigRaw
+ * Signature: (I)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL
+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;
+  int32_t centerPwm = 0;
+  int32_t deadbandMinPwm = 0;
+  int32_t minPwm = 0;
+  HAL_GetPWMConfigRaw((HAL_DigitalHandle)id, &maxPwm, &deadbandMaxPwm,
+                      &centerPwm, &deadbandMinPwm, &minPwm, &status);
+  CheckStatus(env, status);
+  return CreatePWMConfigDataResult(env, maxPwm, deadbandMaxPwm, centerPwm,
+                                   deadbandMinPwm, minPwm);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMEliminateDeadband
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    getPWMEliminateDeadband
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMRaw
+ * Signature: (IS)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMSpeed
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMPosition
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    getPWMRaw
+ * Signature: (I)S
+ */
+JNIEXPORT jshort JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    getPWMSpeed
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    getPWMPosition
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMDisabled
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    latchPWMZero
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PWMJNI
+ * Method:    setPWMPeriodScale
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/PortsJNI.cpp b/hal/src/main/native/cpp/jni/PortsJNI.cpp
new file mode 100644
index 0000000..4e14984
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/PortsJNI.cpp
@@ -0,0 +1,298 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#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
+ * Method:    getNumAccumulators
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumAnalogTriggers
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumAnalogInputs
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumAnalogOutputs
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumCounters
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumDigitalHeaders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumPWMHeaders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumDigitalChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumPWMChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumDigitalPWMOutputs
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumEncoders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumInterrupts
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumRelayChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumRelayHeaders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumPCMModules
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumSolenoidChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumPDPModules
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumPDPChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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/PowerJNI.cpp b/hal/src/main/native/cpp/jni/PowerJNI.cpp
new file mode 100644
index 0000000..9184e9e
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/PowerJNI.cpp
@@ -0,0 +1,228 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_PowerJNI.h"
+#include "hal/Power.h"
+
+using namespace frc;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getVinVoltage
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getVinVoltage
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetVinVoltage(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getVinCurrent
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getVinCurrent
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetVinCurrent(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserVoltage6V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserVoltage6V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetUserVoltage6V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserCurrent6V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserCurrent6V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetUserCurrent6V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserActive6V
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserActive6V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  bool val = HAL_GetUserActive6V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserCurrentFaults6V
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserCurrentFaults6V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  int32_t val = HAL_GetUserCurrentFaults6V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserVoltage5V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserVoltage5V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetUserVoltage5V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserCurrent5V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserCurrent5V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetUserCurrent5V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserActive5V
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserActive5V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  bool val = HAL_GetUserActive5V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserCurrentFaults5V
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserCurrentFaults5V
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  int32_t val = HAL_GetUserCurrentFaults5V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserVoltage3V3
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserVoltage3V3
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetUserVoltage3V3(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserCurrent3V3
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserCurrent3V3
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetUserCurrent3V3(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserActive3V3
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserActive3V3
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  bool val = HAL_GetUserActive3V3(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getUserCurrentFaults3V3
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getUserCurrentFaults3V3
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  int32_t val = HAL_GetUserCurrentFaults3V3(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/RelayJNI.cpp b/hal/src/main/native/cpp/jni/RelayJNI.cpp
new file mode 100644
index 0000000..0cc70fb
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/RelayJNI.cpp
@@ -0,0 +1,119 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include "HALUtil.h"
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_RelayJNI
+ * Method:    initializeRelayPort
+ * Signature: (IZ)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_RelayJNI
+ * Method:    freeRelayPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_RelayJNI
+ * Method:    checkRelayChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_RelayJNI
+ * Method:    setRelay
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_RelayJNI
+ * Method:    getRelay
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/SPIJNI.cpp b/hal/src/main/native/cpp/jni/SPIJNI.cpp
new file mode 100644
index 0000000..d594058
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/SPIJNI.cpp
@@ -0,0 +1,500 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include <wpi/jni_util.h>
+
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiInitialize
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiTransaction
+ * Signature: (ILjava/lang/Object;Ljava/lang/Object;B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiTransaction
+  (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 =
+        reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
+  }
+  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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiTransactionB
+ * Signature: (I[B[BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiTransactionB
+  (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 =
+      HAL_TransactionSPI(static_cast<HAL_SPIPort>(port),
+                         reinterpret_cast<const uint8_t*>(
+                             JByteArrayRef(env, dataToSend).array().data()),
+                         recvBuf.data(), size);
+  env->SetByteArrayRegion(dataReceived, 0, size,
+                          reinterpret_cast<const jbyte*>(recvBuf.data()));
+  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
+  return retVal;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiWrite
+ * Signature: (ILjava/lang/Object;B)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiWriteB
+ * Signature: (I[BB)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiRead
+ * Signature: (IZLjava/lang/Object;B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiRead
+  (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;
+    sendBuf.resize(size);
+    retVal = HAL_TransactionSPI(static_cast<HAL_SPIPort>(port), sendBuf.data(),
+                                dataReceivedPtr, size);
+  } else {
+    retVal = HAL_ReadSPI(static_cast<HAL_SPIPort>(port),
+                         reinterpret_cast<uint8_t*>(dataReceivedPtr), size);
+  }
+  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
+  return retVal;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiReadB
+ * Signature: (IZ[BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiReadB
+  (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);
+  if (initiate) {
+    wpi::SmallVector<uint8_t, 128> sendBuf;
+    sendBuf.resize(size);
+    retVal = HAL_TransactionSPI(static_cast<HAL_SPIPort>(port), sendBuf.data(),
+                                recvBuf.data(), size);
+  } else {
+    retVal = HAL_ReadSPI(static_cast<HAL_SPIPort>(port), recvBuf.data(), size);
+  }
+  env->SetByteArrayRegion(dataReceived, 0, size,
+                          reinterpret_cast<const jbyte*>(recvBuf.data()));
+  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
+  return retVal;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiClose
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiSetSpeed
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiSetOpts
+ * Signature: (IIII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiSetOpts
+  (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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiSetChipSelectActiveHigh
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiSetChipSelectActiveLow
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiInitAuto
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiFreeAuto
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiStartAutoRate
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiStartAutoTrigger
+ * Signature: (IIIZZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiStartAutoTrigger
+  (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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiStopAuto
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiSetAutoTransmitData
+ * Signature: (I[BI)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiForceAutoRead
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiReadAutoReceivedData
+ * Signature: (ILjava/lang/Object;ID)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiReadAutoReceivedData__ILjava_nio_ByteBuffer_2ID
+  (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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiReadAutoReceivedData
+ * Signature: (I[IID)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SPIJNI_spiReadAutoReceivedData__I_3IID
+  (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,
+                           reinterpret_cast<const jint*>(recvBuf.data()));
+  }
+  return retval;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SPIJNI
+ * Method:    spiGetAutoDroppedCount
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/SerialPortJNI.cpp b/hal/src/main/native/cpp/jni/SerialPortJNI.cpp
new file mode 100644
index 0000000..4524fe6
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/SerialPortJNI.cpp
@@ -0,0 +1,369 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#include <wpi/jni_util.h>
+
+#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
+ */
+JNIEXPORT void 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;
+  CheckStatusForceThrow(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialInitializePortDirect
+ * Signature: (BLjava/lang/String;)V
+ */
+JNIEXPORT void 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;
+  CheckStatusForceThrow(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetBaudRate
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetBaudRate
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetDataBits
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetDataBits
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetParity
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetParity
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetStopBits
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetStopBits
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetWriteMode
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetWriteMode
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetFlowControl
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetFlowControl
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetTimeout
+ * Signature: (BD)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetTimeout
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialEnableTermination
+ * Signature: (BC)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialEnableTermination
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialDisableTermination
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialDisableTermination
+  (JNIEnv* env, jclass, jbyte port)
+{
+  SERIALJNI_LOG(logDEBUG) << "Setting Serial Disable termination";
+  int32_t status = 0;
+  HAL_DisableSerialTermination(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetReadBufferSize
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetReadBufferSize
+  (JNIEnv* env, jclass, jbyte port, 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;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialSetWriteBufferSize
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialSetWriteBufferSize
+  (JNIEnv* env, jclass, jbyte port, 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,
+                               &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialGetBytesReceived
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialGetBytesReceived
+  (JNIEnv* env, jclass, jbyte port)
+{
+  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;
+  CheckStatus(env, status);
+  return retVal;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialRead
+ * Signature: (B[BI)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialRead
+  (JNIEnv* env, jclass, jbyte port, 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),
+                               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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialWrite
+ * Signature: (B[BI)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialWrite
+  (JNIEnv* env, jclass, jbyte port, jbyteArray dataToSend, jint size)
+{
+  SERIALJNI_LOG(logDEBUG) << "Serial Write";
+  int32_t status = 0;
+  jint retVal =
+      HAL_WriteSerial(static_cast<HAL_SerialPort>(port),
+                      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;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialFlush
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialFlush
+  (JNIEnv* env, jclass, jbyte port)
+{
+  SERIALJNI_LOG(logDEBUG) << "Serial Flush";
+  int32_t status = 0;
+  HAL_FlushSerial(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialClear
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialClear
+  (JNIEnv* env, jclass, jbyte port)
+{
+  SERIALJNI_LOG(logDEBUG) << "Serial Clear";
+  int32_t status = 0;
+  HAL_ClearSerial(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SerialPortJNI
+ * Method:    serialClose
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SerialPortJNI_serialClose
+  (JNIEnv* env, jclass, jbyte port)
+{
+  SERIALJNI_LOG(logDEBUG) << "Serial Close";
+  int32_t status = 0;
+  HAL_CloseSerial(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/SolenoidJNI.cpp b/hal/src/main/native/cpp/jni/SolenoidJNI.cpp
new file mode 100644
index 0000000..524b70e
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/SolenoidJNI.cpp
@@ -0,0 +1,242 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "HALUtil.h"
+#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" {
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    initializeSolenoidPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+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));
+  return (jint)handle;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    checkSolenoidChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    checkSolenoidModule
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    freeSolenoidPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    setSolenoid
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    getSolenoid
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_SolenoidJNI_getSolenoid
+  (JNIEnv* env, jclass, jint solenoid_port)
+{
+  int32_t status = 0;
+  jboolean val = HAL_GetSolenoid((HAL_SolenoidHandle)solenoid_port, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    getAllSolenoids
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SolenoidJNI_getAllSolenoids
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  jint val = HAL_GetAllSolenoids(module, &status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    getPCMSolenoidBlackList
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SolenoidJNI_getPCMSolenoidBlackList
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  jint val = HAL_GetPCMSolenoidBlackList(module, &status);
+  CheckStatus(env, status);
+  return val;
+}
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    getPCMSolenoidVoltageStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_SolenoidJNI_getPCMSolenoidVoltageStickyFault
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  bool val = HAL_GetPCMSolenoidVoltageStickyFault(module, &status);
+  CheckStatus(env, status);
+  return val;
+}
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    getPCMSolenoidVoltageFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_SolenoidJNI_getPCMSolenoidVoltageFault
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  bool val = HAL_GetPCMSolenoidVoltageFault(module, &status);
+  CheckStatus(env, status);
+  return val;
+}
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    clearAllPCMStickyFaults
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SolenoidJNI_clearAllPCMStickyFaults
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  HAL_ClearAllPCMStickyFaults(module, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    setOneShotDuration
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL
+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);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SolenoidJNI
+ * Method:    fireOneShot
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+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);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/ThreadsJNI.cpp b/hal/src/main/native/cpp/jni/ThreadsJNI.cpp
new file mode 100644
index 0000000..ea3cac6
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/ThreadsJNI.cpp
@@ -0,0 +1,80 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cassert>
+
+#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
+ * Method:    getCurrentThreadPriority
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+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);
+  CheckStatus(env, status);
+  return (jint)ret;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_ThreadsJNI
+ * Method:    getCurrentThreadIsRealTime
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+  CheckStatus(env, status);
+  return (jboolean)isRT;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_ThreadsJNI
+ * Method:    setCurrentThreadPriority
+ * Signature: (ZI)Z
+ */
+JNIEXPORT jboolean JNICALL
+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);
+  CheckStatus(env, status);
+  return (jboolean)ret;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/include/hal/Accelerometer.h b/hal/src/main/native/include/hal/Accelerometer.h
new file mode 100644
index 0000000..9dc488b
--- /dev/null
+++ b/hal/src/main/native/include/hal/Accelerometer.h
@@ -0,0 +1,79 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "hal/Types.h"
+
+/**
+ * @defgroup hal_accelerometer Accelerometer Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+/**
+ * The acceptable accelerometer ranges.
+ */
+HAL_ENUM(HAL_AccelerometerRange) {
+  HAL_AccelerometerRange_k2G = 0,
+  HAL_AccelerometerRange_k4G = 1,
+  HAL_AccelerometerRange_k8G = 2,
+};
+// clang-format on
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * Sets the accelerometer to active or standby mode.
+ *
+ * It must be in standby mode to change any configuration.
+ *
+ * @param active true to set to active, false for standby
+ */
+void HAL_SetAccelerometerActive(HAL_Bool active);
+
+/**
+ * Sets the range of values that can be measured (either 2, 4, or 8 g-forces).
+ *
+ * The accelerometer should be in standby mode when this is called.
+ *
+ * @param range the accelerometer range
+ */
+void HAL_SetAccelerometerRange(HAL_AccelerometerRange range);
+
+/**
+ * Gets the x-axis acceleration.
+ *
+ * This is a floating point value in units of 1 g-force.
+ *
+ * @return the X acceleration
+ */
+double HAL_GetAccelerometerX(void);
+
+/**
+ * Gets the y-axis acceleration.
+ *
+ * This is a floating point value in units of 1 g-force.
+ *
+ * @return the Y acceleration
+ */
+double HAL_GetAccelerometerY(void);
+
+/**
+ * Gets the z-axis acceleration.
+ *
+ * This is a floating point value in units of 1 g-force.
+ *
+ * @return the Z acceleration
+ */
+double HAL_GetAccelerometerZ(void);
+#ifdef __cplusplus
+}  // extern "C"
+/** @} */
+#endif
diff --git a/hal/src/main/native/include/hal/AnalogAccumulator.h b/hal/src/main/native/include/hal/AnalogAccumulator.h
new file mode 100644
index 0000000..9e49e90
--- /dev/null
+++ b/hal/src/main/native/include/hal/AnalogAccumulator.h
@@ -0,0 +1,115 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_analogaccumulator Analog Accumulator Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Is the channel attached to an accumulator.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ * @return The analog channel is attached to an accumulator.
+ */
+HAL_Bool HAL_IsAccumulatorChannel(HAL_AnalogInputHandle analogPortHandle,
+                                  int32_t* status);
+
+/**
+ * Initialize the accumulator.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ */
+void HAL_InitAccumulator(HAL_AnalogInputHandle analogPortHandle,
+                         int32_t* status);
+
+/**
+ * Resets the accumulator to the initial value.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ */
+void HAL_ResetAccumulator(HAL_AnalogInputHandle analogPortHandle,
+                          int32_t* status);
+
+/**
+ * Set the center value of the accumulator.
+ *
+ * The center value is subtracted from each A/D value before it is added to the
+ * accumulator. This is used for the center value of devices like gyros and
+ * accelerometers to make integration work and to take the device offset into
+ * account when integrating.
+ *
+ * This center value is based on the output of the oversampled and averaged
+ * source from channel 1. Because of this, any non-zero oversample bits will
+ * affect the size of the value for this field.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ * @param center The center value of the accumulator.
+ */
+void HAL_SetAccumulatorCenter(HAL_AnalogInputHandle analogPortHandle,
+                              int32_t center, int32_t* status);
+
+/**
+ * Set the accumulator's deadband.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ * @param deadband The deadband of the accumulator.
+ */
+void HAL_SetAccumulatorDeadband(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t deadband, int32_t* status);
+
+/**
+ * Read the accumulated value.
+ *
+ * Read the value that has been accumulating on channel 1.
+ * The accumulator is attached after the oversample and average engine.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ * @return The 64-bit value accumulated since the last Reset().
+ */
+int64_t HAL_GetAccumulatorValue(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t* status);
+
+/**
+ * Read the number of accumulated values.
+ *
+ * Read the count of the accumulated values since the accumulator was last
+ * Reset().
+ *
+ * @param analogPortHandle Handle to the analog port.
+ * @return The number of times samples from the channel were accumulated.
+ */
+int64_t HAL_GetAccumulatorCount(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t* status);
+
+/**
+ * Read the accumulated value and the number of accumulated values atomically.
+ *
+ * This function reads the value and count from the FPGA atomically.
+ * This can be used for averaging.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ * @param value Pointer to the 64-bit accumulated output.
+ * @param count Pointer to the number of accumulation cycles.
+ */
+void HAL_GetAccumulatorOutput(HAL_AnalogInputHandle analogPortHandle,
+                              int64_t* value, int64_t* count, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/AnalogGyro.h b/hal/src/main/native/include/hal/AnalogGyro.h
new file mode 100644
index 0000000..54030bd
--- /dev/null
+++ b/hal/src/main/native/include/hal/AnalogGyro.h
@@ -0,0 +1,138 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_analoggyro Analog Gyro Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes an analog gyro.
+ *
+ * @param handle handle to the analog port
+ * @return       the initialized gyro handle
+ */
+HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle handle,
+                                        int32_t* status);
+
+/**
+ * Sets up an analog gyro with the proper offsets and settings for the KOP
+ * analog gyro.
+ *
+ * @param handle the gyro handle
+ */
+void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status);
+
+/**
+ * Frees an analog gyro.
+ *
+ * @param handle the gyro handle
+ */
+void HAL_FreeAnalogGyro(HAL_GyroHandle handle);
+
+/**
+ * Sets the analog gyro parameters to the specified values.
+ *
+ * This is meant to be used if you want to reuse the values from a previous
+ * calibration.
+ *
+ * @param handle                  the gyro handle
+ * @param voltsPerDegreePerSecond the gyro volts scaling
+ * @param offset                  the gyro offset
+ * @param center                  the gyro center
+ */
+void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
+                                 double voltsPerDegreePerSecond, double offset,
+                                 int32_t center, int32_t* status);
+
+/**
+ * Sets the analog gyro volts per degrees per second scaling.
+ *
+ * @param handle                  the gyro handle
+ * @param voltsPerDegreePerSecond the gyro volts scaling
+ */
+void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
+                                              double voltsPerDegreePerSecond,
+                                              int32_t* status);
+
+/**
+ * Resets the analog gyro value to 0.
+ *
+ * @param handle the gyro handle
+ */
+void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status);
+
+/**
+ * Calibrates the analog gyro.
+ *
+ * This happens by calculating the average value of the gyro over 5 seconds, and
+ * setting that as the center. Note that this call blocks for 5 seconds to
+ * perform this.
+ *
+ * @param handle the gyro handle
+ */
+void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status);
+
+/**
+ * Sets the deadband of the analog gyro.
+ *
+ * @param handle the gyro handle
+ * @param volts  the voltage deadband
+ */
+void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
+                               int32_t* status);
+
+/**
+ * Gets the gyro angle in degrees.
+ *
+ * @param handle the gyro handle
+ * @return the gyro angle in degrees
+ */
+double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status);
+
+/**
+ * Gets the gyro rate in degrees/second.
+ *
+ * @param handle the gyro handle
+ * @return the gyro rate in degrees/second
+ */
+double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status);
+
+/**
+ * Gets the calibrated gyro offset.
+ *
+ * Can be used to not repeat a calibration but reconstruct the gyro object.
+ *
+ * @param handle the gyro handle
+ * @return the gryo offset
+ */
+double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status);
+
+/**
+ * Gets the calibrated gyro center.
+ *
+ * Can be used to not repeat a calibration but reconstruct the gyro object.
+ *
+ * @param handle the gyro handle
+ * @return the gyro center
+ */
+int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/AnalogInput.h b/hal/src/main/native/include/hal/AnalogInput.h
new file mode 100644
index 0000000..45e6662
--- /dev/null
+++ b/hal/src/main/native/include/hal/AnalogInput.h
@@ -0,0 +1,230 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_analoginput Analog Input Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes the analog input port using the given port object.
+ *
+ * @param portHandle Handle to the port to initialize.
+ * @return           the created analog input handle
+ */
+HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle,
+                                                    int32_t* status);
+
+/**
+ * Frees an analog input port.
+ *
+ * @param analogPortHandle Handle to the analog port.
+ */
+void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle);
+
+/**
+ * Checks that the analog module number is valid.
+ *
+ * @param module The analog module number.
+ * @return Analog module is valid and present
+ */
+HAL_Bool HAL_CheckAnalogModule(int32_t module);
+
+/**
+ * Checks that the analog output channel number is value.
+ * Verifies that the analog channel number is one of the legal channel numbers.
+ * Channel numbers are 0-based.
+ *
+ * @param channel The analog output channel number.
+ * @return Analog channel is valid
+ */
+HAL_Bool HAL_CheckAnalogInputChannel(int32_t channel);
+
+/**
+ * Sets the sample rate.
+ *
+ * This is a global setting for the Athena and effects all channels.
+ *
+ * @param samplesPerSecond The number of samples per channel per second.
+ */
+void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status);
+
+/**
+ * Gets the current sample rate.
+ *
+ * This assumes one entry in the scan list.
+ * This is a global setting for the Athena and effects all channels.
+ *
+ * @return Sample rate.
+ */
+double HAL_GetAnalogSampleRate(int32_t* status);
+
+/**
+ * Sets the number of averaging bits.
+ *
+ * This sets the number of averaging bits. The actual number of averaged samples
+ * is 2**bits. Use averaging to improve the stability of your measurement at the
+ * expense of sampling rate. The averaging is done automatically in the FPGA.
+ *
+ * @param analogPortHandle Handle to the analog port to configure.
+ * @param bits Number of bits to average.
+ */
+void HAL_SetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
+                              int32_t bits, int32_t* status);
+
+/**
+ * Gets the number of averaging bits.
+ *
+ * This gets the number of averaging bits from the FPGA. The actual number of
+ * averaged samples is 2**bits. The averaging is done automatically in the FPGA.
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return Bits to average.
+ */
+int32_t HAL_GetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
+                                 int32_t* status);
+
+/**
+ * Sets the number of oversample bits.
+ *
+ * This sets the number of oversample bits. The actual number of oversampled
+ * values is 2**bits. Use oversampling to improve the resolution of your
+ * measurements at the expense of sampling rate. The oversampling is done
+ * automatically in the FPGA.
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @param bits Number of bits to oversample.
+ */
+void HAL_SetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
+                                 int32_t bits, int32_t* status);
+
+/**
+ * Gets the number of oversample bits.
+ *
+ * This gets the number of oversample bits from the FPGA. The actual number of
+ * oversampled values is 2**bits. The oversampling is done automatically in the
+ * FPGA.
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return Bits to oversample.
+ */
+int32_t HAL_GetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
+                                    int32_t* status);
+
+/**
+ * Gets a sample straight from the channel on this module.
+ *
+ * The sample is a 12-bit value representing the 0V to 5V range of the A/D
+ * converter in the module. The units are in A/D converter codes.  Use
+ * GetVoltage() to get the analog value in calibrated units.
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return A sample straight from the channel on this module.
+ */
+int32_t HAL_GetAnalogValue(HAL_AnalogInputHandle analogPortHandle,
+                           int32_t* status);
+
+/**
+ * Gets a sample from the output of the oversample and average engine for the
+ * channel.
+ *
+ * The sample is 12-bit + the value configured in SetOversampleBits().
+ * The value configured in SetAverageBits() will cause this value to be averaged
+ * 2**bits number of samples. This is not a sliding window.  The sample will not
+ * change until 2**(OversamplBits + AverageBits) samples have been acquired from
+ * the module on this channel. Use GetAverageVoltage() to get the analog value
+ * in calibrated units.
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return A sample from the oversample and average engine for the channel.
+ */
+int32_t HAL_GetAnalogAverageValue(HAL_AnalogInputHandle analogPortHandle,
+                                  int32_t* status);
+
+/**
+ * Converts a voltage to a raw value for a specified channel.
+ *
+ * This process depends on the calibration of each channel, so the channel must
+ * be specified.
+ *
+ * @todo This assumes raw values.  Oversampling not supported as is.
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @param voltage The voltage to convert.
+ * @return The raw value for the channel.
+ */
+int32_t HAL_GetAnalogVoltsToValue(HAL_AnalogInputHandle analogPortHandle,
+                                  double voltage, int32_t* status);
+
+/**
+ * Gets a scaled sample straight from the channel on this module.
+ *
+ * The value is scaled to units of Volts using the calibrated scaling data from
+ * GetLSBWeight() and GetOffset().
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return A scaled sample straight from the channel on this module.
+ */
+double HAL_GetAnalogVoltage(HAL_AnalogInputHandle analogPortHandle,
+                            int32_t* status);
+
+/**
+ * Gets a scaled sample from the output of the oversample and average engine for
+ * the channel.
+ *
+ * The value is scaled to units of Volts using the calibrated scaling data from
+ * GetLSBWeight() and GetOffset(). Using oversampling will cause this value to
+ * be higher resolution, but it will update more slowly. Using averaging will
+ * cause this value to be more stable, but it will update more slowly.
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return A scaled sample from the output of the oversample and average engine
+ * for the channel.
+ */
+double HAL_GetAnalogAverageVoltage(HAL_AnalogInputHandle analogPortHandle,
+                                   int32_t* status);
+
+/**
+ * Gets the factory scaling least significant bit weight constant.
+ * The least significant bit weight constant for the channel that was calibrated
+ * in manufacturing and stored in an eeprom in the module.
+ *
+ * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return Least significant bit weight.
+ */
+int32_t HAL_GetAnalogLSBWeight(HAL_AnalogInputHandle analogPortHandle,
+                               int32_t* status);
+
+/**
+ * Gets the factory scaling offset constant.
+ * The offset constant for the channel that was calibrated in manufacturing and
+ * stored in an eeprom in the module.
+ *
+ * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
+ *
+ * @param analogPortHandle Handle to the analog port to use.
+ * @return Offset constant.
+ */
+int32_t HAL_GetAnalogOffset(HAL_AnalogInputHandle analogPortHandle,
+                            int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/AnalogOutput.h b/hal/src/main/native/include/hal/AnalogOutput.h
new file mode 100644
index 0000000..ba0d93b
--- /dev/null
+++ b/hal/src/main/native/include/hal/AnalogOutput.h
@@ -0,0 +1,70 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_analogoutput Analog Output Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes the analog output port using the given port object.
+ *
+ * @param handle handle to the port
+ * @return       the created analog output handle
+ */
+HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle,
+                                                      int32_t* status);
+
+/**
+ * Frees an analog output port.
+ *
+ * @param analogOutputHandle the analog output handle
+ */
+void HAL_FreeAnalogOutputPort(HAL_AnalogOutputHandle analogOutputHandle);
+
+/**
+ * Sets an analog output value.
+ *
+ * @param analogOutputHandle the analog output handle
+ * @param voltage            the voltage (0-5v) to output
+ */
+void HAL_SetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
+                         double voltage, int32_t* status);
+
+/**
+ * Gets the current analog output value.
+ *
+ * @param analogOutputHandle the analog output handle
+ * @return                   the current output voltage (0-5v)
+ */
+double HAL_GetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
+                           int32_t* status);
+
+/**
+ * Checks that the analog output channel number is value.
+ *
+ * Verifies that the analog channel number is one of the legal channel numbers.
+ * Channel numbers are 0-based.
+ *
+ * @return Analog channel is valid
+ */
+HAL_Bool HAL_CheckAnalogOutputChannel(int32_t channel);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/AnalogTrigger.h b/hal/src/main/native/include/hal/AnalogTrigger.h
new file mode 100644
index 0000000..f461f1d
--- /dev/null
+++ b/hal/src/main/native/include/hal/AnalogTrigger.h
@@ -0,0 +1,143 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_analogtrigger Analog Trigger Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+/**
+ * The type of analog trigger to trigger on.
+ */
+HAL_ENUM(HAL_AnalogTriggerType) {
+  HAL_Trigger_kInWindow = 0,
+  HAL_Trigger_kState = 1,
+  HAL_Trigger_kRisingPulse = 2,
+  HAL_Trigger_kFallingPulse = 3
+};
+// clang-format on
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes an analog trigger.
+ *
+ * @param portHandle the analog input to use for triggering
+ * @param index      the trigger index value (output)
+ * @return           the created analog trigger handle
+ */
+HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
+    HAL_AnalogInputHandle portHandle, int32_t* index, int32_t* status);
+
+/**
+ * Frees an analog trigger.
+ *
+ * @param analogTriggerHandle the trigger handle
+ */
+void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
+                            int32_t* status);
+
+/**
+ * Sets the raw ADC upper and lower limits of the analog trigger.
+ *
+ * HAL_SetAnalogTriggerLimitsVoltage is likely better in most cases.
+ *
+ * @param analogTriggerHandle the trigger handle
+ * @param lower               the lower ADC value
+ * @param upper               the upper ADC value
+ */
+void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                   int32_t lower, int32_t upper,
+                                   int32_t* status);
+
+/**
+ * Sets the upper and lower limits of the analog trigger.
+ *
+ * The limits are given as floating point voltage values.
+ *
+ * @param analogTriggerHandle the trigger handle
+ * @param lower               the lower voltage value
+ * @param upper               the upper voltage value
+ */
+void HAL_SetAnalogTriggerLimitsVoltage(
+    HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
+    int32_t* status);
+
+/**
+ * Configures the analog trigger to use the averaged vs. raw values.
+ *
+ * If the value is true, then the averaged value is selected for the analog
+ * trigger, otherwise the immediate value is used.
+ *
+ * @param analogTriggerHandle the trigger handle
+ * @param useAveragedValue    true to use averaged values, false for raw
+ */
+void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                  HAL_Bool useAveragedValue, int32_t* status);
+
+/**
+ * Configures the analog trigger to use a filtered value.
+ *
+ * The analog trigger will operate with a 3 point average rejection filter. This
+ * is designed to help with 360 degree pot applications for the period where the
+ * pot crosses through zero.
+ *
+ * @param analogTriggerHandle the trigger handle
+ * @param useFilteredValue    true to use filtered values, false for average or
+ * raw
+ */
+void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                  HAL_Bool useFilteredValue, int32_t* status);
+
+/**
+ * Returns the InWindow output of the analog trigger.
+ *
+ * True if the analog input is between the upper and lower limits.
+ *
+ * @param analogTriggerHandle the trigger handle
+ * @return                    the InWindow output of the analog trigger
+ */
+HAL_Bool HAL_GetAnalogTriggerInWindow(
+    HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status);
+
+/**
+ * Returns the TriggerState output of the analog trigger.
+ *
+ * True if above upper limit.
+ * False if below lower limit.
+ * If in Hysteresis, maintain previous state.
+ *
+ * @param analogTriggerHandle the trigger handle
+ * @return                    the TriggerState output of the analog trigger
+ */
+HAL_Bool HAL_GetAnalogTriggerTriggerState(
+    HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status);
+
+/**
+ * Gets the state of the analog trigger output.
+ *
+ * @param analogTriggerHandle the trigger handle
+ * @param type                the type of trigger to trigger on
+ * @return                    the state of the analog trigger output
+ */
+HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                    HAL_AnalogTriggerType type,
+                                    int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/CAN.h b/hal/src/main/native/include/hal/CAN.h
new file mode 100644
index 0000000..8cc9c17
--- /dev/null
+++ b/hal/src/main/native/include/hal/CAN.h
@@ -0,0 +1,124 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_canstream CAN Stream Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// These are copies of defines located in CANSessionMux.h prepended with HAL_
+
+#define HAL_CAN_SEND_PERIOD_NO_REPEAT 0
+#define HAL_CAN_SEND_PERIOD_STOP_REPEATING -1
+
+/* Flags in the upper bits of the messageID */
+#define HAL_CAN_IS_FRAME_REMOTE 0x80000000
+#define HAL_CAN_IS_FRAME_11BIT 0x40000000
+
+#define HAL_ERR_CANSessionMux_InvalidBuffer -44086
+#define HAL_ERR_CANSessionMux_MessageNotFound -44087
+#define HAL_WARN_CANSessionMux_NoToken 44087
+#define HAL_ERR_CANSessionMux_NotAllowed -44088
+#define HAL_ERR_CANSessionMux_NotInitialized -44089
+#define HAL_ERR_CANSessionMux_SessionOverrun 44050
+
+/**
+ * Storage for CAN Stream Messages.
+ */
+struct HAL_CANStreamMessage {
+  uint32_t messageID;
+  uint32_t timeStamp;
+  uint8_t data[8];
+  uint8_t dataSize;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Sends a CAN message.
+ *
+ * @param messageID the CAN ID to send
+ * @param data      the data to send (0-8 bytes)
+ * @param dataSize  the size of the data to send (0-8 bytes)
+ * @param periodMs  the period to repeat the packet at. Use
+ * HAL_CAN_SEND_PERIOD_NO_REPEAT to not repeat.
+ */
+void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
+                         uint8_t dataSize, int32_t periodMs, int32_t* status);
+
+/**
+ * Receives a CAN message.
+ *
+ * @param messageID     store for the received message ID
+ * @param messageIDMask the message ID mask to look for
+ * @param data          data output (8 bytes)
+ * @param dataSize      data length (0-8 bytes)
+ * @param timeStamp     the packet received timestamp (based off of
+ * CLOCK_MONOTONIC)
+ */
+void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
+                            uint8_t* data, uint8_t* dataSize,
+                            uint32_t* timeStamp, int32_t* status);
+
+/**
+ * Opens a CAN stream.
+ *
+ * @param sessionHandle output for the session handle
+ * @param messageID     the message ID to read
+ * @param messageIDMask the mssage ID mask
+ * @param maxMessages   the maximum number of messages to stream
+ */
+void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
+                               uint32_t messageIDMask, uint32_t maxMessages,
+                               int32_t* status);
+
+/**
+ * Closes a CAN stream.
+ *
+ * @param sessionHandle the session to close
+ */
+void HAL_CAN_CloseStreamSession(uint32_t sessionHandle);
+
+/**
+ * Reads a CAN stream message.
+ *
+ * @param sessionHandle  the session handle
+ * @param messages       array of messages
+ * @param messagesToRead the max number of messages to read
+ * @param messageRead    the number of messages actually read
+ */
+void HAL_CAN_ReadStreamSession(uint32_t sessionHandle,
+                               struct HAL_CANStreamMessage* messages,
+                               uint32_t messagesToRead, uint32_t* messagesRead,
+                               int32_t* status);
+
+/**
+ * Gets CAN status information.
+ *
+ * @param percentBusUtilization the bus utilization
+ * @param busOffCount           the number of bus off errors
+ * @param txFullCount           the number of tx full errors
+ * @param receiveErrorCount     the number of receive errors
+ * @param transmitErrorCount    the number of transmit errors
+ */
+void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
+                          uint32_t* txFullCount, uint32_t* receiveErrorCount,
+                          uint32_t* transmitErrorCount, int32_t* status);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/CANAPI.h b/hal/src/main/native/include/hal/CANAPI.h
new file mode 100644
index 0000000..48c254d
--- /dev/null
+++ b/hal/src/main/native/include/hal/CANAPI.h
@@ -0,0 +1,162 @@
+/*----------------------------------------------------------------------------*/
+/* 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/CANAPITypes.h"
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_canapi CAN API Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a CAN device.
+ *
+ * These follow the FIRST standard CAN layout. Link TBD
+ *
+ * @param manufacturer the can manufacturer
+ * @param deviceId     the device ID (0-63)
+ * @param deviceType   the device type
+ * @return             the created CAN handle
+ */
+HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
+                                int32_t deviceId, HAL_CANDeviceType deviceType,
+                                int32_t* status);
+
+/**
+ * Frees a CAN device
+ *
+ * @param handle the CAN handle
+ */
+void HAL_CleanCAN(HAL_CANHandle handle);
+
+/**
+ * Writes a packet to the CAN device with a specific ID.
+ *
+ * This ID is 10 bits.
+ *
+ * @param handle the CAN handle
+ * @param data   the data to write (0-8 bytes)
+ * @param length the length of data (0-8)
+ * @param apiId  the ID to write (0-1023 bits)
+ */
+void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
+                        int32_t length, int32_t apiId, int32_t* status);
+
+/**
+ * Writes a repeating packet to the CAN device with a specific ID.
+ *
+ * This ID is 10 bits.
+ *
+ * The RoboRIO will automatically repeat the packet at the specified interval
+ *
+ * @param handle   the CAN handle
+ * @param data     the data to write (0-8 bytes)
+ * @param length   the length of data (0-8)
+ * @param apiId    the ID to write (0-1023)
+ * @param repeatMs the period to repeat in ms
+ */
+void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
+                                 int32_t length, int32_t apiId,
+                                 int32_t repeatMs, int32_t* status);
+
+/**
+ * Stops a repeating packet with a specific ID.
+ *
+ * This ID is 10 bits.
+ *
+ * @param handle the CAN handle
+ * @param apiId  the ID to stop repeating (0-1023)
+ */
+void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
+                                int32_t* status);
+
+/**
+ * Reads a new CAN packet.
+ *
+ * This will only return properly once per packet received. Multiple calls
+ * without receiving another packet will return an error code.
+ *
+ * @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)
+ */
+void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
+                          int32_t* length, uint64_t* receivedTimestamp,
+                          int32_t* status);
+
+/**
+ * Reads a CAN packet. The will continuously return the last packet received,
+ * without accounting for packet age.
+ *
+ * @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)
+ */
+void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
+                             int32_t* length, uint64_t* receivedTimestamp,
+                             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.
+ *
+ * @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
+ */
+void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
+                              uint8_t* data, int32_t* length,
+                              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
new file mode 100644
index 0000000..4bf98bd
--- /dev/null
+++ b/hal/src/main/native/include/hal/CANAPITypes.h
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/

+/* 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

+/** @} */

diff --git a/hal/src/main/native/include/hal/ChipObject.h b/hal/src/main/native/include/hal/ChipObject.h
new file mode 100644
index 0000000..878595b
--- /dev/null
+++ b/hal/src/main/native/include/hal/ChipObject.h
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+
+#include <stdint.h>
+
+#include <FRC_FPGA_ChipObject/RoboRIO_FRC_ChipObject_Aliases.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/nInterfaceGlobals.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAI.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAO.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAccel.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAccumulator.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAlarm.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tAnalogTrigger.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tBIST.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tCounter.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tDIO.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tDMA.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tEncoder.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tGlobal.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tInterrupt.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tPWM.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tPower.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tRelay.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tSPI.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tSysWatchdog.h>
+#include <FRC_FPGA_ChipObject/tDMAChannelDescriptor.h>
+#include <FRC_FPGA_ChipObject/tDMAManager.h>
+#include <FRC_FPGA_ChipObject/tInterruptManager.h>
+#include <FRC_FPGA_ChipObject/tSystem.h>
+#include <FRC_FPGA_ChipObject/tSystemInterface.h>
+
+namespace hal {
+using namespace nFPGA;
+using namespace nRoboRIO_FPGANamespace;
+}  // namespace hal
+
+#pragma GCC diagnostic pop
diff --git a/hal/src/main/native/include/hal/Compressor.h b/hal/src/main/native/include/hal/Compressor.h
new file mode 100644
index 0000000..cb58e46
--- /dev/null
+++ b/hal/src/main/native/include/hal/Compressor.h
@@ -0,0 +1,143 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_compressor Compressor Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a compressor on the given PCM module.
+ *
+ * @param module the module number
+ * @return       the created handle
+ */
+HAL_CompressorHandle HAL_InitializeCompressor(int32_t module, int32_t* status);
+
+/**
+ * Gets if a compressor module is valid.
+ *
+ * @param module the module number
+ * @return       true if the module is valid, otherwise false
+ */
+HAL_Bool HAL_CheckCompressorModule(int32_t module);
+
+/**
+ * Gets the compressor state (on or off).
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if the compressor is on, otherwise false
+ */
+HAL_Bool HAL_GetCompressor(HAL_CompressorHandle compressorHandle,
+                           int32_t* status);
+
+/**
+ * Sets the compressor to closed loop mode.
+ *
+ * @param compressorHandle the compressor handle
+ * @param value            true for closed loop mode, false for off
+ */
+void HAL_SetCompressorClosedLoopControl(HAL_CompressorHandle compressorHandle,
+                                        HAL_Bool value, int32_t* status);
+
+/**
+ * Gets if the compressor is in closed loop mode.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if the compressor is in closed loop mode,
+ * otherwise false
+ */
+HAL_Bool HAL_GetCompressorClosedLoopControl(
+    HAL_CompressorHandle compressorHandle, int32_t* status);
+
+/**
+ * Gets the compressor pressure switch state.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if the pressure switch is triggered, otherwise
+ * false
+ */
+HAL_Bool HAL_GetCompressorPressureSwitch(HAL_CompressorHandle compressorHandle,
+                                         int32_t* status);
+
+/**
+ * Gets the compressor current.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 the compressor current in amps
+ */
+double HAL_GetCompressorCurrent(HAL_CompressorHandle compressorHandle,
+                                int32_t* status);
+
+/**
+ * Gets if the compressor is faulted because of too high of current.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if falted, otherwise false
+ */
+HAL_Bool HAL_GetCompressorCurrentTooHighFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status);
+
+/**
+ * Gets if a sticky fauly is triggered because of too high of current.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if falted, otherwise false
+ */
+HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status);
+
+/**
+ * Gets if a sticky fauly is triggered because of a short.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if falted, otherwise false
+ */
+HAL_Bool HAL_GetCompressorShortedStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status);
+
+/**
+ * Gets if the compressor is faulted because of a short.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if shorted, otherwise false
+ */
+HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
+                                       int32_t* status);
+
+/**
+ * Gets if a sticky fault is triggered of the compressor not connected.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if falted, otherwise false
+ */
+HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status);
+
+/**
+ * Gets if the compressor is not connected.
+ *
+ * @param compressorHandle the compressor handle
+ * @return                 true if not connected, otherwise false
+ */
+HAL_Bool HAL_GetCompressorNotConnectedFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Constants.h b/hal/src/main/native/include/hal/Constants.h
new file mode 100644
index 0000000..2a4d409
--- /dev/null
+++ b/hal/src/main/native/include/hal/Constants.h
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+/**
+ * @defgroup hal_constants Constants Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the number of FPGA system clock ticks per microsecond.
+ *
+ * @return the number of clock ticks per microsecond
+ */
+int32_t HAL_GetSystemClockTicksPerMicrosecond(void);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Counter.h b/hal/src/main/native/include/hal/Counter.h
new file mode 100644
index 0000000..c0dd057
--- /dev/null
+++ b/hal/src/main/native/include/hal/Counter.h
@@ -0,0 +1,307 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/AnalogTrigger.h"
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_counter Counter Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+/**
+ * The counter mode.
+ */
+HAL_ENUM(HAL_Counter_Mode) {
+  HAL_Counter_kTwoPulse = 0,
+  HAL_Counter_kSemiperiod = 1,
+  HAL_Counter_kPulseLength = 2,
+  HAL_Counter_kExternalDirection = 3
+};
+// clang-format on
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a counter.
+ *
+ * @param mode  the counter mode
+ * @param index the compressor index (output)
+ * @return      the created handle
+ */
+HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
+                                        int32_t* status);
+
+/**
+ * Frees a counter.
+ *
+ * @param counterHandle the counter handle
+ */
+void HAL_FreeCounter(HAL_CounterHandle counterHandle, int32_t* status);
+
+/**
+ * Sets the average sample size of a counter.
+ *
+ * @param counterHandle the counter handle
+ * @param size          the size of samples to average
+ */
+void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
+                               int32_t* status);
+
+/**
+ * Sets the source object that causes the counter to count up.
+ *
+ * @param counterHandle       the counter handle
+ * @param digitalSourceHandle the digital source handle (either a
+ * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
+ * @param analogTriggerType   the analog trigger type if the source is an analog
+ * trigger
+ */
+void HAL_SetCounterUpSource(HAL_CounterHandle counterHandle,
+                            HAL_Handle digitalSourceHandle,
+                            HAL_AnalogTriggerType analogTriggerType,
+                            int32_t* status);
+
+/**
+ * Sets the up source to either detect rising edges or falling edges.
+ *
+ * Note that both are allowed to be set true at the same time without issues.
+ *
+ * @param counterHandle the counter handle
+ * @param risingEdge    true to trigger on rising
+ * @param fallingEdge   true to trigger on falling
+ */
+void HAL_SetCounterUpSourceEdge(HAL_CounterHandle counterHandle,
+                                HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                int32_t* status);
+
+/**
+ * Disables the up counting source to the counter.
+ *
+ * @param counterHandle the counter handle
+ */
+void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle, int32_t* status);
+
+/**
+ * Sets the source object that causes the counter to count down.
+ *
+ * @param counterHandle       the counter handle
+ * @param digitalSourceHandle the digital source handle (either a
+ * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
+ * @param analogTriggerType   the analog trigger type if the source is an analog
+ * trigger
+ */
+void HAL_SetCounterDownSource(HAL_CounterHandle counterHandle,
+                              HAL_Handle digitalSourceHandle,
+                              HAL_AnalogTriggerType analogTriggerType,
+                              int32_t* status);
+
+/**
+ * Sets the down source to either detect rising edges or falling edges.
+ * Note that both are allowed to be set true at the same time without issues.
+ *
+ * @param counterHandle the counter handle
+ * @param risingEdge    true to trigger on rising
+ * @param fallingEdge   true to trigger on falling
+ */
+void HAL_SetCounterDownSourceEdge(HAL_CounterHandle counterHandle,
+                                  HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                  int32_t* status);
+
+/**
+ * Disables the down counting source to the counter.
+ *
+ * @param counterHandle the counter handle
+ */
+void HAL_ClearCounterDownSource(HAL_CounterHandle counterHandle,
+                                int32_t* status);
+
+/**
+ * Sets standard up / down counting mode on this counter.
+ *
+ * Up and down counts are sourced independently from two inputs.
+ *
+ * @param counterHandle the counter handle
+ */
+void HAL_SetCounterUpDownMode(HAL_CounterHandle counterHandle, int32_t* status);
+
+/**
+ * Sets directional counting mode on this counter.
+ *
+ * The direction is determined by the B input, with counting happening with the
+ * A input.
+ *
+ * @param counterHandle the counter handle
+ */
+void HAL_SetCounterExternalDirectionMode(HAL_CounterHandle counterHandle,
+                                         int32_t* status);
+
+/**
+ * Sets Semi-period mode on this counter.
+ *
+ * The counter counts up based on the time the input is triggered. High or Low
+ * depends on the highSemiPeriod parameter.
+ *
+ * @param counterHandle  the counter handle
+ * @param highSemiPeriod true for counting when the input is high, false for low
+ */
+void HAL_SetCounterSemiPeriodMode(HAL_CounterHandle counterHandle,
+                                  HAL_Bool highSemiPeriod, int32_t* status);
+
+/**
+ * Configures the counter to count in up or down based on the length of the
+ * input pulse.
+ *
+ * This mode is most useful for direction sensitive gear tooth sensors.
+ *
+ * @param counterHandle the counter handle
+ * @param threshold The pulse length beyond which the counter counts the
+ * opposite direction (seconds)
+ */
+void HAL_SetCounterPulseLengthMode(HAL_CounterHandle counterHandle,
+                                   double threshold, int32_t* status);
+
+/**
+ * Gets the Samples to Average which specifies the number of samples of the
+ * timer to average when calculating the period. Perform averaging to account
+ * for mechanical imperfections or as oversampling to increase resolution.
+ *
+ * @param counterHandle the counter handle
+ * @return SamplesToAverage The number of samples being averaged (from 1 to 127)
+ */
+int32_t HAL_GetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
+                                       int32_t* status);
+
+/**
+ * Sets the Samples to Average which specifies the number of samples of the
+ * timer to average when calculating the period. Perform averaging to account
+ * for mechanical imperfections or as oversampling to increase resolution.
+ *
+ * @param counterHandle    the counter handle
+ * @param samplesToAverage The number of samples to average from 1 to 127
+ */
+void HAL_SetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
+                                    int32_t samplesToAverage, int32_t* status);
+
+/**
+ * Resets the Counter to zero.
+ *
+ * Sets the counter value to zero. This does not effect the running state of the
+ * counter, just sets the current value to zero.
+ *
+ * @param counterHandle the counter handle
+ */
+void HAL_ResetCounter(HAL_CounterHandle counterHandle, int32_t* status);
+
+/**
+ * Reads the current counter value.
+ *
+ * Reads the value at this instant. It may still be running, so it reflects the
+ * current value. Next time it is read, it might have a different value.
+ *
+ * @param counterHandle the counter handle
+ * @return              the current counter value
+ */
+int32_t HAL_GetCounter(HAL_CounterHandle counterHandle, int32_t* status);
+
+/*
+ * Gets the Period of the most recent count.
+ *
+ * Returns the time interval of the most recent count. This can be used for
+ * velocity calculations to determine shaft speed.
+ *
+ * @param counterHandle the counter handle
+ * @returns             the period of the last two pulses in units of seconds
+ */
+double HAL_GetCounterPeriod(HAL_CounterHandle counterHandle, int32_t* status);
+
+/**
+ * Sets the maximum period where the device is still considered "moving".
+ *
+ * Sets the maximum period where the device is considered moving. This value is
+ * used to determine the "stopped" state of the counter using the
+ * HAL_GetCounterStopped method.
+ *
+ * @param counterHandle the counter handle
+ * @param maxPeriod     the maximum period where the counted device is
+ * considered moving in seconds
+ */
+void HAL_SetCounterMaxPeriod(HAL_CounterHandle counterHandle, double maxPeriod,
+                             int32_t* status);
+
+/**
+ * Selects whether you want to continue updating the event timer output when
+ * there are no samples captured.
+ *
+ * The output of the event timer has a buffer of periods that are averaged and
+ * posted to a register on the FPGA.  When the timer detects that the event
+ * source has stopped (based on the MaxPeriod) the buffer of samples to be
+ * averaged is emptied.
+ *
+ * If you enable the update when empty, you will be
+ * notified of the stopped source and the event time will report 0 samples.
+ *
+ * If you disable update when empty, the most recent average will remain on the
+ * output until a new sample is acquired.
+ *
+ * You will never see 0 samples output (except when there have been no events
+ * since an FPGA reset) and you will likely not see the stopped bit become true
+ * (since it is updated at the end of an average and there are no samples to
+ * average).
+ *
+ * @param counterHandle the counter handle
+ * @param enabled       true to enable counter updating with no samples
+ */
+void HAL_SetCounterUpdateWhenEmpty(HAL_CounterHandle counterHandle,
+                                   HAL_Bool enabled, int32_t* status);
+
+/**
+ * Determines if the clock is stopped.
+ *
+ * Determine if the clocked input is stopped based on the MaxPeriod value set
+ * using the SetMaxPeriod method. If the clock exceeds the MaxPeriod, then the
+ * device (and counter) are assumed to be stopped and it returns true.
+ *
+ * @param counterHandle the counter handle
+ * @return              true if the most recent counter period exceeds the
+ * MaxPeriod value set by SetMaxPeriod
+ */
+HAL_Bool HAL_GetCounterStopped(HAL_CounterHandle counterHandle,
+                               int32_t* status);
+
+/**
+ * Gets the last direction the counter value changed.
+ *
+ * @param counterHandle the counter handle
+ * @return              the last direction the counter value changed
+ */
+HAL_Bool HAL_GetCounterDirection(HAL_CounterHandle counterHandle,
+                                 int32_t* status);
+
+/**
+ * Sets the Counter to return reversed sensing on the direction.
+ *
+ * This allows counters to change the direction they are counting in the case of
+ * 1X and 2X quadrature encoding only. Any other counter mode isn't supported.
+ *
+ * @param counterHandle    the counter handle
+ * @param reverseDirection true if the value counted should be negated.
+ */
+void HAL_SetCounterReverseDirection(HAL_CounterHandle counterHandle,
+                                    HAL_Bool reverseDirection, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/DIO.h b/hal/src/main/native/include/hal/DIO.h
new file mode 100644
index 0000000..7812306
--- /dev/null
+++ b/hal/src/main/native/include/hal/DIO.h
@@ -0,0 +1,200 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_dio DIO Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a new instance of a digital port.
+ *
+ * @param portHandle the port handle to create from
+ * @param input      true for input, false for output
+ * @return           the created digital handle
+ */
+HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
+                                        HAL_Bool input, int32_t* status);
+
+/**
+ * Checks if a DIO channel is valid.
+ *
+ * @param channel the channel number to check
+ * @return        true if the channel is correct, otherwise false
+ */
+HAL_Bool HAL_CheckDIOChannel(int32_t channel);
+
+void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle);
+
+/**
+ * Allocates a DO PWM Generator.
+ *
+ * @return the allocated digital PWM handle
+ */
+HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status);
+
+/**
+ * Frees the resource associated with a DO PWM generator.
+ *
+ * @param pwmGenerator the digital PWM handle
+ */
+void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status);
+
+/**
+ * Changes the frequency of the DO PWM generator.
+ *
+ * The valid range is from 0.6 Hz to 19 kHz.
+ *
+ *  The frequency resolution is logarithmic.
+ *
+ * @param rate the frequency to output all digital output PWM signals
+ */
+void HAL_SetDigitalPWMRate(double rate, int32_t* status);
+
+/**
+ * Configures the duty-cycle of the PWM generator.
+ *
+ * @param pwmGenerator the digital PWM handle
+ * @param dutyCycle    the percent duty cycle to output [0..1]
+ */
+void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
+                                double dutyCycle, int32_t* status);
+
+/**
+ * Configures which DO channel the PWM signal is output on.
+ *
+ * @param pwmGenerator the digital PWM handle
+ * @param channel      the channel to output on
+ */
+void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
+                                    int32_t channel, int32_t* status);
+
+/**
+ * Writes a digital value to a DIO channel.
+ *
+ * @param dioPortHandle the digital port handle
+ * @param value         the state to set the digital channel (if it is
+ * configured as an output)
+ */
+void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
+                int32_t* status);
+
+/**
+ * Sets the direction of a DIO channel.
+ *
+ * @param dioPortHandle the digital port handle
+ * @param input         true to set input, false for output
+ */
+void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
+                         int32_t* status);
+
+/**
+ * Reads a digital value from a DIO channel.
+ *
+ * @param dioPortHandle the digital port handle
+ * @return              the state of the specified channel
+ */
+HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status);
+
+/**
+ * Reads the direction of a DIO channel.
+ *
+ * @param dioPortHandle the digital port handle
+ * @return              true for input, false for output
+ */
+HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status);
+
+/**
+ * Generates a single digital pulse.
+ *
+ * Write a pulse to the specified digital output channel. There can only be a
+ * single pulse going at any time.
+ *
+ * @param dioPortHandle the digital port handle
+ * @param pulseLength   the active length of the pulse (in seconds)
+ */
+void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
+               int32_t* status);
+
+/**
+ * Checks a DIO line to see if it is currently generating a pulse.
+ *
+ * @return true if a pulse is in progress, otherwise false
+ */
+HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status);
+
+/**
+ * Checks if any DIO line is currently generating a pulse.
+ *
+ * @return true if a pulse on some line is in progress
+ */
+HAL_Bool HAL_IsAnyPulsing(int32_t* status);
+
+/**
+ * Writes the filter index from the FPGA.
+ *
+ * Set the filter index used to filter out short pulses.
+ *
+ * @param dioPortHandle the digital port handle
+ * @param filterIndex   the filter index (Must be in the range 0 - 3, where 0
+ * means "none" and 1 - 3 means filter # filterIndex - 1)
+ */
+void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
+                         int32_t* status);
+
+/**
+ * Reads the filter index from the FPGA.
+ *
+ * Gets the filter index used to filter out short pulses.
+ *
+ * @param dioPortHandle the digital port handle
+ * @return filterIndex  the filter index (Must be in the range 0 - 3,
+ * where 0 means "none" and 1 - 3 means filter # filterIndex - 1)
+ */
+int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status);
+
+/**
+ * Sets the filter period for the specified filter index.
+ *
+ * Sets the filter period in FPGA cycles.  Even though there are 2 different
+ * filter index domains (MXP vs HDR), ignore that distinction for now since it
+ * compilicates the interface.  That can be changed later.
+ *
+ * @param filterIndex the filter index, 0 - 2
+ * @param value       the number of cycles that the signal must not transition
+ * to be counted as a transition.
+ */
+void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status);
+
+/**
+ * Gets the filter period for the specified filter index.
+ *
+ * Gets the filter period in FPGA cycles.  Even though there are 2 different
+ * filter index domains (MXP vs HDR), ignore that distinction for now since it
+ * compilicates the interface.  Set status to NiFpga_Status_SoftwareFault if the
+ * filter values miss-match.
+ *
+ * @param filterIndex the filter index, 0 - 2
+ * @param value       the number of cycles that the signal must not transition
+ * to be counted as a transition.
+ */
+int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/DriverStation.h b/hal/src/main/native/include/hal/DriverStation.h
new file mode 100644
index 0000000..1c18681
--- /dev/null
+++ b/hal/src/main/native/include/hal/DriverStation.h
@@ -0,0 +1,276 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2013-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/DriverStationTypes.h"
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_driverstation Driver Station Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Sends an error to the driver station.
+ *
+ * @param isError   true for error, false for warning
+ * @param errorCode the error code
+ * @param isLVCode  true for a LV error code, false for a standard error code
+ * @param details   the details of the error
+ * @param location  the file location of the errror
+ * @param callstack the callstack of the error
+ * @param printMsg  true to print the error message to stdout as well as to the
+ * DS
+ */
+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);
+
+/**
+ * Gets the current control word of the driver station.
+ *
+ * The control work contains the robot state.
+ *
+ * @param controlWord the control word (out)
+ * @return            the error code, or 0 for success
+ */
+int32_t HAL_GetControlWord(HAL_ControlWord* controlWord);
+
+/**
+ * Gets the current alliance station ID.
+ *
+ * @param status the error code, or 0 for success
+ * @return       the alliance station ID
+ */
+HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status);
+
+/**
+ * Gets the axes of a specific joystick.
+ *
+ * @param joystickNum the joystick number
+ * @param axes        the axes values (output)
+ * @return            the error code, or 0 for success
+ */
+int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes);
+
+/**
+ * Gets the POVs of a specific joystick.
+ *
+ * @param joystickNum the joystick number
+ * @param povs        the POV values (output)
+ * @return            the error code, or 0 for success
+ */
+int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs);
+
+/**
+ * Gets the buttons of a specific joystick.
+ *
+ * @param joystickNum the joystick number
+ * @param buttons     the button values (output)
+ * @return            the error code, or 0 for success
+ */
+int32_t HAL_GetJoystickButtons(int32_t joystickNum,
+                               HAL_JoystickButtons* buttons);
+
+/**
+ * Retrieves the Joystick Descriptor for particular slot.
+ *
+ * @param desc [out] descriptor (data transfer object) to fill in.  desc is
+ * filled in regardless of success. In other words, if descriptor is not
+ * available, desc is filled in with default values matching the init-values in
+ * Java and C++ Driverstation for when caller requests a too-large joystick
+ * index.
+ *
+ * @return error code reported from Network Comm back-end.  Zero is good,
+ * nonzero is bad.
+ */
+int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
+                                  HAL_JoystickDescriptor* desc);
+
+/**
+ * Gets is a specific joystick is considered to be an XBox controller.
+ *
+ * @param joystickNum the joystick number
+ * @return            true if xbox, false otherwise
+ */
+HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum);
+
+/**
+ * Gets the type of joystick connected.
+ *
+ * This is device specific, and different depending on what system input type
+ * the joystick uses.
+ *
+ * @param joystickNum the joystick number
+ * @return            the enumerated joystick type
+ */
+int32_t HAL_GetJoystickType(int32_t joystickNum);
+
+/**
+ * Gets the name of a joystick.
+ *
+ * The returned array must be freed with HAL_FreeJoystickName.
+ *
+ * Will be null terminated.
+ *
+ * @param joystickNum the joystick number
+ * @return            the joystick name
+ */
+char* HAL_GetJoystickName(int32_t joystickNum);
+
+/**
+ * Frees a joystick name received with HAL_GetJoystickName
+ *
+ * @param name the name storage
+ */
+void HAL_FreeJoystickName(char* name);
+
+/**
+ * Gets the type of a specific joystick axis.
+ *
+ * This is device specific, and different depending on what system input type
+ * the joystick uses.
+ *
+ * @param joystickNum the joystick number
+ * @param axis        the axis number
+ * @return            the enumerated axis type
+ */
+int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis);
+
+/**
+ * Set joystick outputs.
+ *
+ * @param joystickNum the joystick numer
+ * @param outputs     bitmask of outputs, 1 for on 0 for off
+ * @param leftRumble  the left rumble value (0-FFFF)
+ * @param rightRumble the right rumble value (0-FFFF)
+ * @return            the error code, or 0 for success
+ */
+int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
+                               int32_t leftRumble, int32_t rightRumble);
+
+/**
+ * Returns the approximate match time.
+ *
+ * The FMS does not send an official match time to the robots, but does send
+ * an approximate match time. The value will count down the time remaining in
+ * the current period (auto or teleop).
+ *
+ * Warning: This is not an official time (so it cannot be used to dispute ref
+ * calls or guarantee that a function will trigger before the match ends).
+ *
+ * The Practice Match function of the DS approximates the behaviour seen on
+ * the field.
+ *
+ * @param status the error code, or 0 for success
+ * @return time remaining in current match period (auto or teleop)
+ */
+double HAL_GetMatchTime(int32_t* status);
+
+/**
+ * Gets info about a specific match.
+ *
+ * @param info the match info (output)
+ * @return     the error code, or 0 for success
+ */
+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.
+ */
+void HAL_ReleaseDSMutex(void);
+
+/**
+ * Has a new control packet from the driver station arrived since the last
+ * time this function was called?
+ *
+ * @return true if the control data has been updated since the last call
+ */
+HAL_Bool HAL_IsNewControlData(void);
+
+/**
+ * Waits for the newest DS packet to arrive. Note that this is a blocking call.
+ */
+void HAL_WaitForDSData(void);
+
+/**
+ * Waits for the newest DS packet to arrive. If timeout is <= 0, this will wait
+ * forever. Otherwise, it will wait until either a new packet, or the timeout
+ * time has passed.
+ *
+ * @param timeout timeout in seconds
+ * @return        true for new data, false for timeout
+ */
+HAL_Bool HAL_WaitForDSDataTimeout(double timeout);
+
+/**
+ * Initializes the driver station communication. This will properly
+ * handle multiple calls. However note that this CANNOT be called from a library
+ * that interfaces with LabVIEW.
+ */
+void HAL_InitializeDriverStation(void);
+
+/**
+ * Sets the program starting flag in the DS.
+ *
+ * This is what changes the DS to showing robot code ready.
+ */
+void HAL_ObserveUserProgramStarting(void);
+
+/**
+ * Sets the disabled flag in the DS.
+ *
+ * This is used for the DS to ensure the robot is properly responding to its
+ * state request. Ensure this get called about every 50ms, or the robot will be
+ * disabled by the DS.
+ */
+void HAL_ObserveUserProgramDisabled(void);
+
+/**
+ * Sets the autonomous enabled flag in the DS.
+ *
+ * This is used for the DS to ensure the robot is properly responding to its
+ * state request. Ensure this get called about every 50ms, or the robot will be
+ * disabled by the DS.
+ */
+void HAL_ObserveUserProgramAutonomous(void);
+
+/**
+ * Sets the teleoperated enabled flag in the DS.
+ *
+ * This is used for the DS to ensure the robot is properly responding to its
+ * state request. Ensure this get called about every 50ms, or the robot will be
+ * disabled by the DS.
+ */
+void HAL_ObserveUserProgramTeleop(void);
+
+/**
+ * Sets the test mode flag in the DS.
+ *
+ * This is used for the DS to ensure the robot is properly responding to its
+ * state request. Ensure this get called about every 50ms, or the robot will be
+ * disabled by the DS.
+ */
+void HAL_ObserveUserProgramTest(void);
+
+#endif  // HAL_USE_LABVIEW
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/DriverStationTypes.h b/hal/src/main/native/include/hal/DriverStationTypes.h
new file mode 100644
index 0000000..7c5d6f6
--- /dev/null
+++ b/hal/src/main/native/include/hal/DriverStationTypes.h
@@ -0,0 +1,110 @@
+/*----------------------------------------------------------------------------*/
+/* 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_driverstation Driver Station Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#define HAL_IO_CONFIG_DATA_SIZE 32
+#define HAL_SYS_STATUS_DATA_SIZE 44
+#define HAL_USER_STATUS_DATA_SIZE \
+  (984 - HAL_IO_CONFIG_DATA_SIZE - HAL_SYS_STATUS_DATA_SIZE)
+
+#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Input 17
+#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Output 18
+#define HALFRC_NetworkCommunication_DynamicType_Kinect_Header 19
+#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra1 20
+#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices1 21
+#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra2 22
+#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices2 23
+#define HALFRC_NetworkCommunication_DynamicType_Kinect_Joystick 24
+#define HALFRC_NetworkCommunication_DynamicType_Kinect_Custom 25
+
+struct HAL_ControlWord {
+  uint32_t enabled : 1;
+  uint32_t autonomous : 1;
+  uint32_t test : 1;
+  uint32_t eStop : 1;
+  uint32_t fmsAttached : 1;
+  uint32_t dsAttached : 1;
+  uint32_t control_reserved : 26;
+};
+typedef struct HAL_ControlWord HAL_ControlWord;
+
+// clang-format off
+HAL_ENUM(HAL_AllianceStationID) {
+  HAL_AllianceStationID_kRed1,
+  HAL_AllianceStationID_kRed2,
+  HAL_AllianceStationID_kRed3,
+  HAL_AllianceStationID_kBlue1,
+  HAL_AllianceStationID_kBlue2,
+  HAL_AllianceStationID_kBlue3,
+};
+
+HAL_ENUM(HAL_MatchType) {
+  HAL_kMatchType_none,
+  HAL_kMatchType_practice,
+  HAL_kMatchType_qualification,
+  HAL_kMatchType_elimination,
+};
+// clang-format on
+
+/* The maximum number of axes that will be stored in a single HALJoystickAxes
+ * struct. This is used for allocating buffers, not bounds checking, since
+ * there are usually less axes in practice.
+ */
+#define HAL_kMaxJoystickAxes 12
+#define HAL_kMaxJoystickPOVs 12
+#define HAL_kMaxJoysticks 6
+
+struct HAL_JoystickAxes {
+  int16_t count;
+  float axes[HAL_kMaxJoystickAxes];
+};
+typedef struct HAL_JoystickAxes HAL_JoystickAxes;
+
+struct HAL_JoystickPOVs {
+  int16_t count;
+  int16_t povs[HAL_kMaxJoystickPOVs];
+};
+typedef struct HAL_JoystickPOVs HAL_JoystickPOVs;
+
+struct HAL_JoystickButtons {
+  uint32_t buttons;
+  uint8_t count;
+};
+typedef struct HAL_JoystickButtons HAL_JoystickButtons;
+
+struct HAL_JoystickDescriptor {
+  uint8_t isXbox;
+  uint8_t type;
+  char name[256];
+  uint8_t axisCount;
+  uint8_t axisTypes[HAL_kMaxJoystickAxes];
+  uint8_t buttonCount;
+  uint8_t povCount;
+};
+typedef struct HAL_JoystickDescriptor HAL_JoystickDescriptor;
+
+struct HAL_MatchInfo {
+  char eventName[64];
+  HAL_MatchType matchType;
+  uint16_t matchNumber;
+  uint8_t replayNumber;
+  uint8_t gameSpecificMessage[64];
+  uint16_t gameSpecificMessageSize;
+};
+typedef struct HAL_MatchInfo HAL_MatchInfo;
+/** @} */
diff --git a/hal/src/main/native/include/hal/Encoder.h b/hal/src/main/native/include/hal/Encoder.h
new file mode 100644
index 0000000..449b814
--- /dev/null
+++ b/hal/src/main/native/include/hal/Encoder.h
@@ -0,0 +1,301 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/AnalogTrigger.h"
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_encoder Encoder Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+/**
+ * The type of index pulse for the encoder.
+ */
+HAL_ENUM(HAL_EncoderIndexingType) {
+  HAL_kResetWhileHigh,
+  HAL_kResetWhileLow,
+  HAL_kResetOnFallingEdge,
+  HAL_kResetOnRisingEdge
+};
+
+/**
+ * The encoding scaling of the encoder.
+ */
+HAL_ENUM(HAL_EncoderEncodingType) {
+  HAL_Encoder_k1X,
+  HAL_Encoder_k2X,
+  HAL_Encoder_k4X
+};
+// clang-format on
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes an encoder.
+ *
+ * @param digitalSourceHandleA the A source (either a HAL_DigitalHandle or a
+ * HAL_AnalogTriggerHandle)
+ * @param analogTriggerTypeA   the analog trigger type of the A source if it is
+ * an analog trigger
+ * @param digitalSourceHandleB the B source (either a HAL_DigitalHandle or a
+ * HAL_AnalogTriggerHandle)
+ * @param analogTriggerTypeB   the analog trigger type of the B source if it is
+ * an analog trigger
+ * @param reverseDirection     true to reverse the counting direction from
+ * standard, otherwise false
+ * @param encodingType         the encoding type
+   @return                     the created encoder handle
+ */
+HAL_EncoderHandle HAL_InitializeEncoder(
+    HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
+    HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
+    HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
+    int32_t* status);
+
+/**
+ * Frees an encoder.
+ *
+ * @param encoderHandle the encoder handle
+ */
+void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/**
+ * Gets the current counts of the encoder after encoding type scaling.
+ *
+ * This is scaled by the value passed duing initialization to encodingType.
+ *
+ * @param encoderHandle the encoder handle
+ * @return the current scaled count
+ */
+int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/**
+ * Gets the raw counts of the encoder.
+ *
+ * This is not scaled by any values.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the raw encoder count
+ */
+int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/**
+ * Gets the encoder scale value.
+ *
+ * This is set by the value passed during initialization to encodingType.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the encoder scale value
+ */
+int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
+                                    int32_t* status);
+
+/**
+ * Reads the current encoder value.
+ *
+ * Read the value at this instant. It may still be running, so it reflects the
+ * current value. Next time it is read, it might have a different value.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the current encoder value
+ */
+void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/*
+ * Gets the Period of the most recent count.
+ *
+ * Returns the time interval of the most recent count. This can be used for
+ * velocity calculations to determine shaft speed.
+ *
+ * @param encoderHandle the encoder handle
+ * @returns             the period of the last two pulses in units of seconds
+ */
+double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/**
+ * Sets the maximum period where the device is still considered "moving".
+ *
+ * Sets the maximum period where the device is considered moving. This value is
+ * used to determine the "stopped" state of the encoder using the
+ * HAL_GetEncoderStopped method.
+ *
+ * @param encoderHandle the encoder handle
+ * @param maxPeriod     the maximum period where the counted device is
+ * considered moving in seconds
+ */
+void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
+                             int32_t* status);
+
+/**
+ * Determines if the clock is stopped.
+ *
+ * Determines if the clocked input is stopped based on the MaxPeriod value set
+ * using the SetMaxPeriod method. If the clock exceeds the MaxPeriod, then the
+ * device (and encoder) are assumed to be stopped and it returns true.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              true if the most recent encoder period exceeds the
+ * MaxPeriod value set by SetMaxPeriod
+ */
+HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
+                               int32_t* status);
+
+/**
+ * Gets the last direction the encoder value changed.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the last direction the encoder value changed
+ */
+HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
+                                 int32_t* status);
+
+/**
+ * Gets the current distance traveled by the encoder.
+ *
+ * This is the encoder count scaled by the distance per pulse set for the
+ * encoder.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the encoder distance (units are determined by the units
+ * passed to HAL_SetEncoderDistancePerPulse)
+ */
+double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/**
+ * Gets the current rate of the encoder.
+ *
+ * This is the encoder period scaled by the distance per pulse set for the
+ * encoder.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the encoder rate (units are determined by the units
+ * passed to HAL_SetEncoderDistancePerPulse, time value is seconds)
+ */
+double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/**
+ * Sets the minimum rate to be considered moving by the encoder.
+ *
+ * Units need to match what is set by HAL_SetEncoderDistancePerPulse, with time
+ * as seconds.
+ *
+ * @param encoderHandle the encoder handle
+ * @param minRate       the minimum rate to be considered moving (units are
+ * determined by the units passed to HAL_SetEncoderDistancePerPulse, time value
+ * is seconds)
+ */
+void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
+                           int32_t* status);
+
+/**
+ * Sets the distance traveled per encoder pulse. This is used as a scaling
+ * factor for the rate and distance calls.
+ *
+ * @param encoderHandle    the encoder handle
+ * @param distancePerPulse the distance traveled per encoder pulse (units user
+ * defined)
+ */
+void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
+                                    double distancePerPulse, int32_t* status);
+
+/**
+ * Sets if to reverse the direction of the encoder.
+ *
+ * Note that this is not a toggle. It is an absolute set.
+ *
+ * @param encoderHandle    the encoder handle
+ * @param reverseDirection true to reverse the direction, false to not.
+ */
+void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
+                                    HAL_Bool reverseDirection, int32_t* status);
+
+/**
+ * Sets the number of encoder samples to average when calculating encoder rate.
+ *
+ * @param encoderHandle    the encoder handle
+ * @param samplesToAverage the number of samples to average
+ */
+void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
+                                    int32_t samplesToAverage, int32_t* status);
+
+/**
+ * Gets the current samples to average value.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the current samples to average value
+ */
+int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
+                                       int32_t* status);
+
+/**
+ * Sets the source for an index pulse on the encoder.
+ *
+ * The index pulse can be used to cause an encoder to reset based on an external
+ * input.
+ *
+ * @param encoderHandle       the encoder handle
+ * @param digitalSourceHandle the index source handle (either a
+ * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
+ * @param analogTriggerType   the analog trigger type if the source is an analog
+ * trigger
+ * @param type                the index triggering type
+ */
+void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
+                               HAL_Handle digitalSourceHandle,
+                               HAL_AnalogTriggerType analogTriggerType,
+                               HAL_EncoderIndexingType type, int32_t* status);
+
+/**
+ * Gets the FPGA index of the encoder.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the FPGA index of the encoder
+ */
+int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
+                                int32_t* status);
+
+/**
+ * Gets the decoding scale factor of the encoder.
+ *
+ * This is used to perform the scaling from raw to type scaled values.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the scale value for the encoder
+ */
+double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
+                                         int32_t* status);
+
+/**
+ * Gets the user set distance per pulse of the encoder.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the set distance per pulse
+ */
+double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
+                                      int32_t* status);
+
+/**
+ * Gets the encoding type of the encoder.
+ *
+ * @param encoderHandle the encoder handle
+ * @return              the encoding type
+ */
+HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
+    HAL_EncoderHandle encoderHandle, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Errors.h b/hal/src/main/native/include/hal/Errors.h
new file mode 100644
index 0000000..4476ab0
--- /dev/null
+++ b/hal/src/main/native/include/hal/Errors.h
@@ -0,0 +1,132 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+/**
+ * @defgroup hal_errors Error Defines
+ * @ingroup hal_capi
+ * @{
+ */
+
+#define CTR_RxTimeout_MESSAGE "CTRE CAN Receive Timeout"
+#define CTR_TxTimeout_MESSAGE "CTRE CAN Transmit Timeout"
+#define CTR_InvalidParamValue_MESSAGE "CTRE CAN Invalid Parameter"
+#define CTR_UnexpectedArbId_MESSAGE \
+  "CTRE Unexpected Arbitration ID (CAN Node ID)"
+#define CTR_TxFailed_MESSAGE "CTRE CAN Transmit Error"
+#define CTR_SigNotUpdated_MESSAGE "CTRE CAN Signal Not Updated"
+
+#define NiFpga_Status_FifoTimeout_MESSAGE "NIFPGA: FIFO timeout error"
+#define NiFpga_Status_TransferAborted_MESSAGE "NIFPGA: Transfer aborted error"
+#define NiFpga_Status_MemoryFull_MESSAGE \
+  "NIFPGA: Memory Allocation failed, memory full"
+#define NiFpga_Status_SoftwareFault_MESSAGE "NIFPGA: Unexpected software error"
+#define NiFpga_Status_InvalidParameter_MESSAGE "NIFPGA: Invalid Parameter"
+#define NiFpga_Status_ResourceNotFound_MESSAGE "NIFPGA: Resource not found"
+#define NiFpga_Status_ResourceNotInitialized_MESSAGE \
+  "NIFPGA: Resource not initialized"
+#define NiFpga_Status_HardwareFault_MESSAGE "NIFPGA: Hardware Fault"
+#define NiFpga_Status_IrqTimeout_MESSAGE "NIFPGA: Interrupt timeout"
+
+#define ERR_CANSessionMux_InvalidBuffer_MESSAGE "CAN: Invalid Buffer"
+#define ERR_CANSessionMux_MessageNotFound_MESSAGE "CAN: Message not found"
+#define WARN_CANSessionMux_NoToken_MESSAGE "CAN: No token"
+#define ERR_CANSessionMux_NotAllowed_MESSAGE "CAN: Not allowed"
+#define ERR_CANSessionMux_NotInitialized_MESSAGE "CAN: Not initialized"
+
+#define ERR_FRCSystem_NetCommNotResponding_MESSAGE \
+  "FRCSystem: NetComm not responding"
+#define ERR_FRCSystem_NoDSConnection_MESSAGE \
+  "FRCSystem: No driver station connected"
+
+#define SAMPLE_RATE_TOO_HIGH 1001
+#define SAMPLE_RATE_TOO_HIGH_MESSAGE \
+  "HAL: Analog module sample rate is too high"
+#define VOLTAGE_OUT_OF_RANGE 1002
+#define VOLTAGE_OUT_OF_RANGE_MESSAGE \
+  "HAL: Voltage to convert to raw value is out of range [0; 5]"
+#define LOOP_TIMING_ERROR 1004
+#define LOOP_TIMING_ERROR_MESSAGE \
+  "HAL: Digital module loop timing is not the expected value"
+#define SPI_WRITE_NO_MOSI 1012
+#define SPI_WRITE_NO_MOSI_MESSAGE \
+  "HAL: Cannot write to SPI port with no MOSI output"
+#define SPI_READ_NO_MISO 1013
+#define SPI_READ_NO_MISO_MESSAGE \
+  "HAL: Cannot read from SPI port with no MISO input"
+#define SPI_READ_NO_DATA 1014
+#define SPI_READ_NO_DATA_MESSAGE "HAL: No data available to read from SPI"
+#define INCOMPATIBLE_STATE 1015
+#define INCOMPATIBLE_STATE_MESSAGE \
+  "HAL: Incompatible State: The operation cannot be completed"
+#define NO_AVAILABLE_RESOURCES -1004
+#define NO_AVAILABLE_RESOURCES_MESSAGE "HAL: No available resources to allocate"
+#define NULL_PARAMETER -1005
+#define NULL_PARAMETER_MESSAGE "HAL: A pointer parameter to a method is NULL"
+#define ANALOG_TRIGGER_LIMIT_ORDER_ERROR -1010
+#define ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE \
+  "HAL: AnalogTrigger limits error.  Lower limit > Upper Limit"
+#define ANALOG_TRIGGER_PULSE_OUTPUT_ERROR -1011
+#define ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE \
+  "HAL: Attempted to read AnalogTrigger pulse output."
+#define PARAMETER_OUT_OF_RANGE -1028
+#define PARAMETER_OUT_OF_RANGE_MESSAGE "HAL: A parameter is out of range."
+#define RESOURCE_IS_ALLOCATED -1029
+#define RESOURCE_IS_ALLOCATED_MESSAGE "HAL: Resource already allocated"
+#define RESOURCE_OUT_OF_RANGE -1030
+#define RESOURCE_OUT_OF_RANGE_MESSAGE \
+  "HAL: The requested resource is out of range."
+#define HAL_INVALID_ACCUMULATOR_CHANNEL -1035
+#define HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE \
+  "HAL: The requested input is not an accumulator channel"
+#define HAL_COUNTER_NOT_SUPPORTED -1058
+#define HAL_COUNTER_NOT_SUPPORTED_MESSAGE \
+  "HAL: Counter mode not supported for encoder method"
+#define HAL_PWM_SCALE_ERROR -1072
+#define HAL_PWM_SCALE_ERROR_MESSAGE \
+  "HAL: The PWM Scale Factors are out of range"
+#define HAL_HANDLE_ERROR -1098
+#define HAL_HANDLE_ERROR_MESSAGE \
+  "HAL: A handle parameter was passed incorrectly"
+
+#define HAL_SERIAL_PORT_NOT_FOUND -1123
+#define HAL_SERIAL_PORT_NOT_FOUND_MESSAGE \
+  "HAL: The specified serial port device was not found"
+
+#define HAL_SERIAL_PORT_OPEN_ERROR -1124
+#define HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE \
+  "HAL: The serial port could not be opened"
+
+#define HAL_SERIAL_PORT_ERROR -1125
+#define HAL_SERIAL_PORT_ERROR_MESSAGE \
+  "HAL: There was an error on the serial port"
+
+#define HAL_THREAD_PRIORITY_ERROR -1152
+#define HAL_THREAD_PRIORITY_ERROR_MESSAGE \
+  "HAL: Getting or setting the priority of a thread has failed";
+
+#define HAL_THREAD_PRIORITY_RANGE_ERROR -1153
+#define HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE \
+  "HAL: The priority requested to be set is invalid"
+
+#define HAL_CAN_TIMEOUT -1154
+#define HAL_CAN_TIMEOUT_MESSAGE "HAL: CAN Receive has Timed Out"
+
+#define VI_ERROR_SYSTEM_ERROR_MESSAGE "HAL - VISA: System Error";
+#define VI_ERROR_INV_OBJECT_MESSAGE "HAL - VISA: Invalid Object"
+#define VI_ERROR_RSRC_LOCKED_MESSAGE "HAL - VISA: Resource Locked"
+#define VI_ERROR_RSRC_NFOUND_MESSAGE "HAL - VISA: Resource Not Found"
+#define VI_ERROR_INV_RSRC_NAME_MESSAGE "HAL - VISA: Invalid Resource Name"
+#define VI_ERROR_QUEUE_OVERFLOW_MESSAGE "HAL - VISA: Queue Overflow"
+#define VI_ERROR_IO_MESSAGE "HAL - VISA: General IO Error"
+#define VI_ERROR_ASRL_PARITY_MESSAGE "HAL - VISA: Parity Error"
+#define VI_ERROR_ASRL_FRAMING_MESSAGE "HAL - VISA: Framing Error"
+#define VI_ERROR_ASRL_OVERRUN_MESSAGE "HAL - VISA: Buffer Overrun Error"
+#define VI_ERROR_RSRC_BUSY_MESSAGE "HAL - VISA: Resource Busy"
+#define VI_ERROR_INV_PARAMETER_MESSAGE "HAL - VISA: Invalid Parameter"
+/** @} */
diff --git a/hal/src/main/native/include/hal/Extensions.h b/hal/src/main/native/include/hal/Extensions.h
new file mode 100644
index 0000000..0fcbcba
--- /dev/null
+++ b/hal/src/main/native/include/hal/Extensions.h
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+/**
+ * @defgroup hal_extensions Simulator Extensions
+ * @ingroup hal_capi
+ * HAL Simulator Extensions.  These are libraries that provide additional
+ * simulator functionality, such as a Gazebo interface, or a more light weight
+ * simulation.
+ *
+ * An extension must expose the HALSIM_InitExtension entry point which is
+ * invoked after the library is loaded.
+ *
+ * The entry point is expected to return < 0 for errors that should stop
+ * the HAL completely, 0 for success, and > 0 for a non fatal error.
+ * @{
+ */
+typedef int halsim_extension_init_func_t(void);
+
+extern "C" {
+/**
+ * Loads a single extension from a direct path.
+ *
+ * Expected to be called internally, not by users.
+ *
+ * @param library the library path
+ * @return        the succes state of the initialization
+ */
+int HAL_LoadOneExtension(const char* library);
+
+/**
+ * Loads any extra halsim libraries provided in the HALSIM_EXTENSIONS
+ * environment variable.
+ *
+ * @return        the succes state of the initialization
+ */
+int HAL_LoadExtensions(void);
+}  // extern "C"
+/** @} */
diff --git a/hal/src/main/native/include/hal/HAL.h b/hal/src/main/native/include/hal/HAL.h
new file mode 100644
index 0000000..f0da13f
--- /dev/null
+++ b/hal/src/main/native/include/hal/HAL.h
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2013-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>
+
+#ifndef HAL_USE_LABVIEW
+
+#include "hal/Accelerometer.h"
+#include "hal/AnalogAccumulator.h"
+#include "hal/AnalogGyro.h"
+#include "hal/AnalogInput.h"
+#include "hal/AnalogOutput.h"
+#include "hal/AnalogTrigger.h"
+#include "hal/CAN.h"
+#include "hal/Compressor.h"
+#include "hal/Constants.h"
+#include "hal/Counter.h"
+#include "hal/DIO.h"
+#include "hal/DriverStation.h"
+#include "hal/Errors.h"
+#include "hal/I2C.h"
+#include "hal/Interrupts.h"
+#include "hal/Notifier.h"
+#include "hal/PDP.h"
+#include "hal/PWM.h"
+#include "hal/Ports.h"
+#include "hal/Power.h"
+#include "hal/Relay.h"
+#include "hal/SPI.h"
+#include "hal/SerialPort.h"
+#include "hal/Solenoid.h"
+
+#endif  // HAL_USE_LABVIEW
+
+#include "hal/Types.h"
+#include "hal/HALBase.h"
+
+#ifdef __cplusplus
+#include "hal/FRCUsageReporting.h"
+#endif
diff --git a/hal/src/main/native/include/hal/HALBase.h b/hal/src/main/native/include/hal/HALBase.h
new file mode 100644
index 0000000..fd22c0c
--- /dev/null
+++ b/hal/src/main/native/include/hal/HALBase.h
@@ -0,0 +1,182 @@
+/*----------------------------------------------------------------------------*/

+/* 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

+/** @} */

diff --git a/hal/src/main/native/include/hal/I2C.h b/hal/src/main/native/include/hal/I2C.h
new file mode 100644
index 0000000..fc8b5c8
--- /dev/null
+++ b/hal/src/main/native/include/hal/I2C.h
@@ -0,0 +1,93 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/I2CTypes.h"
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_i2c I2C Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes the I2C port.
+ *
+ * Opens the port if necessary and saves the handle.
+ * If opening the MXP port, also sets up the channel functions appropriately.
+ *
+ * @param port The port to open, 0 for the on-board, 1 for the MXP.
+ */
+void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status);
+
+/**
+ * Generic I2C read/write transaction.
+ *
+ * This is a lower-level interface to the I2C hardware giving you more control
+ * over each transaction.
+ *
+ * @param port The I2C port, 0 for the on-board, 1 for the MXP.
+ * @param dataToSend Buffer of data to send as part of the transaction.
+ * @param sendSize Number of bytes to send as part of the transaction.
+ * @param dataReceived Buffer to read data into.
+ * @param receiveSize Number of bytes to read from the device.
+ * @return >= 0 on success or -1 on transfer abort.
+ */
+int32_t HAL_TransactionI2C(HAL_I2CPort port, int32_t deviceAddress,
+                           const uint8_t* dataToSend, int32_t sendSize,
+                           uint8_t* dataReceived, int32_t receiveSize);
+
+/**
+ * Executes a write transaction with the device.
+ *
+ * Writes a single byte to a register on a device and wait until the
+ *   transaction is complete.
+ *
+ * @param port The I2C port, 0 for the on-board, 1 for the MXP.
+ * @param registerAddress The address of the register on the device to be
+ * written.
+ * @param data The byte to write to the register on the device.
+ * @return >= 0 on success or -1 on transfer abort.
+ */
+int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress,
+                     const uint8_t* dataToSend, int32_t sendSize);
+
+/**
+ * Executes a read transaction with the device.
+ *
+ * Reads bytes from a device.
+ * Most I2C devices will auto-increment the register pointer internally allowing
+ *   you to read consecutive registers on a device in a single transaction.
+ *
+ * @param port The I2C port, 0 for the on-board, 1 for the MXP.
+ * @param registerAddress The register to read first in the transaction.
+ * @param count The number of bytes to read in the transaction.
+ * @param buffer A pointer to the array of bytes to store the data read from the
+ * device.
+ * @return >= 0 on success or -1 on transfer abort.
+ */
+int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer,
+                    int32_t count);
+
+/**
+ * Closes an I2C port
+ *
+ * @param port The I2C port, 0 for the on-board, 1 for the MXP.
+ */
+void HAL_CloseI2C(HAL_I2CPort port);
+#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
new file mode 100644
index 0000000..d0b269f
--- /dev/null
+++ b/hal/src/main/native/include/hal/I2CTypes.h
@@ -0,0 +1,24 @@
+/*----------------------------------------------------------------------------*/
+/* 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_i2c I2C Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+HAL_ENUM(HAL_I2CPort) { HAL_I2C_kInvalid = -1, HAL_I2C_kOnboard, HAL_I2C_kMXP };
+// clang-format on
+
+/** @} */
diff --git a/hal/src/main/native/include/hal/Interrupts.h b/hal/src/main/native/include/hal/Interrupts.h
new file mode 100644
index 0000000..126b92c
--- /dev/null
+++ b/hal/src/main/native/include/hal/Interrupts.h
@@ -0,0 +1,159 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/AnalogTrigger.h"
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_interrupts Interrupts Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*HAL_InterruptHandlerFunction)(uint32_t interruptAssertedMask,
+                                             void* param);
+
+/**
+ * Initializes an interrupt.
+ *
+ * @param watcher true for synchronous interrupts, false for asynchronous
+ * @return        the created interrupt handle
+ */
+HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher, int32_t* status);
+
+/**
+ * Frees an interrupt.
+ *
+ * @param interruptHandle the interrupt handle
+ * @return                the param passed to the interrupt, or nullptr if one
+ * wasn't passed.
+ */
+void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
+
+/**
+ * In synchronous mode, waits for the defined interrupt to occur.
+ *
+ * @param interruptHandle the interrupt handle
+ * @param timeout        timeout in seconds
+ * @param ignorePrevious if true, ignore interrupts that happened before
+ * waitForInterrupt was called
+ * @return               the mask of interrupts that fired
+ */
+int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
+                             double timeout, HAL_Bool ignorePrevious,
+                             int32_t* status);
+
+/**
+ * Enables interrupts to occur on this input.
+ *
+ * Interrupts are disabled when the RequestInterrupt call is made. This gives
+ * time to do the setup of the other options before starting to field
+ * interrupts.
+ *
+ * @param interruptHandle the interrupt handle
+ */
+void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
+
+/**
+ * Disables interrupts without without deallocating structures.
+ *
+ * @param interruptHandle the interrupt handle
+ */
+void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
+                           int32_t* status);
+
+/**
+ * Returns the timestamp for the rising interrupt that occurred most recently.
+ *
+ * This is in the same time domain as HAL_GetFPGATime().  It only contains the
+ * bottom 32 bits of the timestamp.  If your robot has been running for over 1
+ * hour, you will need to fill in the upper 32 bits yourself.
+ *
+ * @param interruptHandle the interrupt handle
+ * @return                timestamp in microseconds since FPGA Initialization
+ */
+int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
+                                         int32_t* status);
+
+/**
+ * Returns the timestamp for the falling interrupt that occurred most recently.
+ *
+ * This is in the same time domain as HAL_GetFPGATime().  It only contains the
+ * bottom 32 bits of the timestamp.  If your robot has been running for over 1
+ * hour, you will need to fill in the upper 32 bits yourself.
+ *
+ * @param interruptHandle the interrupt handle
+ * @return                timestamp in microseconds since FPGA Initialization
+ */
+int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
+                                          int32_t* status);
+
+/**
+ * Requests interrupts on a specific digital source.
+ *
+ * @param interruptHandle     the interrupt handle
+ * @param digitalSourceHandle the digital source handle (either a
+ * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
+ * @param analogTriggerType   the trigger type if the source is an AnalogTrigger
+ */
+void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
+                           HAL_Handle digitalSourceHandle,
+                           HAL_AnalogTriggerType analogTriggerType,
+                           int32_t* status);
+
+/**
+ * Attaches an asynchronous interrupt handler to the interrupt.
+ *
+ * This interrupt gets called directly on the FPGA interrupt thread, so will
+ * block other interrupts while running.
+ *
+ * @param interruptHandle the interrupt handle
+ * @param handler         the handler function for the interrupt to call
+ * @param param           a parameter to be passed to the handler
+ */
+void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
+                                HAL_InterruptHandlerFunction handler,
+                                void* param, int32_t* status);
+
+/**
+ * Attaches an asynchronous interrupt handler to the interrupt.
+ *
+ * This interrupt gets called on a thread specific to the interrupt, so will not
+ * block other interrupts.
+ *
+ * @param interruptHandle the interrupt handle
+ * @param handler         the handler function for the interrupt to call
+ * @param param           a parameter to be passed to the handler
+ */
+void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
+                                        HAL_InterruptHandlerFunction handler,
+                                        void* param, int32_t* status);
+
+/**
+ * Sets the edges to trigger the interrupt on.
+ *
+ * Note that both edges triggered is a valid configuration.
+ *
+ * @param interruptHandle the interrupt handle
+ * @param risingEdge      true for triggering on rising edge
+ * @param fallingEdge     true for triggering on falling edge
+ */
+void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
+                                  HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                  int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Notifier.h b/hal/src/main/native/include/hal/Notifier.h
new file mode 100644
index 0000000..27f20e3
--- /dev/null
+++ b/hal/src/main/native/include/hal/Notifier.h
@@ -0,0 +1,88 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_notifier Notifier Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a notifier.
+ *
+ * A notifier is an FPGA controller timer that triggers at requested intervals
+ * based on the FPGA time. This can be used to make precise control loops.
+ *
+ * @return the created notifier
+ */
+HAL_NotifierHandle HAL_InitializeNotifier(int32_t* status);
+
+/**
+ * Stops a notifier from running.
+ *
+ * This will cause any call into HAL_WaitForNotifierAlarm to return.
+ *
+ * @param notifierHandle the notifier handle
+ */
+void HAL_StopNotifier(HAL_NotifierHandle notifierHandle, int32_t* status);
+
+/**
+ * Cleans a notifier.
+ *
+ * Note this also stops a notifier if it is already running.
+ *
+ * @param notifierHandle the notifier handle
+ */
+void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status);
+
+/**
+ * Updates the trigger time for a notifier.
+ *
+ * Note that this time is an absolute time relative to HAL_GetFPGATime()
+ *
+ * @param notifierHandle the notifier handle
+ * @param triggerTime    the updated trigger time
+ */
+void HAL_UpdateNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                             uint64_t triggerTime, int32_t* status);
+
+/**
+ * Cancels the next notifier alarm.
+ *
+ * This does not cause HAL_WaitForNotifierAlarm to return.
+ *
+ * @param notifierHandle the notifier handle
+ */
+void HAL_CancelNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                             int32_t* status);
+
+/**
+ * Waits for the next alarm for the specific notifier.
+ *
+ * This is a blocking call until either the time elapses or HAL_StopNotifier
+ * gets called.
+ *
+ * @param notifierHandle the notifier handle
+ * @return               the FPGA time the notifier returned
+ */
+uint64_t HAL_WaitForNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                                  int32_t* status);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/PDP.h b/hal/src/main/native/include/hal/PDP.h
new file mode 100644
index 0000000..50873f8
--- /dev/null
+++ b/hal/src/main/native/include/hal/PDP.h
@@ -0,0 +1,122 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_pdp PDP Functions
+ * @ingroup hal_capi
+ * Functions to control the Power Distribution Panel.
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a Power Distribution Panel.
+ *
+ * @param  module the module number to initialize
+ * @return the created PDP
+ */
+HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status);
+
+/**
+ * Cleans a PDP module.
+ *
+ * @param handle the module handle
+ */
+void HAL_CleanPDP(HAL_PDPHandle handle);
+
+/**
+ * Checks if a PDP channel is valid.
+ *
+ * @param channel the channel to check
+ * @return        true if the channel is valid, otherwise false
+ */
+HAL_Bool HAL_CheckPDPChannel(int32_t channel);
+
+/**
+ * Checks if a PDP module is valid.
+ *
+ * @param channel the module to check
+ * @return        true if the module is valid, otherwise false
+ */
+HAL_Bool HAL_CheckPDPModule(int32_t module);
+
+/**
+ * Gets the temperature of the PDP.
+ *
+ * @param handle the module handle
+ * @return       the module temperature (celsius)
+ */
+double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the PDP input voltage.
+ *
+ * @param handle the module handle
+ * @return       the input voltage (volts)
+ */
+double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the current of a specific PDP channel.
+ *
+ * @param module  the module
+ * @param channel the channel
+ * @return        the channel current (amps)
+ */
+double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
+                                int32_t* status);
+
+/**
+ * Gets the total current of the PDP.
+ *
+ * @param handle the module handle
+ * @return       the total current (amps)
+ */
+double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the total power of the PDP.
+ *
+ * @param handle the module handle
+ * @return       the total power (watts)
+ */
+double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the total energy of the PDP.
+ *
+ * @param handle the module handle
+ * @return       the total energy (joules)
+ */
+double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Resets the PDP accumulated energy.
+ *
+ * @param handle the module handle
+ */
+void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Clears any PDP sticky faults.
+ *
+ * @param handle the module handle
+ */
+void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/PWM.h b/hal/src/main/native/include/hal/PWM.h
new file mode 100644
index 0000000..781a423
--- /dev/null
+++ b/hal/src/main/native/include/hal/PWM.h
@@ -0,0 +1,233 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_pwm PWM Output Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a PWM port.
+ *
+ * @param portHandle the port to initialize
+ * @return           the created pwm handle
+ */
+HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
+                                        int32_t* status);
+
+/**
+ * Frees a PWM port.
+ *
+ * @param pwmPortHandle the pwm handle
+ */
+void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status);
+
+/**
+ * Checks if a pwm channel is valid.
+ *
+ * @param channel the channel to check
+ * @return        true if the channel is valid, otherwise false
+ */
+HAL_Bool HAL_CheckPWMChannel(int32_t channel);
+
+/**
+ * Sets the configuration settings for the PWM channel.
+ *
+ * All values are in milliseconds.
+ *
+ * @param pwmPortHandle  the PWM handle
+ * @param maxPwm         the maximum PWM value
+ * @param deadbandMaxPwm the high range of the center deadband
+ * @param centerPwm      the center PWM value
+ * @param deadbandMinPwm the low range of the center deadband
+ * @param minPwm         the minimum PWM value
+ */
+void HAL_SetPWMConfig(HAL_DigitalHandle pwmPortHandle, double maxPwm,
+                      double deadbandMaxPwm, double centerPwm,
+                      double deadbandMinPwm, double minPwm, int32_t* status);
+
+/**
+ * Sets the raw configuration settings for the PWM channel.
+ *
+ * We recommend using HAL_SetPWMConfig() instead, as those values are properly
+ * scaled. Usually used for values grabbed by HAL_GetPWMConfigRaw().
+ *
+ * Values are in raw FPGA units.
+ *
+ * @param pwmPortHandle  the PWM handle
+ * @param maxPwm         the maximum PWM value
+ * @param deadbandMaxPwm the high range of the center deadband
+ * @param centerPwm      the center PWM value
+ * @param deadbandMinPwm the low range of the center deadband
+ * @param minPwm         the minimum PWM value
+ */
+void HAL_SetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t maxPwm,
+                         int32_t deadbandMaxPwm, int32_t centerPwm,
+                         int32_t deadbandMinPwm, int32_t minPwm,
+                         int32_t* status);
+
+/**
+ * Gets the raw pwm configuration settings for the PWM channel.
+ *
+ * Values are in raw FPGA units. These units have the potential to change for
+ * any FPGA release.
+ *
+ * @param pwmPortHandle  the PWM handle
+ * @param maxPwm         the maximum PWM value
+ * @param deadbandMaxPwm the high range of the center deadband
+ * @param centerPwm      the center PWM value
+ * @param deadbandMinPwm the low range of the center deadband
+ * @param minPwm         the minimum PWM value
+ */
+void HAL_GetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t* maxPwm,
+                         int32_t* deadbandMaxPwm, int32_t* centerPwm,
+                         int32_t* deadbandMinPwm, int32_t* minPwm,
+                         int32_t* status);
+
+/**
+ * Sets if the FPGA should output the center value if the input value is within
+ * the deadband.
+ *
+ * @param pwmPortHandle     the PWM handle
+ * @param eliminateDeadband true to eliminate deadband, otherwise false
+ */
+void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
+                                 HAL_Bool eliminateDeadband, int32_t* status);
+
+/**
+ * Gets the current eliminate deadband value.
+ *
+ * @param pwmPortHandle the PWM handle
+ * @return              true if set, otherwise false
+ */
+HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
+                                     int32_t* status);
+
+/**
+ * Sets a PWM channel to the desired value.
+ *
+ * The values are in raw FPGA units, and have the potential to change with any
+ * FPGA release.
+ *
+ * @param pwmPortHandle the PWM handle
+ * @param value         the PWM value to set
+ */
+void HAL_SetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t value,
+                   int32_t* status);
+
+/**
+ * Sets a PWM channel to the desired scaled value.
+ *
+ * The values range from -1 to 1 and the period is controlled by the PWM Period
+ * and MinHigh registers.
+ *
+ * @param pwmPortHandle the PWM handle
+ * @param value         the scaled PWM value to set
+ */
+void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
+                     int32_t* status);
+
+/**
+ * Sets a PWM channel to the desired position value.
+ *
+ * The values range from 0 to 1 and the period is controlled by the PWM Period
+ * and MinHigh registers.
+ *
+ * @param pwmPortHandle the PWM handle
+ * @param value         the positional PWM value to set
+ */
+void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double position,
+                        int32_t* status);
+
+/**
+ * Sets a PWM channel to be disabled.
+ *
+ * The channel is disabled until the next time it is set. Note this is different
+ * from just setting a 0 speed, as this will actively stop all signalling on the
+ * channel.
+ *
+ * @param pwmPortHandle the PWM handle.
+ */
+void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status);
+
+/**
+ * Gets a value from a PWM channel.
+ *
+ * The values are in raw FPGA units, and have the potential to change with any
+ * FPGA release.
+ *
+ * @param pwmPortHandle the PWM handle
+ * @return              the current raw PWM value
+ */
+int32_t HAL_GetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t* status);
+
+/**
+ * Gets a scaled value from a PWM channel.
+ *
+ * The values range from -1 to 1.
+ *
+ * @param pwmPortHandle the PWM handle
+ * @return              the current speed PWM value
+ */
+double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status);
+
+/**
+ * Gets a position value from a PWM channel.
+ *
+ * The values range from 0 to 1.
+ *
+ * @param pwmPortHandle the PWM handle
+ * @return              the current positional PWM value
+ */
+double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status);
+
+/**
+ * Forces a PWM signal to go to 0 temporarily.
+ *
+ * @param pwmPortHandle the PWM handle.
+ */
+void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status);
+
+/**
+ * Sets how how often the PWM signal is squelched, thus scaling the period.
+ *
+ * @param pwmPortHandle the PWM handle.
+ * @param squelchMask   the 2-bit mask of outputs to squelch
+ */
+void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
+                           int32_t* status);
+
+/**
+ * Gets the loop timing of the PWM system.
+ *
+ * @return the loop time
+ */
+int32_t HAL_GetPWMLoopTiming(int32_t* status);
+
+/**
+ * Gets the pwm starting cycle time.
+ *
+ * This time is relative to the FPGA time.
+ *
+ * @return the pwm cycle start time
+ */
+uint64_t HAL_GetPWMCycleStartTime(int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Ports.h b/hal/src/main/native/include/hal/Ports.h
new file mode 100644
index 0000000..9b29817
--- /dev/null
+++ b/hal/src/main/native/include/hal/Ports.h
@@ -0,0 +1,150 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+/**
+ * @defgroup hal_ports Ports Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the number of analog accumulators in the current system.
+ *
+ * @return the number of analog accumulators
+ */
+int32_t HAL_GetNumAccumulators(void);
+
+/**
+ * Gets the number of analog triggers in the current system.
+ *
+ * @return the number of analog triggers
+ */
+int32_t HAL_GetNumAnalogTriggers(void);
+
+/**
+ * Gets the number of analog inputs in the current system.
+ *
+ * @return the number of analog inputs
+ */
+int32_t HAL_GetNumAnalogInputs(void);
+
+/**
+ * Gets the number of analog outputs in the current system.
+ *
+ * @return the number of analog outputs
+ */
+int32_t HAL_GetNumAnalogOutputs(void);
+
+/**
+ * Gets the number of analog counters in the current system.
+ *
+ * @return the number of counters
+ */
+int32_t HAL_GetNumCounters(void);
+
+/**
+ * Gets the number of digital headers in the current system.
+ *
+ * @return the number of digital headers
+ */
+int32_t HAL_GetNumDigitalHeaders(void);
+
+/**
+ * Gets the number of PWM headers in the current system.
+ *
+ * @return the number of PWM headers
+ */
+int32_t HAL_GetNumPWMHeaders(void);
+
+/**
+ * Gets the number of digital channels in the current system.
+ *
+ * @return the number of digital channels
+ */
+int32_t HAL_GetNumDigitalChannels(void);
+
+/**
+ * Gets the number of PWM channels in the current system.
+ *
+ * @return the number of PWM channels
+ */
+int32_t HAL_GetNumPWMChannels(void);
+
+/**
+ * Gets the number of digital IO PWM outputs in the current system.
+ *
+ * @return the number of digital IO PWM outputs
+ */
+int32_t HAL_GetNumDigitalPWMOutputs(void);
+
+/**
+ * Gets the number of quadrature encoders in the current system.
+ *
+ * @return the number of quadrature encoders
+ */
+int32_t HAL_GetNumEncoders(void);
+
+/**
+ * Gets the number of interrupts in the current system.
+ *
+ * @return the number of interrupts
+ */
+int32_t HAL_GetNumInterrupts(void);
+
+/**
+ * Gets the number of relay channels in the current system.
+ *
+ * @return the number of relay channels
+ */
+int32_t HAL_GetNumRelayChannels(void);
+
+/**
+ * Gets the number of relay headers in the current system.
+ *
+ * @return the number of relay headers
+ */
+int32_t HAL_GetNumRelayHeaders(void);
+
+/**
+ * Gets the number of PCM modules in the current system.
+ *
+ * @return the number of PCM modules
+ */
+int32_t HAL_GetNumPCMModules(void);
+
+/**
+ * Gets the number of solenoid channels in the current system.
+ *
+ * @return the number of solenoid channels
+ */
+int32_t HAL_GetNumSolenoidChannels(void);
+
+/**
+ * Gets the number of PDP modules in the current system.
+ *
+ * @return the number of PDP modules
+ */
+int32_t HAL_GetNumPDPModules(void);
+
+/**
+ * Gets the number of PDP channels in the current system.
+ *
+ * @return the number of PDP channels
+ */
+int32_t HAL_GetNumPDPChannels(void);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Power.h b/hal/src/main/native/include/hal/Power.h
new file mode 100644
index 0000000..7ac7991
--- /dev/null
+++ b/hal/src/main/native/include/hal/Power.h
@@ -0,0 +1,124 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_power Power Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the roboRIO input voltage.
+ *
+ * @return the input voltage (volts)
+ */
+double HAL_GetVinVoltage(int32_t* status);
+
+/**
+ * Gets the roboRIO input current.
+ *
+ * @return the input current (amps)
+ */
+double HAL_GetVinCurrent(int32_t* status);
+
+/**
+ * Gets the 6V rail voltage.
+ *
+ * @return the 6V rail voltage (volts)
+ */
+double HAL_GetUserVoltage6V(int32_t* status);
+
+/**
+ * Gets the 6V rail current.
+ *
+ * @return the 6V rail current (amps)
+ */
+double HAL_GetUserCurrent6V(int32_t* status);
+
+/**
+ * Gets the active state of the 6V rail.
+ *
+ * @return true if the rail is active, otherwise false
+ */
+HAL_Bool HAL_GetUserActive6V(int32_t* status);
+
+/**
+ * Gets the fault count for the 6V rail.
+ *
+ * @return the number of 6V fault counts
+ */
+int32_t HAL_GetUserCurrentFaults6V(int32_t* status);
+
+/**
+ * Gets the 5V rail voltage.
+ *
+ * @return the 5V rail voltage (volts)
+ */
+double HAL_GetUserVoltage5V(int32_t* status);
+
+/**
+ * Gets the 5V rail current.
+ *
+ * @return the 5V rail current (amps)
+ */
+double HAL_GetUserCurrent5V(int32_t* status);
+
+/**
+ * Gets the active state of the 5V rail.
+ *
+ * @return true if the rail is active, otherwise false
+ */
+HAL_Bool HAL_GetUserActive5V(int32_t* status);
+
+/**
+ * Gets the fault count for the 5V rail.
+ *
+ * @return the number of 5V fault counts
+ */
+int32_t HAL_GetUserCurrentFaults5V(int32_t* status);
+
+/**
+ * Gets the 3V3 rail voltage.
+ *
+ * @return the 3V3 rail voltage (volts)
+ */
+double HAL_GetUserVoltage3V3(int32_t* status);
+
+/**
+ * Gets the 3V3 rail current.
+ *
+ * @return the 3V3 rail current (amps)
+ */
+double HAL_GetUserCurrent3V3(int32_t* status);
+
+/**
+ * Gets the active state of the 3V3 rail.
+ *
+ * @return true if the rail is active, otherwise false
+ */
+HAL_Bool HAL_GetUserActive3V3(int32_t* status);
+
+/**
+ * Gets the fault count for the 3V3 rail.
+ *
+ * @return the number of 3V3 fault counts
+ */
+int32_t HAL_GetUserCurrentFaults3V3(int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Relay.h b/hal/src/main/native/include/hal/Relay.h
new file mode 100644
index 0000000..281aad6
--- /dev/null
+++ b/hal/src/main/native/include/hal/Relay.h
@@ -0,0 +1,71 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_relay Relay Output Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a relay.
+ *
+ * Note this call will only initialize either the forward or reverse port of the
+ * relay. If you need both, you will need to initialize 2 relays.
+ *
+ * @param portHandle the port handle to initialize
+ * @param fwd        true for the forward port, false for the reverse port
+ * @return           the created relay handle
+ */
+HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
+                                        int32_t* status);
+
+/**
+ * Frees a relay port.
+ *
+ * @param relayPortHandle the relay handle
+ */
+void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle);
+
+/**
+ * Checks if a relay channel is valid.
+ *
+ * @param channel the channel to check
+ * @return        true if the channel is valid, otherwise false
+ */
+HAL_Bool HAL_CheckRelayChannel(int32_t channel);
+
+/**
+ * Sets the state of a relay output.
+ *
+ * @param relayPortHandle the relay handle
+ * @param on              true for on, false for off
+ */
+void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
+                  int32_t* status);
+
+/**
+ * Gets the current state of the relay channel.
+ *
+ * @param relayPortHandle the relay handle
+ * @return                true for on, false for off
+ */
+HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/SPI.h b/hal/src/main/native/include/hal/SPI.h
new file mode 100644
index 0000000..4f1815f
--- /dev/null
+++ b/hal/src/main/native/include/hal/SPI.h
@@ -0,0 +1,250 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/AnalogTrigger.h"
+#include "hal/SPITypes.h"
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_spi SPI Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes the SPI port. Opens the port if necessary and saves the handle.
+ *
+ * If opening the MXP port, also sets up the channel functions appropriately.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS3, 4 for MXP
+ */
+void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status);
+
+/**
+ * Performs an SPI send/receive transaction.
+ *
+ * This is a lower-level interface to the spi hardware giving you more control
+ * over each transaction.
+ *
+ * @param port         The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ * for MXP
+ * @param dataToSend   Buffer of data to send as part of the transaction.
+ * @param dataReceived Buffer to read data into.
+ * @param size         Number of bytes to transfer. [0..7]
+ * @return             Number of bytes transferred, -1 for error
+ */
+int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend,
+                           uint8_t* dataReceived, int32_t size);
+
+/**
+ * Executes a write transaction with the device.
+ *
+ * Writes to a device and wait until the transaction is complete.
+ *
+ * @param port      The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ * for MXP
+ * @param datToSend The data to write to the register on the device.
+ * @param sendSize  The number of bytes to be written
+ * @return          The number of bytes written. -1 for an error
+ */
+int32_t HAL_WriteSPI(HAL_SPIPort port, const uint8_t* dataToSend,
+                     int32_t sendSize);
+
+/**
+ * Executes a read from the device.
+ *
+ * This method does not write any data out to the device.
+ *
+ * Most spi devices will require a register address to be written before they
+ * begin returning data.
+ *
+ * @param port   The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP
+ * @param buffer A pointer to the array of bytes to store the data read from the
+ * device.
+ * @param count  The number of bytes to read in the transaction. [1..7]
+ * @return       Number of bytes read. -1 for error.
+ */
+int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count);
+
+/**
+ * Closes the SPI port.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
+ */
+void HAL_CloseSPI(HAL_SPIPort port);
+
+/**
+ * Sets the clock speed for the SPI bus.
+ *
+ * @param port  The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP
+ * @param speed The speed in Hz (0-1MHz)
+ */
+void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed);
+
+/**
+ * Sets the SPI options.
+ *
+ * @param port             The number of the port to use. 0-3 for Onboard
+ * CS0-CS2, 4 for MXP
+ * @param msbFirst         True to write the MSB first, False for LSB first
+ * @param sampleOnTrailing True to sample on the trailing edge, False to sample
+ * on the leading edge
+ * @param clkIdleHigh      True to set the clock to active low, False to set the
+ * clock active high
+ */
+void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
+                    HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh);
+
+/**
+ * Sets the CS Active high for a SPI port.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
+ */
+void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status);
+
+/**
+ * Sets the CS Active low for a SPI port.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
+ */
+void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status);
+
+/**
+ * Gets the stored handle for a SPI port.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
+ * @return     The stored handle for the SPI port. 0 represents no stored
+ * handle.
+ */
+int32_t HAL_GetSPIHandle(HAL_SPIPort port);
+
+/**
+ * Sets the stored handle for a SPI port.
+ *
+ * @param port   The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP.
+ * @param handle The value of the handle for the port.
+ */
+void HAL_SetSPIHandle(HAL_SPIPort port, int32_t handle);
+
+/**
+ * Initializes the SPI automatic accumulator.
+ *
+ * @param port       The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ * for MXP.
+ * @param bufferSize The accumulator buffer size.
+ */
+void HAL_InitSPIAuto(HAL_SPIPort port, int32_t bufferSize, int32_t* status);
+
+/**
+ * Frees an SPI automatic accumulator.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP.
+ */
+void HAL_FreeSPIAuto(HAL_SPIPort port, int32_t* status);
+
+/**
+ * Sets the period for automatic SPI accumulation.
+ *
+ * @param port   The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP.
+ * @param period The accumlation period (seconds).
+ */
+void HAL_StartSPIAutoRate(HAL_SPIPort port, double period, int32_t* status);
+
+/**
+ * Starts the auto SPI accumulator on a specific trigger.
+ *
+ * Note that triggering on both rising and falling edges is a valid
+ * configuration.
+ *
+ * @param port                The number of the port to use. 0-3 for Onboard
+ * CS0-CS2, 4 for MXP.
+ * @param digitalSourceHandle The trigger source to use (Either
+ * HAL_AnalogTriggerHandle or HAL_DigitalHandle).
+ * @param analogTriggerType   The analog trigger type, if the source is an
+ * analog trigger.
+ * @param triggerRising       Trigger on the rising edge if true.
+ * @param triggerFalling      Trigger on the falling edge if true.
+ */
+void HAL_StartSPIAutoTrigger(HAL_SPIPort port, HAL_Handle digitalSourceHandle,
+                             HAL_AnalogTriggerType analogTriggerType,
+                             HAL_Bool triggerRising, HAL_Bool triggerFalling,
+                             int32_t* status);
+
+/**
+ * Stops an automatic SPI accumlation.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP.
+ */
+void HAL_StopSPIAuto(HAL_SPIPort port, int32_t* status);
+
+/**
+ * Sets the data to be transmitted to the device to initiate a read.
+ *
+ * @param port       The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ * for MXP.
+ * @param dataToSend Pointer to the data to send (Gets copied for continue use,
+ * so no need to keep alive).
+ * @param dataSize   The length of the data to send.
+ * @param zeroSize   The number of zeros to send after the data.
+ */
+void HAL_SetSPIAutoTransmitData(HAL_SPIPort port, const uint8_t* dataToSend,
+                                int32_t dataSize, int32_t zeroSize,
+                                int32_t* status);
+
+/**
+ * Immediately forces an SPI read to happen.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP.
+ */
+void HAL_ForceSPIAutoRead(HAL_SPIPort port, int32_t* status);
+
+/**
+ * Reads data received by the SPI accumulator.  Each received data sequence
+ * consists of a timestamp followed by the received data bytes, one byte per
+ * word (in the least significant byte).  The length of each received data
+ * sequence is the same as the combined dataSize + zeroSize set in
+ * HAL_SetSPIAutoTransmitData.
+ *
+ * @param port      The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ * for MXP.
+ * @param buffer    The buffer to store the data into.
+ * @param numToRead The number of words to read.
+ * @param timeout   The read timeout (in seconds).
+ * @return          The number of words actually read.
+ */
+int32_t HAL_ReadSPIAutoReceivedData(HAL_SPIPort port, uint32_t* buffer,
+                                    int32_t numToRead, double timeout,
+                                    int32_t* status);
+
+/**
+ * Gets the count of how many SPI accumulations have been missed.
+ *
+ * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ * MXP.
+ * @return     The number of missed accumulations.
+ */
+int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status);
+
+#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
new file mode 100644
index 0000000..907623c
--- /dev/null
+++ b/hal/src/main/native/include/hal/SPITypes.h
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------------*/
+/* 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_spi SPI Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+HAL_ENUM(HAL_SPIPort) {
+  HAL_SPI_kInvalid = -1,
+  HAL_SPI_kOnboardCS0,
+  HAL_SPI_kOnboardCS1,
+  HAL_SPI_kOnboardCS2,
+  HAL_SPI_kOnboardCS3,
+  HAL_SPI_kMXP
+};
+// clang-format on
+/** @} */
diff --git a/hal/src/main/native/include/hal/SerialPort.h b/hal/src/main/native/include/hal/SerialPort.h
new file mode 100644
index 0000000..c2fd105
--- /dev/null
+++ b/hal/src/main/native/include/hal/SerialPort.h
@@ -0,0 +1,230 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_serialport Serial Port Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+// clang-format off
+HAL_ENUM(HAL_SerialPort) {
+  HAL_SerialPort_Onboard = 0,
+  HAL_SerialPort_MXP = 1,
+  HAL_SerialPort_USB1 = 2,
+  HAL_SerialPort_USB2 = 3
+};
+// clang-format on
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a serial port.
+ *
+ * The channels are either the onboard RS232, the mxp uart, or 2 USB ports. The
+ * top port is USB1, the bottom port is USB2.
+ *
+ * @param port the serial port to initialize
+ */
+void 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).
+ * Note these are not always consistent between roboRIO reboots.
+ *
+ * @param port     the serial port to initialize
+ * @param portName the VISA port name
+ */
+void HAL_InitializeSerialPortDirect(HAL_SerialPort port, const char* portName,
+                                    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
+ */
+void HAL_SetSerialBaudRate(HAL_SerialPort port, 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)
+ */
+void HAL_SetSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status);
+
+/**
+ * Sets the number of parity bits on a serial port.
+ *
+ * Valid values are:
+ *   0: None (default)
+ *   1: Odd
+ *   2: Even
+ *   3: Mark - Means exists and always 1
+ *   4: Space - Means exists and always 0
+ *
+ * @param port   the serial port
+ * @param parity the parity bit mode (see remarks for valid values)
+ */
+void HAL_SetSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status);
+
+/**
+ * Sets the number of stop bits on a serial port.
+ *
+ * Valid values are:
+ *   10: One stop bit (default)
+ *   15: One and a half stop bits
+ *   20: Two stop bits
+ *
+ * @param port     the serial port
+ * @param stopBits the stop bit value (see remarks for valid values)
+ */
+void HAL_SetSerialStopBits(HAL_SerialPort port, int32_t stopBits,
+                           int32_t* status);
+
+/**
+ * Sets the write mode on a serial port.
+ *
+ * Valid values are:
+ *   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)
+ */
+void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode, int32_t* status);
+
+/**
+ * Sets the flow control mode of a serial port.
+ *
+ * Valid values are:
+ *   0: None (default)
+ *   1: XON-XOFF
+ *   2: RTS-CTS
+ *   3: DTR-DSR
+ *
+ * @param port the serial port
+ * @param flow the mode to set (see remarks for valid values)
+ */
+void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
+                              int32_t* status);
+
+/**
+ * Sets the minimum serial read timeout of a port.
+ *
+ * @param port    the serial port
+ * @param timeout the timeout in milliseconds
+ */
+void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout, int32_t* status);
+
+/**
+ * Sets the termination character that terminates a read.
+ *
+ * By default this is disabled.
+ *
+ * @param port       the serial port
+ * @param terminator the termination character to set
+ */
+void HAL_EnableSerialTermination(HAL_SerialPort port, char terminator,
+                                 int32_t* status);
+
+/**
+ * Disables a termination character for reads.
+ *
+ * @param port the serial port
+ */
+void HAL_DisableSerialTermination(HAL_SerialPort port, int32_t* status);
+
+/**
+ * Sets the size of the read buffer.
+ *
+ * @param port the serial port
+ * @param size the read buffer size
+ */
+void HAL_SetSerialReadBufferSize(HAL_SerialPort port, int32_t size,
+                                 int32_t* status);
+
+/**
+ * Sets the size of the write buffer.
+ *
+ * @param port the serial port
+ * @param size the write buffer size
+ */
+void HAL_SetSerialWriteBufferSize(HAL_SerialPort port, 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
+ */
+int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status);
+
+/**
+ * Reads data from the serial port.
+ *
+ * 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
+ */
+int32_t HAL_ReadSerial(HAL_SerialPort port, char* buffer, int32_t count,
+                       int32_t* status);
+
+/**
+ * Writes data to the serial port.
+ *
+ * @param port   the serial port
+ * @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);
+
+/**
+ * Flushes the serial write buffer out to the port.
+ *
+ * @param port the serial port
+ */
+void HAL_FlushSerial(HAL_SerialPort port, int32_t* status);
+
+/**
+ * Clears the receive buffer of the serial port.
+ *
+ * @param port the serial port
+ */
+void HAL_ClearSerial(HAL_SerialPort port, int32_t* status);
+
+/**
+ * Closes a serial port.
+ *
+ * @param port the serial port to close
+ */
+void HAL_CloseSerial(HAL_SerialPort port, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Solenoid.h b/hal/src/main/native/include/hal/Solenoid.h
new file mode 100644
index 0000000..53257b2
--- /dev/null
+++ b/hal/src/main/native/include/hal/Solenoid.h
@@ -0,0 +1,141 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_solenoid Solenoid Output Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a solenoid port.
+ *
+ * @param portHandle the port handle of the module and channel to initialize
+ * @return           the created solenoid handle
+ */
+HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle,
+                                              int32_t* status);
+
+/**
+ * Frees a solenoid port.
+ *
+ * @param solenoidPortHandle the solenoid handle
+ */
+void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle);
+
+/**
+ * Checks if a solenoid module is in the valid range.
+ *
+ * @param module the module number to check
+ * @return       true if the module number is valid, otherwise false
+ */
+HAL_Bool HAL_CheckSolenoidModule(int32_t module);
+
+/**
+ * Checks if a solenoid channel is in the valid range.
+ *
+ * @param channel the channel number to check
+ * @return       true if the channel number is valid, otherwise false
+ */
+HAL_Bool HAL_CheckSolenoidChannel(int32_t channel);
+
+/**
+ * Gets the current solenoid output value.
+ *
+ * @param solenoidPortHandle the solenoid handle
+ * @return                   true if the solenoid is on, otherwise false
+ */
+HAL_Bool HAL_GetSolenoid(HAL_SolenoidHandle solenoidPortHandle,
+                         int32_t* status);
+
+/**
+ * Gets the status of all solenoids on a specific module.
+ *
+ * @param module the module to check
+ * @return       bitmask of the channels, 1 for on 0 for off
+ */
+int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status);
+
+/**
+ * Sets a solenoid output value.
+ *
+ * @param solenoidPortHandle the solenoid handle
+ * @param value              true for on, false for off
+ */
+void HAL_SetSolenoid(HAL_SolenoidHandle solenoidPortHandle, HAL_Bool value,
+                     int32_t* status);
+
+/**
+ * Sets all channels on a specific module.
+ *
+ * @param module the module to set the channels on
+ * @param state  bitmask of the channels to set, 1 for on 0 for off
+ */
+void HAL_SetAllSolenoids(int32_t module, int32_t state, int32_t* status);
+
+/**
+ * Gets the channels blacklisted from being enabled on a module.
+ *
+ * @param module the module to check
+ * @retur        bitmask of the blacklisted channels, 1 for true 0 for false
+ */
+int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status);
+
+/**
+ * Gets if a specific module has an over or under voltage sticky fault.
+ *
+ * @param module the module to check
+ * @return       true if a stick fault is set, otherwise false
+ */
+HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status);
+
+/**
+ * Gets if a specific module has an over or under voltage fault.
+ *
+ * @param module the module to check
+ * @return       true if faulted, otherwise false
+ */
+HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status);
+
+/**
+ * Clears all faults on a module.
+ *
+ * @param module the module to clear
+ */
+void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status);
+
+/**
+ * Sets the one shot duration on a solenoid channel.
+ *
+ * @param solenoidPortHandle the solenoid handle
+ * @param durMS              the one shot duration in ms
+ */
+void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
+                            int32_t durMS, int32_t* status);
+
+/**
+ * Fires a single pulse on a solenoid channel.
+ *
+ * The pulse is the duration set by HAL_SetOneShotDuration().
+ *
+ * @param solenoidPortHandle the solenoid handle
+ */
+void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Threads.h b/hal/src/main/native/include/hal/Threads.h
new file mode 100644
index 0000000..4908c9c
--- /dev/null
+++ b/hal/src/main/native/include/hal/Threads.h
@@ -0,0 +1,72 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#define NativeThreadHandle const void*
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_threads Threads Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+extern "C" {
+/**
+ * Gets the thread priority for the specified thread.
+ *
+ * @param handle     Native handle pointer to the thread to get the priority for
+ * @param isRealTime Set to true if thread is realtime, otherwise false
+ * @param status     Error status variable. 0 on success
+ * @return           The current thread priority. Scaled 1-99, with 1 being
+ * highest.
+ */
+int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
+                              int32_t* status);
+
+/**
+ * Gets the thread priority for the current thread.
+ *
+ * @param handle     Native handle pointer to the thread to get the priority for
+ * @param isRealTime Set to true if thread is realtime, otherwise false
+ * @param status     Error status variable. 0 on success
+ * @return           The current thread priority. Scaled 1-99, with 1 being
+ * highest.
+ */
+int32_t HAL_GetCurrentThreadPriority(HAL_Bool* isRealTime, int32_t* status);
+
+/**
+ * Sets the thread priority for the specified thread.
+ *
+ * @param thread   Reference to the thread to set the priority of
+ * @param realTime Set to true to set a realtime priority, false for standard
+ * priority
+ * @param priority Priority to set the thread to. Scaled 1-99, with 1 being
+ * highest
+ * @param status   Error status variable. 0 on success
+ * @return         The success state of setting the priority
+ */
+HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
+                               int32_t priority, int32_t* status);
+
+/**
+ * Sets the thread priority for the current thread.
+ *
+ * @param thread   Reference to the thread to set the priority of
+ * @param realTime Set to true to set a realtime priority, false for standard
+ * priority
+ * @param priority Priority to set the thread to. Scaled 1-99, with 1 being
+ * highest
+ * @param status   Error status variable. 0 on success
+ * @return         The success state of setting the priority
+ */
+HAL_Bool HAL_SetCurrentThreadPriority(HAL_Bool realTime, int32_t priority,
+                                      int32_t* status);
+}  // extern "C"
+/** @} */
diff --git a/hal/src/main/native/include/hal/Types.h b/hal/src/main/native/include/hal/Types.h
new file mode 100644
index 0000000..6180439
--- /dev/null
+++ b/hal/src/main/native/include/hal/Types.h
@@ -0,0 +1,65 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+/**
+ * @defgroup hal_types Type Definitions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#define HAL_kInvalidHandle 0
+
+typedef int32_t HAL_Handle;
+
+typedef HAL_Handle HAL_PortHandle;
+
+typedef HAL_Handle HAL_AnalogInputHandle;
+
+typedef HAL_Handle HAL_AnalogOutputHandle;
+
+typedef HAL_Handle HAL_AnalogTriggerHandle;
+
+typedef HAL_Handle HAL_CompressorHandle;
+
+typedef HAL_Handle HAL_CounterHandle;
+
+typedef HAL_Handle HAL_DigitalHandle;
+
+typedef HAL_Handle HAL_DigitalPWMHandle;
+
+typedef HAL_Handle HAL_EncoderHandle;
+
+typedef HAL_Handle HAL_FPGAEncoderHandle;
+
+typedef HAL_Handle HAL_GyroHandle;
+
+typedef HAL_Handle HAL_InterruptHandle;
+
+typedef HAL_Handle HAL_NotifierHandle;
+
+typedef HAL_Handle HAL_RelayHandle;
+
+typedef HAL_Handle HAL_SolenoidHandle;
+
+typedef HAL_Handle HAL_CANHandle;
+
+typedef HAL_CANHandle HAL_PDPHandle;
+
+typedef int32_t HAL_Bool;
+
+#ifdef __cplusplus
+#define HAL_ENUM(name) enum name : int32_t
+#else
+#define HAL_ENUM(name)  \
+  typedef int32_t name; \
+  enum name
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/cpp/Log.h b/hal/src/main/native/include/hal/cpp/Log.h
new file mode 100644
index 0000000..bcc3995
--- /dev/null
+++ b/hal/src/main/native/include/hal/cpp/Log.h
@@ -0,0 +1,128 @@
+/*----------------------------------------------------------------------------*/
+/* 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/SerialHelper.h b/hal/src/main/native/include/hal/cpp/SerialHelper.h
new file mode 100644
index 0000000..9f4d6a0
--- /dev/null
+++ b/hal/src/main/native/include/hal/cpp/SerialHelper.h
@@ -0,0 +1,83 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include <wpi/SmallString.h>
+#include <wpi/SmallVector.h>
+#include <wpi/mutex.h>
+
+#include "hal/SerialPort.h"
+
+namespace hal {
+/**
+ * A class for deterministically getting information about Serial Ports.
+ */
+class SerialHelper {
+ public:
+  SerialHelper();
+
+  /**
+   * Get the VISA name of a serial port.
+   *
+   * @param port   the serial port index
+   * @param status status check
+   * @return       the VISA name
+   */
+  std::string GetVISASerialPortName(HAL_SerialPort port, int32_t* status);
+
+  /**
+   * Get the OS name of a serial port.
+   *
+   * @param port   the serial port index
+   * @param status status check
+   * @return       the OS name
+   */
+  std::string GetOSSerialPortName(HAL_SerialPort port, int32_t* status);
+
+  /**
+   * Get a vector of all serial port VISA names.
+   *
+   * @param status status check
+   * @return       vector of serial port VISA names
+   */
+  std::vector<std::string> GetVISASerialPortList(int32_t* status);
+
+  /**
+   * Get a vector of all serial port OS names.
+   *
+   * @param status status check
+   * @return       vector of serial port OS names
+   */
+  std::vector<std::string> GetOSSerialPortList(int32_t* status);
+
+ private:
+  void SortHubPathVector();
+  void CoiteratedSort(wpi::SmallVectorImpl<wpi::SmallString<16>>& vec);
+  void QueryHubPaths(int32_t* status);
+
+  int32_t GetIndexForPort(HAL_SerialPort port, int32_t* status);
+
+  // Vectors to hold data before sorting.
+  // Note we will most likely have at max 2 instances, and the longest string
+  // is around 12, so these should never touch the heap;
+  wpi::SmallVector<wpi::SmallString<16>, 4> m_visaResource;
+  wpi::SmallVector<wpi::SmallString<16>, 4> m_osResource;
+  wpi::SmallVector<wpi::SmallString<16>, 4> m_unsortedHubPath;
+  wpi::SmallVector<wpi::SmallString<16>, 4> m_sortedHubPath;
+
+  int32_t m_resourceHandle;
+
+  static wpi::mutex m_nameMutex;
+  static std::string m_usbNames[2];
+};
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/cpp/UnsafeDIO.h b/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
new file mode 100644
index 0000000..ceb41c3
--- /dev/null
+++ b/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
@@ -0,0 +1,95 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <wpi/mutex.h>
+
+#include "hal/ChipObject.h"
+#include "hal/Types.h"
+
+namespace hal {
+
+/**
+ * Proxy class for directly manipulating the DIO pins.
+ *
+ * This class is not copyable or movable, and should never be used
+ * outside of the UnsafeManipulateDIO callback.
+ */
+struct DIOSetProxy {
+  DIOSetProxy(const DIOSetProxy&) = delete;
+  DIOSetProxy(DIOSetProxy&&) = delete;
+  DIOSetProxy& operator=(const DIOSetProxy&) = delete;
+  DIOSetProxy& operator=(DIOSetProxy&&) = delete;
+
+  void SetOutputMode(int32_t* status) {
+    m_dio->writeOutputEnable(m_setOutputDirReg, status);
+  }
+
+  void SetInputMode(int32_t* status) {
+    m_dio->writeOutputEnable(m_unsetOutputDirReg, status);
+  }
+
+  void SetOutputTrue(int32_t* status) {
+    m_dio->writeDO(m_setOutputStateReg, status);
+  }
+
+  void SetOutputFalse(int32_t* status) {
+    m_dio->writeDO(m_unsetOutputStateReg, status);
+  }
+
+  tDIO::tOutputEnable m_setOutputDirReg;
+  tDIO::tOutputEnable m_unsetOutputDirReg;
+  tDIO::tDO m_setOutputStateReg;
+  tDIO::tDO m_unsetOutputStateReg;
+  tDIO* m_dio;
+};
+namespace detail {
+wpi::mutex& UnsafeGetDIOMutex();
+tDIO* UnsafeGetDigialSystem();
+int32_t ComputeDigitalMask(HAL_DigitalHandle handle, int32_t* status);
+}  // namespace detail
+
+/**
+ * Unsafe digital output set function
+ * This function can be used to perform fast and determinstically set digital
+ * outputs. This function holds the DIO lock, so calling anyting other then
+ * functions on the Proxy object passed as a parameter can deadlock your
+ * program.
+ *
+ * @param handle the HAL digital handle of the pin to toggle.
+ * @param status status check
+ * @param func   A functor taking a ref to a DIOSetProxy object.
+ */
+template <typename Functor>
+void UnsafeManipulateDIO(HAL_DigitalHandle handle, int32_t* status,
+                         Functor func) {
+  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  wpi::mutex& dioMutex = detail::UnsafeGetDIOMutex();
+  tDIO* dSys = detail::UnsafeGetDigialSystem();
+  auto mask = detail::ComputeDigitalMask(handle, status);
+  if (status != 0) return;
+  std::lock_guard<wpi::mutex> lock(dioMutex);
+
+  tDIO::tOutputEnable enableOE = dSys->readOutputEnable(status);
+  enableOE.value |= mask;
+  auto disableOE = enableOE;
+  disableOE.value &= ~mask;
+  tDIO::tDO enableDO = dSys->readDO(status);
+  enableDO.value |= mask;
+  auto disableDO = enableDO;
+  disableDO.value &= ~mask;
+
+  DIOSetProxy dioData{enableOE, disableOE, enableDO, disableDO, dSys};
+  func(dioData);
+}
+
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/cpp/fpga_clock.h b/hal/src/main/native/include/hal/cpp/fpga_clock.h
new file mode 100644
index 0000000..94031b1
--- /dev/null
+++ b/hal/src/main/native/include/hal/cpp/fpga_clock.h
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <chrono>
+#include <limits>
+
+/** WPILib Hardware Abstraction Layer (HAL) namespace */
+namespace hal {
+
+/**
+ * A std::chrono compatible wrapper around the FPGA Timer.
+ */
+class fpga_clock {
+ public:
+  using rep = std::chrono::microseconds::rep;
+  using period = std::chrono::microseconds::period;
+  using duration = std::chrono::microseconds;
+  using time_point = std::chrono::time_point<fpga_clock>;
+
+  static fpga_clock::time_point now() noexcept;
+  static constexpr bool is_steady = true;
+
+  static fpga_clock::time_point epoch() noexcept { return time_point(zero()); }
+
+  static fpga_clock::duration zero() noexcept { return duration(0); }
+
+  static const time_point min_time;
+};
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/handles/DigitalHandleResource.h b/hal/src/main/native/include/hal/handles/DigitalHandleResource.h
new file mode 100644
index 0000000..23fb676
--- /dev/null
+++ b/hal/src/main/native/include/hal/handles/DigitalHandleResource.h
@@ -0,0 +1,105 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include <wpi/mutex.h>
+
+#include "hal/Errors.h"
+#include "hal/Types.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The DigitalHandleResource class is a way to track handles. This version
+ * allows a limited number of handles that are allocated by index.
+ * The enum value is seperate, as 2 enum values are allowed per handle
+ * Because they are allocated by index, each individual index holds its own
+ * mutex, which reduces contention heavily.]
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size>
+class DigitalHandleResource : public HandleBase {
+  friend class DigitalHandleResourceTest;
+
+ public:
+  DigitalHandleResource() = default;
+  DigitalHandleResource(const DigitalHandleResource&) = delete;
+  DigitalHandleResource& operator=(const DigitalHandleResource&) = delete;
+
+  THandle Allocate(int16_t index, HAL_HandleEnum enumValue, int32_t* status);
+  std::shared_ptr<TStruct> Get(THandle handle, HAL_HandleEnum enumValue);
+  void Free(THandle handle, HAL_HandleEnum enumValue);
+  void ResetHandles() override;
+
+ private:
+  std::array<std::shared_ptr<TStruct>, size> m_structures;
+  std::array<wpi::mutex, size> m_handleMutexes;
+};
+
+template <typename THandle, typename TStruct, int16_t size>
+THandle DigitalHandleResource<THandle, TStruct, size>::Allocate(
+    int16_t index, HAL_HandleEnum enumValue, int32_t* status) {
+  // don't aquire the lock if we can fail early.
+  if (index < 0 || index >= size) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // check for allocation, otherwise allocate and return a valid handle
+  if (m_structures[index] != nullptr) {
+    *status = RESOURCE_IS_ALLOCATED;
+    return HAL_kInvalidHandle;
+  }
+  m_structures[index] = std::make_shared<TStruct>();
+  return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
+}
+
+template <typename THandle, typename TStruct, int16_t size>
+std::shared_ptr<TStruct> DigitalHandleResource<THandle, TStruct, size>::Get(
+    THandle handle, HAL_HandleEnum enumValue) {
+  // get handle index, and fail early if index out of range or wrong handle
+  int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
+  if (index < 0 || index >= size) {
+    return nullptr;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // return structure. Null will propogate correctly, so no need to manually
+  // check.
+  return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size>
+void DigitalHandleResource<THandle, TStruct, size>::Free(
+    THandle handle, HAL_HandleEnum enumValue) {
+  // get handle index, and fail early if index out of range or wrong handle
+  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]);
+  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]);
+    m_structures[i].reset();
+  }
+  HandleBase::ResetHandles();
+}
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/handles/HandlesInternal.h b/hal/src/main/native/include/hal/handles/HandlesInternal.h
new file mode 100644
index 0000000..85b3493
--- /dev/null
+++ b/hal/src/main/native/include/hal/handles/HandlesInternal.h
@@ -0,0 +1,211 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "hal/Types.h"
+
+/* General Handle Data Layout
+ * Bits 0-15:  Handle Index
+ * Bits 16-23: 8 bit rolling reset detection
+ * Bits 24-30: Handle Type
+ * Bit 31:     1 if handle error, 0 if no error
+ *
+ * Other specialized handles will use different formats, however Bits 24-31 are
+ * always reserved for type and error handling.
+ */
+
+namespace hal {
+
+/**
+ * Base for all HAL Handles.
+ */
+class HandleBase {
+ public:
+  HandleBase();
+  ~HandleBase();
+  HandleBase(const HandleBase&) = delete;
+  HandleBase& operator=(const HandleBase&) = delete;
+  virtual void ResetHandles();
+  static void ResetGlobalHandles();
+
+ protected:
+  int16_t m_version;
+};
+
+constexpr int16_t InvalidHandleIndex = -1;
+
+/**
+ * Enum of HAL handle types. Vendors/Teams should use Vendor (17).
+ */
+enum class HAL_HandleEnum {
+  Undefined = 0,
+  DIO = 1,
+  Port = 2,
+  Notifier = 3,
+  Interrupt = 4,
+  AnalogOutput = 5,
+  AnalogInput = 6,
+  AnalogTrigger = 7,
+  Relay = 8,
+  PWM = 9,
+  DigitalPWM = 10,
+  Counter = 11,
+  FPGAEncoder = 12,
+  Encoder = 13,
+  Compressor = 14,
+  Solenoid = 15,
+  AnalogGyro = 16,
+  Vendor = 17,
+  SimulationJni = 18,
+  CAN = 19,
+};
+
+/**
+ * Get the handle index from a handle.
+ *
+ * @param handle the handle
+ * @return       the index
+ */
+static inline int16_t getHandleIndex(HAL_Handle handle) {
+  // mask and return last 16 bits
+  return static_cast<int16_t>(handle & 0xffff);
+}
+
+/**
+ * Get the handle type from a handle.
+ *
+ * @param handle the handle
+ * @return       the type
+ */
+static inline HAL_HandleEnum getHandleType(HAL_Handle handle) {
+  // mask first 8 bits and cast to enum
+  return static_cast<HAL_HandleEnum>((handle >> 24) & 0xff);
+}
+
+/**
+ * Get if the handle is a specific type.
+ *
+ * @param handle     the handle
+ * @param handleType the type to check
+ * @return           true if the type is correct, otherwise false
+ */
+static inline bool isHandleType(HAL_Handle handle, HAL_HandleEnum handleType) {
+  return handleType == getHandleType(handle);
+}
+
+/**
+ * Get if the version of the handle is correct.
+ *
+ * Do not use on the roboRIO, used specifically for the sim to handle resets.
+ *
+ * @param handle  the handle
+ * @param version the handle version to check
+ * @return        true if the handle is the right version, otherwise false
+ */
+static inline bool isHandleCorrectVersion(HAL_Handle handle, int16_t version) {
+  return (((handle & 0xFF0000) >> 16) & version) == version;
+}
+
+/**
+ * Get if the handle is a correct type and version.
+ *
+ * Note the version is not checked on the roboRIO.
+ *
+ * @param handle     the handle
+ * @param handleType the type to check
+ * @param version    the handle version to check
+ * @return           true if the handle is proper version and type, otherwise
+ * false.
+ */
+static inline int16_t getHandleTypedIndex(HAL_Handle handle,
+                                          HAL_HandleEnum enumType,
+                                          int16_t version) {
+  if (!isHandleType(handle, enumType)) return InvalidHandleIndex;
+#if !defined(__FRC_ROBORIO__)
+  if (!isHandleCorrectVersion(handle, version)) return InvalidHandleIndex;
+#endif
+  return getHandleIndex(handle);
+}
+
+/* specialized functions for Port handle
+ * Port Handle Data Layout
+ * Bits 0-7:   Channel Number
+ * Bits 8-15:  Module Number
+ * Bits 16-23: Unused
+ * Bits 24-30: Handle Type
+ * Bit 31:     1 if handle error, 0 if no error
+ */
+
+// using a 16 bit value so we can store 0-255 and still report error
+/**
+ * Gets the port channel of a port handle.
+ *
+ * @param handle the port handle
+ * @return       the port channel
+ */
+static inline int16_t getPortHandleChannel(HAL_PortHandle handle) {
+  if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+  return static_cast<uint8_t>(handle & 0xff);
+}
+
+// using a 16 bit value so we can store 0-255 and still report error
+/**
+ * Gets the port module of a port handle.
+ *
+ * @param handle the port handle
+ * @return       the port module
+ */
+static inline int16_t getPortHandleModule(HAL_PortHandle handle) {
+  if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+  return static_cast<uint8_t>((handle >> 8) & 0xff);
+}
+
+// using a 16 bit value so we can store 0-255 and still report error
+/**
+ * Gets the SPI channel of a port handle.
+ *
+ * @param handle the port handle
+ * @return       the port SPI channel
+ */
+static inline int16_t getPortHandleSPIEnable(HAL_PortHandle handle) {
+  if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+  return static_cast<uint8_t>((handle >> 16) & 0xff);
+}
+
+/**
+ * Create a port handle.
+ *
+ * @param channel the channel
+ * @param module  the module
+ * @return        port handle for the module and channel
+ */
+HAL_PortHandle createPortHandle(uint8_t channel, uint8_t module);
+
+/**
+ * Create a port handle for SPI.
+ *
+ * @param channel the SPI channel
+ * @return        port handle for the channel
+ */
+HAL_PortHandle createPortHandleForSPI(uint8_t channel);
+
+/**
+ * Create a handle for a specific index, type and version.
+ *
+ * Note the version is not checked on the roboRIO.
+ *
+ * @param index      the index
+ * @param handleType the handle type
+ * @param version    the handle version
+ * @return           the created handle
+ */
+HAL_Handle createHandle(int16_t index, HAL_HandleEnum handleType,
+                        int16_t version);
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h b/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h
new file mode 100644
index 0000000..a038e04
--- /dev/null
+++ b/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h
@@ -0,0 +1,117 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include <wpi/mutex.h>
+
+#include "hal/Errors.h"
+#include "hal/Types.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The IndexedClassedHandleResource class is a way to track handles. This
+ * version
+ * allows a limited number of handles that are allocated by index.
+ * Because they are allocated by index, each individual index holds its own
+ * mutex, which reduces contention heavily.]
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+class IndexedClassedHandleResource : public HandleBase {
+  friend class IndexedClassedHandleResourceTest;
+
+ public:
+  IndexedClassedHandleResource() = default;
+  IndexedClassedHandleResource(const IndexedClassedHandleResource&) = delete;
+  IndexedClassedHandleResource& operator=(const IndexedClassedHandleResource&) =
+      delete;
+
+  THandle Allocate(int16_t index, std::shared_ptr<TStruct> toSet,
+                   int32_t* status);
+  std::shared_ptr<TStruct> Get(THandle handle);
+  void Free(THandle handle);
+  void ResetHandles();
+
+ private:
+  std::array<std::shared_ptr<TStruct>, size> m_structures;
+  std::array<wpi::mutex, size> m_handleMutexes;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+THandle
+IndexedClassedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
+    int16_t index, std::shared_ptr<TStruct> toSet, int32_t* status) {
+  // don't aquire the lock if we can fail early.
+  if (index < 0 || index >= size) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // check for allocation, otherwise allocate and return a valid handle
+  if (m_structures[index] != nullptr) {
+    *status = RESOURCE_IS_ALLOCATED;
+    return HAL_kInvalidHandle;
+  }
+  m_structures[index] = toSet;
+  return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct>
+IndexedClassedHandleResource<THandle, TStruct, size, enumValue>::Get(
+    THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
+  if (index < 0 || index >= size) {
+    return nullptr;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // return structure. Null will propogate correctly, so no need to manually
+  // check.
+  return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+void IndexedClassedHandleResource<THandle, TStruct, size, enumValue>::Free(
+    THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  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]);
+  m_structures[index].reset();
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+void IndexedClassedHandleResource<THandle, TStruct, size,
+                                  enumValue>::ResetHandles() {
+  for (int i = 0; i < size; i++) {
+    std::lock_guard<wpi::mutex> lock(m_handleMutexes[i]);
+    m_structures[i].reset();
+  }
+  HandleBase::ResetHandles();
+}
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/handles/IndexedHandleResource.h b/hal/src/main/native/include/hal/handles/IndexedHandleResource.h
new file mode 100644
index 0000000..39abf58
--- /dev/null
+++ b/hal/src/main/native/include/hal/handles/IndexedHandleResource.h
@@ -0,0 +1,110 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include <wpi/mutex.h>
+
+#include "hal/Errors.h"
+#include "hal/Types.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The IndexedHandleResource class is a way to track handles. This version
+ * allows a limited number of handles that are allocated by index.
+ * Because they are allocated by index, each individual index holds its own
+ * mutex, which reduces contention heavily.]
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+class IndexedHandleResource : public HandleBase {
+  friend class IndexedHandleResourceTest;
+
+ public:
+  IndexedHandleResource() = default;
+  IndexedHandleResource(const IndexedHandleResource&) = delete;
+  IndexedHandleResource& operator=(const IndexedHandleResource&) = delete;
+
+  THandle Allocate(int16_t index, int32_t* status);
+  std::shared_ptr<TStruct> Get(THandle handle);
+  void Free(THandle handle);
+  void ResetHandles() override;
+
+ private:
+  std::array<std::shared_ptr<TStruct>, size> m_structures;
+  std::array<wpi::mutex, size> m_handleMutexes;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+THandle IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
+    int16_t index, int32_t* status) {
+  // don't aquire the lock if we can fail early.
+  if (index < 0 || index >= size) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // check for allocation, otherwise allocate and return a valid handle
+  if (m_structures[index] != nullptr) {
+    *status = RESOURCE_IS_ALLOCATED;
+    return HAL_kInvalidHandle;
+  }
+  m_structures[index] = std::make_shared<TStruct>();
+  return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct>
+IndexedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
+  if (index < 0 || index >= size) {
+    return nullptr;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // return structure. Null will propogate correctly, so no need to manually
+  // check.
+  return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+void IndexedHandleResource<THandle, TStruct, size, enumValue>::Free(
+    THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  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]);
+  m_structures[index].reset();
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          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]);
+    m_structures[i].reset();
+  }
+  HandleBase::ResetHandles();
+}
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h b/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h
new file mode 100644
index 0000000..2723129
--- /dev/null
+++ b/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h
@@ -0,0 +1,116 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include <wpi/mutex.h>
+
+#include "hal/Types.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The LimitedClassedHandleResource class is a way to track handles. This
+ * version
+ * allows a limited number of handles that are allocated sequentially.
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+class LimitedClassedHandleResource : public HandleBase {
+  friend class LimitedClassedHandleResourceTest;
+
+ public:
+  LimitedClassedHandleResource() = default;
+  LimitedClassedHandleResource(const LimitedClassedHandleResource&) = delete;
+  LimitedClassedHandleResource& operator=(const LimitedClassedHandleResource&) =
+      delete;
+
+  THandle Allocate(std::shared_ptr<TStruct> toSet);
+  std::shared_ptr<TStruct> Get(THandle handle);
+  void Free(THandle handle);
+  void ResetHandles() override;
+
+ private:
+  std::array<std::shared_ptr<TStruct>, size> m_structures;
+  std::array<wpi::mutex, size> m_handleMutexes;
+  wpi::mutex m_allocateMutex;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+THandle
+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);
+  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]);
+      m_structures[i] = toSet;
+      return static_cast<THandle>(createHandle(i, enumValue, m_version));
+    }
+  }
+  return HAL_kInvalidHandle;
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct>
+LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Get(
+    THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
+  if (index < 0 || index >= size) {
+    return nullptr;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // return structure. Null will propogate correctly, so no need to manually
+  // check.
+  return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+void LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Free(
+    THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  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]);
+  m_structures[index].reset();
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+void LimitedClassedHandleResource<THandle, TStruct, size,
+                                  enumValue>::ResetHandles() {
+  {
+    std::lock_guard<wpi::mutex> allocateLock(m_allocateMutex);
+    for (int i = 0; i < size; i++) {
+      std::lock_guard<wpi::mutex> handleLock(m_handleMutexes[i]);
+      m_structures[i].reset();
+    }
+  }
+  HandleBase::ResetHandles();
+}
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/handles/LimitedHandleResource.h b/hal/src/main/native/include/hal/handles/LimitedHandleResource.h
new file mode 100644
index 0000000..a535829
--- /dev/null
+++ b/hal/src/main/native/include/hal/handles/LimitedHandleResource.h
@@ -0,0 +1,110 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include <wpi/mutex.h>
+
+#include "HandlesInternal.h"
+#include "hal/Types.h"
+
+namespace hal {
+
+/**
+ * The LimitedHandleResource class is a way to track handles. This version
+ * allows a limited number of handles that are allocated sequentially.
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+class LimitedHandleResource : public HandleBase {
+  friend class LimitedHandleResourceTest;
+
+ public:
+  LimitedHandleResource() = default;
+  LimitedHandleResource(const LimitedHandleResource&) = delete;
+  LimitedHandleResource& operator=(const LimitedHandleResource&) = delete;
+
+  THandle Allocate();
+  std::shared_ptr<TStruct> Get(THandle handle);
+  void Free(THandle handle);
+  void ResetHandles() override;
+
+ private:
+  std::array<std::shared_ptr<TStruct>, size> m_structures;
+  std::array<wpi::mutex, size> m_handleMutexes;
+  wpi::mutex m_allocateMutex;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+THandle LimitedHandleResource<THandle, TStruct, size, enumValue>::Allocate() {
+  // globally lock to loop through indices
+  std::lock_guard<wpi::mutex> 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]);
+      m_structures[i] = std::make_shared<TStruct>();
+      return static_cast<THandle>(createHandle(i, enumValue, m_version));
+    }
+  }
+  return HAL_kInvalidHandle;
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct>
+LimitedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
+  if (index < 0 || index >= size) {
+    return nullptr;
+  }
+  std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
+  // return structure. Null will propogate correctly, so no need to manually
+  // check.
+  return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+void LimitedHandleResource<THandle, TStruct, size, enumValue>::Free(
+    THandle handle) {
+  // get handle index, and fail early if index out of range or wrong handle
+  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]);
+  m_structures[index].reset();
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+          HAL_HandleEnum enumValue>
+void LimitedHandleResource<THandle, TStruct, size, enumValue>::ResetHandles() {
+  {
+    std::lock_guard<wpi::mutex> allocateLock(m_allocateMutex);
+    for (int i = 0; i < size; i++) {
+      std::lock_guard<wpi::mutex> handleLock(m_handleMutexes[i]);
+      m_structures[i].reset();
+    }
+  }
+  HandleBase::ResetHandles();
+}
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h b/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
new file mode 100644
index 0000000..7df8061
--- /dev/null
+++ b/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
@@ -0,0 +1,126 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <memory>
+#include <utility>
+#include <vector>
+
+#include <wpi/mutex.h>
+
+#include "hal/Types.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The UnlimitedHandleResource class is a way to track handles. This version
+ * allows an unlimted number of handles that are allocated sequentially. When
+ * possible, indices are reused to save memory usage and keep the array length
+ * down.
+ * However, automatic array management has not been implemented, but might be in
+ * the future.
+ * Because we have to loop through the allocator, we must use a global mutex.
+
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+class UnlimitedHandleResource : public HandleBase {
+  friend class UnlimitedHandleResourceTest;
+
+ public:
+  UnlimitedHandleResource() = default;
+  UnlimitedHandleResource(const UnlimitedHandleResource&) = delete;
+  UnlimitedHandleResource& operator=(const UnlimitedHandleResource&) = delete;
+
+  THandle Allocate(std::shared_ptr<TStruct> structure);
+  std::shared_ptr<TStruct> Get(THandle handle);
+  /* Returns structure previously at that handle (or nullptr if none) */
+  std::shared_ptr<TStruct> Free(THandle handle);
+  void ResetHandles() override;
+
+  /* Calls func(THandle, TStruct*) for each handle.  Note this holds the
+   * global lock for the entirety of execution.
+   */
+  template <typename Functor>
+  void ForEach(Functor func);
+
+ private:
+  std::vector<std::shared_ptr<TStruct>> m_structures;
+  wpi::mutex m_handleMutex;
+};
+
+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);
+  size_t i;
+  for (i = 0; i < m_structures.size(); i++) {
+    if (m_structures[i] == nullptr) {
+      m_structures[i] = structure;
+      return static_cast<THandle>(createHandle(i, enumValue, m_version));
+    }
+  }
+  if (i >= INT16_MAX) return HAL_kInvalidHandle;
+
+  m_structures.push_back(structure);
+  return static_cast<THandle>(
+      createHandle(static_cast<int16_t>(i), enumValue, m_version));
+}
+
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+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);
+  if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
+    return nullptr;
+  return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+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);
+  if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
+    return nullptr;
+  return std::move(m_structures[index]);
+}
+
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+void UnlimitedHandleResource<THandle, TStruct, enumValue>::ResetHandles() {
+  {
+    std::lock_guard<wpi::mutex> lock(m_handleMutex);
+    for (size_t i = 0; i < m_structures.size(); i++) {
+      m_structures[i].reset();
+    }
+  }
+  HandleBase::ResetHandles();
+}
+
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+template <typename Functor>
+void UnlimitedHandleResource<THandle, TStruct, enumValue>::ForEach(
+    Functor func) {
+  std::lock_guard<wpi::mutex> lock(m_handleMutex);
+  size_t i;
+  for (i = 0; i < m_structures.size(); i++) {
+    if (m_structures[i] != nullptr) {
+      func(static_cast<THandle>(createHandle(i, enumValue, m_version)),
+           m_structures[i].get());
+    }
+  }
+}
+
+}  // namespace hal
diff --git a/hal/src/main/native/include/hal/labview/HAL.h b/hal/src/main/native/include/hal/labview/HAL.h
new file mode 100644
index 0000000..db9f20f
--- /dev/null
+++ b/hal/src/main/native/include/hal/labview/HAL.h
@@ -0,0 +1,14 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#define HAL_USE_LABVIEW
+
+#include "hal/DriverStation.h"
+#include "hal/HAL.h"
+#include "hal/Types.h"
diff --git a/hal/src/main/native/include/mockdata/AccelerometerData.h b/hal/src/main/native/include/mockdata/AccelerometerData.h
new file mode 100644
index 0000000..79f151d
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/AccelerometerData.h
@@ -0,0 +1,70 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Accelerometer.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetAccelerometerData(int32_t index);
+int32_t HALSIM_RegisterAccelerometerActiveCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelAccelerometerActiveCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetAccelerometerActive(int32_t index);
+void HALSIM_SetAccelerometerActive(int32_t index, HAL_Bool active);
+
+int32_t HALSIM_RegisterAccelerometerRangeCallback(int32_t index,
+                                                  HAL_NotifyCallback callback,
+                                                  void* param,
+                                                  HAL_Bool initialNotify);
+void HALSIM_CancelAccelerometerRangeCallback(int32_t index, int32_t uid);
+HAL_AccelerometerRange HALSIM_GetAccelerometerRange(int32_t index);
+void HALSIM_SetAccelerometerRange(int32_t index, HAL_AccelerometerRange range);
+
+int32_t HALSIM_RegisterAccelerometerXCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelAccelerometerXCallback(int32_t index, int32_t uid);
+double HALSIM_GetAccelerometerX(int32_t index);
+void HALSIM_SetAccelerometerX(int32_t index, double x);
+
+int32_t HALSIM_RegisterAccelerometerYCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelAccelerometerYCallback(int32_t index, int32_t uid);
+double HALSIM_GetAccelerometerY(int32_t index);
+void HALSIM_SetAccelerometerY(int32_t index, double y);
+
+int32_t HALSIM_RegisterAccelerometerZCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelAccelerometerZCallback(int32_t index, int32_t uid);
+double HALSIM_GetAccelerometerZ(int32_t index);
+void HALSIM_SetAccelerometerZ(int32_t index, double z);
+
+void HALSIM_RegisterAccelerometerAllCallbacks(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..5b648ee
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/AnalogGyroData.h
@@ -0,0 +1,51 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetAnalogGyroData(int32_t index);
+int32_t HALSIM_RegisterAnalogGyroAngleCallback(int32_t index,
+                                               HAL_NotifyCallback callback,
+                                               void* param,
+                                               HAL_Bool initialNotify);
+void HALSIM_CancelAnalogGyroAngleCallback(int32_t index, int32_t uid);
+double HALSIM_GetAnalogGyroAngle(int32_t index);
+void HALSIM_SetAnalogGyroAngle(int32_t index, double angle);
+
+int32_t HALSIM_RegisterAnalogGyroRateCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelAnalogGyroRateCallback(int32_t index, int32_t uid);
+double HALSIM_GetAnalogGyroRate(int32_t index);
+void HALSIM_SetAnalogGyroRate(int32_t index, double rate);
+
+int32_t HALSIM_RegisterAnalogGyroInitializedCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogGyroInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetAnalogGyroInitialized(int32_t index);
+void HALSIM_SetAnalogGyroInitialized(int32_t index, HAL_Bool initialized);
+
+void HALSIM_RegisterAnalogGyroAllCallbacks(int32_t index,
+                                           HAL_NotifyCallback callback,
+                                           void* param, HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..7a95164
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/AnalogInData.h
@@ -0,0 +1,101 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetAnalogInData(int32_t index);
+int32_t HALSIM_RegisterAnalogInInitializedCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetAnalogInInitialized(int32_t index);
+void HALSIM_SetAnalogInInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterAnalogInAverageBitsCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInAverageBitsCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetAnalogInAverageBits(int32_t index);
+void HALSIM_SetAnalogInAverageBits(int32_t index, int32_t averageBits);
+
+int32_t HALSIM_RegisterAnalogInOversampleBitsCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInOversampleBitsCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetAnalogInOversampleBits(int32_t index);
+void HALSIM_SetAnalogInOversampleBits(int32_t index, int32_t oversampleBits);
+
+int32_t HALSIM_RegisterAnalogInVoltageCallback(int32_t index,
+                                               HAL_NotifyCallback callback,
+                                               void* param,
+                                               HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInVoltageCallback(int32_t index, int32_t uid);
+double HALSIM_GetAnalogInVoltage(int32_t index);
+void HALSIM_SetAnalogInVoltage(int32_t index, double voltage);
+
+int32_t HALSIM_RegisterAnalogInAccumulatorInitializedCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInAccumulatorInitializedCallback(int32_t index,
+                                                         int32_t uid);
+HAL_Bool HALSIM_GetAnalogInAccumulatorInitialized(int32_t index);
+void HALSIM_SetAnalogInAccumulatorInitialized(int32_t index,
+                                              HAL_Bool accumulatorInitialized);
+
+int32_t HALSIM_RegisterAnalogInAccumulatorValueCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInAccumulatorValueCallback(int32_t index, int32_t uid);
+int64_t HALSIM_GetAnalogInAccumulatorValue(int32_t index);
+void HALSIM_SetAnalogInAccumulatorValue(int32_t index,
+                                        int64_t accumulatorValue);
+
+int32_t HALSIM_RegisterAnalogInAccumulatorCountCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInAccumulatorCountCallback(int32_t index, int32_t uid);
+int64_t HALSIM_GetAnalogInAccumulatorCount(int32_t index);
+void HALSIM_SetAnalogInAccumulatorCount(int32_t index,
+                                        int64_t accumulatorCount);
+
+int32_t HALSIM_RegisterAnalogInAccumulatorCenterCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInAccumulatorCenterCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetAnalogInAccumulatorCenter(int32_t index);
+void HALSIM_SetAnalogInAccumulatorCenter(int32_t index,
+                                         int32_t accumulatorCenter);
+
+int32_t HALSIM_RegisterAnalogInAccumulatorDeadbandCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogInAccumulatorDeadbandCallback(int32_t index,
+                                                      int32_t uid);
+int32_t HALSIM_GetAnalogInAccumulatorDeadband(int32_t index);
+void HALSIM_SetAnalogInAccumulatorDeadband(int32_t index,
+                                           int32_t accumulatorDeadband);
+
+void HALSIM_RegisterAnalogInAllCallbacks(int32_t index,
+                                         HAL_NotifyCallback callback,
+                                         void* param, HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..48046ec
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/AnalogOutData.h
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetAnalogOutData(int32_t index);
+int32_t HALSIM_RegisterAnalogOutVoltageCallback(int32_t index,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify);
+void HALSIM_CancelAnalogOutVoltageCallback(int32_t index, int32_t uid);
+double HALSIM_GetAnalogOutVoltage(int32_t index);
+void HALSIM_SetAnalogOutVoltage(int32_t index, double voltage);
+
+int32_t HALSIM_RegisterAnalogOutInitializedCallback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogOutInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetAnalogOutInitialized(int32_t index);
+void HALSIM_SetAnalogOutInitialized(int32_t index, HAL_Bool initialized);
+
+void HALSIM_RegisterAnalogOutAllCallbacks(int32_t index,
+                                          HAL_NotifyCallback callback,
+                                          void* param, HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..8146b8f
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/AnalogTriggerData.h
@@ -0,0 +1,68 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+enum HALSIM_AnalogTriggerMode : int32_t {
+  HALSIM_AnalogTriggerUnassigned,
+  HALSIM_AnalogTriggerFiltered,
+  HALSIM_AnalogTriggerAveraged
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetAnalogTriggerData(int32_t index);
+int32_t HALSIM_RegisterAnalogTriggerInitializedCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogTriggerInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetAnalogTriggerInitialized(int32_t index);
+void HALSIM_SetAnalogTriggerInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterAnalogTriggerTriggerLowerBoundCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogTriggerTriggerLowerBoundCallback(int32_t index,
+                                                         int32_t uid);
+double HALSIM_GetAnalogTriggerTriggerLowerBound(int32_t index);
+void HALSIM_SetAnalogTriggerTriggerLowerBound(int32_t index,
+                                              double triggerLowerBound);
+
+int32_t HALSIM_RegisterAnalogTriggerTriggerUpperBoundCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogTriggerTriggerUpperBoundCallback(int32_t index,
+                                                         int32_t uid);
+double HALSIM_GetAnalogTriggerTriggerUpperBound(int32_t index);
+void HALSIM_SetAnalogTriggerTriggerUpperBound(int32_t index,
+                                              double triggerUpperBound);
+
+int32_t HALSIM_RegisterAnalogTriggerTriggerModeCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelAnalogTriggerTriggerModeCallback(int32_t index, int32_t uid);
+HALSIM_AnalogTriggerMode HALSIM_GetAnalogTriggerTriggerMode(int32_t index);
+void HALSIM_SetAnalogTriggerTriggerMode(int32_t index,
+                                        HALSIM_AnalogTriggerMode triggerMode);
+
+void HALSIM_RegisterAnalogTriggerAllCallbacks(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..4d76dca
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/CanData.h
@@ -0,0 +1,78 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "HAL_Value.h"
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+typedef void (*HAL_CAN_SendMessageCallback)(const char* name, void* param,
+                                            uint32_t messageID,
+                                            const uint8_t* data,
+                                            uint8_t dataSize, int32_t periodMs,
+                                            int32_t* status);
+
+typedef void (*HAL_CAN_ReceiveMessageCallback)(
+    const char* name, void* param, uint32_t* messageID, uint32_t messageIDMask,
+    uint8_t* data, uint8_t* dataSize, uint32_t* timeStamp, int32_t* status);
+
+typedef void (*HAL_CAN_OpenStreamSessionCallback)(
+    const char* name, void* param, uint32_t* sessionHandle, uint32_t messageID,
+    uint32_t messageIDMask, uint32_t maxMessages, int32_t* status);
+
+typedef void (*HAL_CAN_CloseStreamSessionCallback)(const char* name,
+                                                   void* param,
+                                                   uint32_t sessionHandle);
+
+typedef void (*HAL_CAN_ReadStreamSessionCallback)(
+    const char* name, void* param, uint32_t sessionHandle,
+    struct HAL_CANStreamMessage* messages, uint32_t messagesToRead,
+    uint32_t* messagesRead, int32_t* status);
+
+typedef void (*HAL_CAN_GetCANStatusCallback)(
+    const char* name, void* param, float* percentBusUtilization,
+    uint32_t* busOffCount, uint32_t* txFullCount, uint32_t* receiveErrorCount,
+    uint32_t* transmitErrorCount, int32_t* status);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetCanData(void);
+
+int32_t HALSIM_RegisterCanSendMessageCallback(
+    HAL_CAN_SendMessageCallback callback, void* param);
+void HALSIM_CancelCanSendMessageCallback(int32_t uid);
+
+int32_t HALSIM_RegisterCanReceiveMessageCallback(
+    HAL_CAN_ReceiveMessageCallback callback, void* param);
+void HALSIM_CancelCanReceiveMessageCallback(int32_t uid);
+
+int32_t HALSIM_RegisterCanOpenStreamCallback(
+    HAL_CAN_OpenStreamSessionCallback callback, void* param);
+void HALSIM_CancelCanOpenStreamCallback(int32_t uid);
+
+int32_t HALSIM_RegisterCanCloseStreamCallback(
+    HAL_CAN_CloseStreamSessionCallback callback, void* param);
+void HALSIM_CancelCanCloseStreamCallback(int32_t uid);
+
+int32_t HALSIM_RegisterCanReadStreamCallback(
+    HAL_CAN_ReadStreamSessionCallback callback, void* param);
+void HALSIM_CancelCanReadStreamCallback(int32_t uid);
+
+int32_t HALSIM_RegisterCanGetCANStatusCallback(
+    HAL_CAN_GetCANStatusCallback callback, void* param);
+void HALSIM_CancelCanGetCANStatusCallback(int32_t uid);
+
+#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
new file mode 100644
index 0000000..b3bd9f2
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/DIOData.h
@@ -0,0 +1,65 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetDIOData(int32_t index);
+int32_t HALSIM_RegisterDIOInitializedCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelDIOInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetDIOInitialized(int32_t index);
+void HALSIM_SetDIOInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterDIOValueCallback(int32_t index,
+                                        HAL_NotifyCallback callback,
+                                        void* param, HAL_Bool initialNotify);
+void HALSIM_CancelDIOValueCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetDIOValue(int32_t index);
+void HALSIM_SetDIOValue(int32_t index, HAL_Bool value);
+
+int32_t HALSIM_RegisterDIOPulseLengthCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelDIOPulseLengthCallback(int32_t index, int32_t uid);
+double HALSIM_GetDIOPulseLength(int32_t index);
+void HALSIM_SetDIOPulseLength(int32_t index, double pulseLength);
+
+int32_t HALSIM_RegisterDIOIsInputCallback(int32_t index,
+                                          HAL_NotifyCallback callback,
+                                          void* param, HAL_Bool initialNotify);
+void HALSIM_CancelDIOIsInputCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetDIOIsInput(int32_t index);
+void HALSIM_SetDIOIsInput(int32_t index, HAL_Bool isInput);
+
+int32_t HALSIM_RegisterDIOFilterIndexCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelDIOFilterIndexCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetDIOFilterIndex(int32_t index);
+void HALSIM_SetDIOFilterIndex(int32_t index, int32_t filterIndex);
+
+void HALSIM_RegisterDIOAllCallbacks(int32_t index, HAL_NotifyCallback callback,
+                                    void* param, HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..d35e313
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/DigitalPWMData.h
@@ -0,0 +1,51 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetDigitalPWMData(int32_t index);
+int32_t HALSIM_RegisterDigitalPWMInitializedCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelDigitalPWMInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetDigitalPWMInitialized(int32_t index);
+void HALSIM_SetDigitalPWMInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterDigitalPWMDutyCycleCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelDigitalPWMDutyCycleCallback(int32_t index, int32_t uid);
+double HALSIM_GetDigitalPWMDutyCycle(int32_t index);
+void HALSIM_SetDigitalPWMDutyCycle(int32_t index, double dutyCycle);
+
+int32_t HALSIM_RegisterDigitalPWMPinCallback(int32_t index,
+                                             HAL_NotifyCallback callback,
+                                             void* param,
+                                             HAL_Bool initialNotify);
+void HALSIM_CancelDigitalPWMPinCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetDigitalPWMPin(int32_t index);
+void HALSIM_SetDigitalPWMPin(int32_t index, int32_t pin);
+
+void HALSIM_RegisterDigitalPWMAllCallbacks(int32_t index,
+                                           HAL_NotifyCallback callback,
+                                           void* param, HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..57ca4e0
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/DriverStationData.h
@@ -0,0 +1,95 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/DriverStationTypes.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetDriverStationData(void);
+int32_t HALSIM_RegisterDriverStationEnabledCallback(HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationEnabledCallback(int32_t uid);
+HAL_Bool HALSIM_GetDriverStationEnabled(void);
+void HALSIM_SetDriverStationEnabled(HAL_Bool enabled);
+
+int32_t HALSIM_RegisterDriverStationAutonomousCallback(
+    HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationAutonomousCallback(int32_t uid);
+HAL_Bool HALSIM_GetDriverStationAutonomous(void);
+void HALSIM_SetDriverStationAutonomous(HAL_Bool autonomous);
+
+int32_t HALSIM_RegisterDriverStationTestCallback(HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationTestCallback(int32_t uid);
+HAL_Bool HALSIM_GetDriverStationTest(void);
+void HALSIM_SetDriverStationTest(HAL_Bool test);
+
+int32_t HALSIM_RegisterDriverStationEStopCallback(HAL_NotifyCallback callback,
+                                                  void* param,
+                                                  HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationEStopCallback(int32_t uid);
+HAL_Bool HALSIM_GetDriverStationEStop(void);
+void HALSIM_SetDriverStationEStop(HAL_Bool eStop);
+
+int32_t HALSIM_RegisterDriverStationFmsAttachedCallback(
+    HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationFmsAttachedCallback(int32_t uid);
+HAL_Bool HALSIM_GetDriverStationFmsAttached(void);
+void HALSIM_SetDriverStationFmsAttached(HAL_Bool fmsAttached);
+
+int32_t HALSIM_RegisterDriverStationDsAttachedCallback(
+    HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationDsAttachedCallback(int32_t uid);
+HAL_Bool HALSIM_GetDriverStationDsAttached(void);
+void HALSIM_SetDriverStationDsAttached(HAL_Bool dsAttached);
+
+int32_t HALSIM_RegisterDriverStationAllianceStationIdCallback(
+    HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationAllianceStationIdCallback(int32_t uid);
+HAL_AllianceStationID HALSIM_GetDriverStationAllianceStationId(void);
+void HALSIM_SetDriverStationAllianceStationId(
+    HAL_AllianceStationID allianceStationId);
+
+int32_t HALSIM_RegisterDriverStationMatchTimeCallback(
+    HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
+void HALSIM_CancelDriverStationMatchTimeCallback(int32_t uid);
+double HALSIM_GetDriverStationMatchTime(void);
+void HALSIM_SetDriverStationMatchTime(double matchTime);
+
+void HALSIM_SetJoystickAxes(int32_t joystickNum, const HAL_JoystickAxes* axes);
+void HALSIM_SetJoystickPOVs(int32_t joystickNum, const HAL_JoystickPOVs* povs);
+void HALSIM_SetJoystickButtons(int32_t joystickNum,
+                               const HAL_JoystickButtons* buttons);
+void HALSIM_SetJoystickDescriptor(int32_t joystickNum,
+                                  const HAL_JoystickDescriptor* descriptor);
+
+void HALSIM_GetJoystickOutputs(int32_t joystickNum, int64_t* outputs,
+                               int32_t* leftRumble, int32_t* rightRumble);
+
+void HALSIM_SetMatchInfo(const HAL_MatchInfo* info);
+
+void HALSIM_RegisterDriverStationAllCallbacks(HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+
+void HALSIM_NotifyDriverStationNewData(void);
+
+#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
new file mode 100644
index 0000000..bcd00a7
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/EncoderData.h
@@ -0,0 +1,99 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetEncoderData(int32_t index);
+int16_t HALSIM_GetDigitalChannelA(int32_t index);
+int32_t HALSIM_RegisterEncoderInitializedCallback(int32_t index,
+                                                  HAL_NotifyCallback callback,
+                                                  void* param,
+                                                  HAL_Bool initialNotify);
+void HALSIM_CancelEncoderInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetEncoderInitialized(int32_t index);
+void HALSIM_SetEncoderInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterEncoderCountCallback(int32_t index,
+                                            HAL_NotifyCallback callback,
+                                            void* param,
+                                            HAL_Bool initialNotify);
+void HALSIM_CancelEncoderCountCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetEncoderCount(int32_t index);
+void HALSIM_SetEncoderCount(int32_t index, int32_t count);
+
+int32_t HALSIM_RegisterEncoderPeriodCallback(int32_t index,
+                                             HAL_NotifyCallback callback,
+                                             void* param,
+                                             HAL_Bool initialNotify);
+void HALSIM_CancelEncoderPeriodCallback(int32_t index, int32_t uid);
+double HALSIM_GetEncoderPeriod(int32_t index);
+void HALSIM_SetEncoderPeriod(int32_t index, double period);
+
+int32_t HALSIM_RegisterEncoderResetCallback(int32_t index,
+                                            HAL_NotifyCallback callback,
+                                            void* param,
+                                            HAL_Bool initialNotify);
+void HALSIM_CancelEncoderResetCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetEncoderReset(int32_t index);
+void HALSIM_SetEncoderReset(int32_t index, HAL_Bool reset);
+
+int32_t HALSIM_RegisterEncoderMaxPeriodCallback(int32_t index,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify);
+void HALSIM_CancelEncoderMaxPeriodCallback(int32_t index, int32_t uid);
+double HALSIM_GetEncoderMaxPeriod(int32_t index);
+void HALSIM_SetEncoderMaxPeriod(int32_t index, double maxPeriod);
+
+int32_t HALSIM_RegisterEncoderDirectionCallback(int32_t index,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify);
+void HALSIM_CancelEncoderDirectionCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetEncoderDirection(int32_t index);
+void HALSIM_SetEncoderDirection(int32_t index, HAL_Bool direction);
+
+int32_t HALSIM_RegisterEncoderReverseDirectionCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelEncoderReverseDirectionCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetEncoderReverseDirection(int32_t index);
+void HALSIM_SetEncoderReverseDirection(int32_t index,
+                                       HAL_Bool reverseDirection);
+
+int32_t HALSIM_RegisterEncoderSamplesToAverageCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelEncoderSamplesToAverageCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetEncoderSamplesToAverage(int32_t index);
+void HALSIM_SetEncoderSamplesToAverage(int32_t index, int32_t samplesToAverage);
+
+int32_t HALSIM_RegisterEncoderDistancePerPulseCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelEncoderDistancePerPulseCallback(int32_t index, int32_t uid);
+double HALSIM_GetEncoderDistancePerPulse(int32_t index);
+void HALSIM_SetEncoderDistancePerPulse(int32_t index, double distancePerPulse);
+
+void HALSIM_RegisterEncoderAllCallbacks(int32_t index,
+                                        HAL_NotifyCallback callback,
+                                        void* param, HAL_Bool initialNotify);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif
diff --git a/hal/src/main/native/include/mockdata/HAL_Value.h b/hal/src/main/native/include/mockdata/HAL_Value.h
new file mode 100644
index 0000000..ee348b9
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/HAL_Value.h
@@ -0,0 +1,71 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "hal/Types.h"
+
+/** HAL data types. */
+enum HAL_Type {
+  HAL_UNASSIGNED = 0,
+  HAL_BOOLEAN = 0x01,
+  HAL_DOUBLE = 0x02,
+  HAL_ENUM = 0x16,
+  HAL_INT = 0x32,
+  HAL_LONG = 0x64,
+};
+
+/** HAL Entry Value.  Note this is a typed union. */
+struct HAL_Value {
+  union {
+    HAL_Bool v_boolean;
+    int32_t v_enum;
+    int32_t v_int;
+    int64_t v_long;
+    double v_double;
+  } data;
+  enum HAL_Type type;
+};
+
+inline HAL_Value MakeBoolean(HAL_Bool v) {
+  HAL_Value value;
+  value.type = HAL_BOOLEAN;
+  value.data.v_boolean = v;
+  return value;
+}
+
+inline HAL_Value MakeEnum(int v) {
+  HAL_Value value;
+  value.type = HAL_ENUM;
+  value.data.v_enum = v;
+  return value;
+}
+
+inline HAL_Value MakeInt(int v) {
+  HAL_Value value;
+  value.type = HAL_INT;
+  value.data.v_int = v;
+  return value;
+}
+
+inline HAL_Value MakeLong(int64_t v) {
+  HAL_Value value;
+  value.type = HAL_LONG;
+  value.data.v_long = v;
+  return value;
+}
+
+inline HAL_Value MakeDouble(double v) {
+  HAL_Value value;
+  value.type = HAL_DOUBLE;
+  value.data.v_double = v;
+  return value;
+}
+
+#endif
diff --git a/hal/src/main/native/include/mockdata/I2CData.h b/hal/src/main/native/include/mockdata/I2CData.h
new file mode 100644
index 0000000..8565fdb
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/I2CData.h
@@ -0,0 +1,43 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetI2CData(int32_t index);
+
+int32_t HALSIM_RegisterI2CInitializedCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelI2CInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetI2CInitialized(int32_t index);
+void HALSIM_SetI2CInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterI2CReadCallback(int32_t index,
+                                       HAL_BufferCallback callback,
+                                       void* param);
+void HALSIM_CancelI2CReadCallback(int32_t index, int32_t uid);
+
+int32_t HALSIM_RegisterI2CWriteCallback(int32_t index,
+                                        HAL_ConstBufferCallback callback,
+                                        void* param);
+void HALSIM_CancelI2CWriteCallback(int32_t index, int32_t uid);
+
+#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
new file mode 100644
index 0000000..37eb0e7
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/MockHooks.h
@@ -0,0 +1,21 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "hal/Types.h"
+
+extern "C" {
+void HALSIM_WaitForProgramStart(void);
+void HALSIM_SetProgramStarted(void);
+HAL_Bool HALSIM_GetProgramStarted(void);
+void HALSIM_RestartTiming(void);
+}  // extern "C"
+
+#endif
diff --git a/hal/src/main/native/include/mockdata/NotifyListener.h b/hal/src/main/native/include/mockdata/NotifyListener.h
new file mode 100644
index 0000000..8d7e199
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/NotifyListener.h
@@ -0,0 +1,40 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "HAL_Value.h"
+
+typedef void (*HAL_NotifyCallback)(const char* name, void* param,
+                                   const struct HAL_Value* value);
+
+typedef void (*HAL_BufferCallback)(const char* name, void* param,
+                                   unsigned char* buffer, unsigned int count);
+
+typedef void (*HAL_ConstBufferCallback)(const char* name, void* param,
+                                        const unsigned char* buffer,
+                                        unsigned int count);
+
+namespace hal {
+
+template <typename CallbackFunction>
+struct HalCallbackListener {
+  HalCallbackListener() = default;
+  HalCallbackListener(void* param_, CallbackFunction callback_)
+      : callback(callback_), param(param_) {}
+
+  explicit operator bool() const { return callback != nullptr; }
+
+  CallbackFunction callback;
+  void* param;
+};
+
+}  // namespace hal
+
+#endif
diff --git a/hal/src/main/native/include/mockdata/PCMData.h b/hal/src/main/native/include/mockdata/PCMData.h
new file mode 100644
index 0000000..d919cc9
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/PCMData.h
@@ -0,0 +1,93 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetPCMData(int32_t index);
+int32_t HALSIM_RegisterPCMSolenoidInitializedCallback(
+    int32_t index, int32_t channel, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelPCMSolenoidInitializedCallback(int32_t index, int32_t channel,
+                                                 int32_t uid);
+HAL_Bool HALSIM_GetPCMSolenoidInitialized(int32_t index, int32_t channel);
+void HALSIM_SetPCMSolenoidInitialized(int32_t index, int32_t channel,
+                                      HAL_Bool solenoidInitialized);
+
+int32_t HALSIM_RegisterPCMSolenoidOutputCallback(int32_t index, int32_t channel,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelPCMSolenoidOutputCallback(int32_t index, int32_t channel,
+                                            int32_t uid);
+HAL_Bool HALSIM_GetPCMSolenoidOutput(int32_t index, int32_t channel);
+void HALSIM_SetPCMSolenoidOutput(int32_t index, int32_t channel,
+                                 HAL_Bool solenoidOutput);
+
+int32_t HALSIM_RegisterPCMCompressorInitializedCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelPCMCompressorInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetPCMCompressorInitialized(int32_t index);
+void HALSIM_SetPCMCompressorInitialized(int32_t index,
+                                        HAL_Bool compressorInitialized);
+
+int32_t HALSIM_RegisterPCMCompressorOnCallback(int32_t index,
+                                               HAL_NotifyCallback callback,
+                                               void* param,
+                                               HAL_Bool initialNotify);
+void HALSIM_CancelPCMCompressorOnCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetPCMCompressorOn(int32_t index);
+void HALSIM_SetPCMCompressorOn(int32_t index, HAL_Bool compressorOn);
+
+int32_t HALSIM_RegisterPCMClosedLoopEnabledCallback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelPCMClosedLoopEnabledCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetPCMClosedLoopEnabled(int32_t index);
+void HALSIM_SetPCMClosedLoopEnabled(int32_t index, HAL_Bool closedLoopEnabled);
+
+int32_t HALSIM_RegisterPCMPressureSwitchCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelPCMPressureSwitchCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetPCMPressureSwitch(int32_t index);
+void HALSIM_SetPCMPressureSwitch(int32_t index, HAL_Bool pressureSwitch);
+
+int32_t HALSIM_RegisterPCMCompressorCurrentCallback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelPCMCompressorCurrentCallback(int32_t index, int32_t uid);
+double HALSIM_GetPCMCompressorCurrent(int32_t index);
+void HALSIM_SetPCMCompressorCurrent(int32_t index, double compressorCurrent);
+
+void HALSIM_RegisterPCMAllNonSolenoidCallbacks(int32_t index,
+                                               HAL_NotifyCallback callback,
+                                               void* param,
+                                               HAL_Bool initialNotify);
+
+void HALSIM_RegisterPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                            HAL_NotifyCallback callback,
+                                            void* param,
+                                            HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..be24da8
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/PDPData.h
@@ -0,0 +1,60 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetPDPData(int32_t index);
+int32_t HALSIM_RegisterPDPInitializedCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelPDPInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetPDPInitialized(int32_t index);
+void HALSIM_SetPDPInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterPDPTemperatureCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelPDPTemperatureCallback(int32_t index, int32_t uid);
+double HALSIM_GetPDPTemperature(int32_t index);
+void HALSIM_SetPDPTemperature(int32_t index, double temperature);
+
+int32_t HALSIM_RegisterPDPVoltageCallback(int32_t index,
+                                          HAL_NotifyCallback callback,
+                                          void* param, HAL_Bool initialNotify);
+void HALSIM_CancelPDPVoltageCallback(int32_t index, int32_t uid);
+double HALSIM_GetPDPVoltage(int32_t index);
+void HALSIM_SetPDPVoltage(int32_t index, double voltage);
+
+int32_t HALSIM_RegisterPDPCurrentCallback(int32_t index, int32_t channel,
+                                          HAL_NotifyCallback callback,
+                                          void* param, HAL_Bool initialNotify);
+void HALSIM_CancelPDPCurrentCallback(int32_t index, int32_t channel,
+                                     int32_t uid);
+double HALSIM_GetPDPCurrent(int32_t index, int32_t channel);
+void HALSIM_SetPDPCurrent(int32_t index, int32_t channel, double current);
+
+void HALSIM_RegisterPDPAllNonCurrentCallbacks(int32_t index, int32_t channel,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..08ba357
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/PWMData.h
@@ -0,0 +1,72 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetPWMData(int32_t index);
+int32_t HALSIM_RegisterPWMInitializedCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelPWMInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetPWMInitialized(int32_t index);
+void HALSIM_SetPWMInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterPWMRawValueCallback(int32_t index,
+                                           HAL_NotifyCallback callback,
+                                           void* param, HAL_Bool initialNotify);
+void HALSIM_CancelPWMRawValueCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetPWMRawValue(int32_t index);
+void HALSIM_SetPWMRawValue(int32_t index, int32_t rawValue);
+
+int32_t HALSIM_RegisterPWMSpeedCallback(int32_t index,
+                                        HAL_NotifyCallback callback,
+                                        void* param, HAL_Bool initialNotify);
+void HALSIM_CancelPWMSpeedCallback(int32_t index, int32_t uid);
+double HALSIM_GetPWMSpeed(int32_t index);
+void HALSIM_SetPWMSpeed(int32_t index, double speed);
+
+int32_t HALSIM_RegisterPWMPositionCallback(int32_t index,
+                                           HAL_NotifyCallback callback,
+                                           void* param, HAL_Bool initialNotify);
+void HALSIM_CancelPWMPositionCallback(int32_t index, int32_t uid);
+double HALSIM_GetPWMPosition(int32_t index);
+void HALSIM_SetPWMPosition(int32_t index, double position);
+
+int32_t HALSIM_RegisterPWMPeriodScaleCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelPWMPeriodScaleCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetPWMPeriodScale(int32_t index);
+void HALSIM_SetPWMPeriodScale(int32_t index, int32_t periodScale);
+
+int32_t HALSIM_RegisterPWMZeroLatchCallback(int32_t index,
+                                            HAL_NotifyCallback callback,
+                                            void* param,
+                                            HAL_Bool initialNotify);
+void HALSIM_CancelPWMZeroLatchCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetPWMZeroLatch(int32_t index);
+void HALSIM_SetPWMZeroLatch(int32_t index, HAL_Bool zeroLatch);
+
+void HALSIM_RegisterPWMAllCallbacks(int32_t index, HAL_NotifyCallback callback,
+                                    void* param, HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..6fdac7f
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/RelayData.h
@@ -0,0 +1,60 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetRelayData(int32_t index);
+int32_t HALSIM_RegisterRelayInitializedForwardCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelRelayInitializedForwardCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRelayInitializedForward(int32_t index);
+void HALSIM_SetRelayInitializedForward(int32_t index,
+                                       HAL_Bool initializedForward);
+
+int32_t HALSIM_RegisterRelayInitializedReverseCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelRelayInitializedReverseCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRelayInitializedReverse(int32_t index);
+void HALSIM_SetRelayInitializedReverse(int32_t index,
+                                       HAL_Bool initializedReverse);
+
+int32_t HALSIM_RegisterRelayForwardCallback(int32_t index,
+                                            HAL_NotifyCallback callback,
+                                            void* param,
+                                            HAL_Bool initialNotify);
+void HALSIM_CancelRelayForwardCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRelayForward(int32_t index);
+void HALSIM_SetRelayForward(int32_t index, HAL_Bool forward);
+
+int32_t HALSIM_RegisterRelayReverseCallback(int32_t index,
+                                            HAL_NotifyCallback callback,
+                                            void* param,
+                                            HAL_Bool initialNotify);
+void HALSIM_CancelRelayReverseCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRelayReverse(int32_t index);
+void HALSIM_SetRelayReverse(int32_t index, HAL_Bool reverse);
+
+void HALSIM_RegisterRelayAllCallbacks(int32_t index,
+                                      HAL_NotifyCallback callback, void* param,
+                                      HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..88b6ece
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/RoboRioData.h
@@ -0,0 +1,146 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetRoboRioData(int32_t index);
+int32_t HALSIM_RegisterRoboRioFPGAButtonCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioFPGAButtonCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRoboRioFPGAButton(int32_t index);
+void HALSIM_SetRoboRioFPGAButton(int32_t index, HAL_Bool fPGAButton);
+
+int32_t HALSIM_RegisterRoboRioVInVoltageCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioVInVoltageCallback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioVInVoltage(int32_t index);
+void HALSIM_SetRoboRioVInVoltage(int32_t index, double vInVoltage);
+
+int32_t HALSIM_RegisterRoboRioVInCurrentCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioVInCurrentCallback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioVInCurrent(int32_t index);
+void HALSIM_SetRoboRioVInCurrent(int32_t index, double vInCurrent);
+
+int32_t HALSIM_RegisterRoboRioUserVoltage6VCallback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserVoltage6VCallback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioUserVoltage6V(int32_t index);
+void HALSIM_SetRoboRioUserVoltage6V(int32_t index, double userVoltage6V);
+
+int32_t HALSIM_RegisterRoboRioUserCurrent6VCallback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserCurrent6VCallback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioUserCurrent6V(int32_t index);
+void HALSIM_SetRoboRioUserCurrent6V(int32_t index, double userCurrent6V);
+
+int32_t HALSIM_RegisterRoboRioUserActive6VCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserActive6VCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRoboRioUserActive6V(int32_t index);
+void HALSIM_SetRoboRioUserActive6V(int32_t index, HAL_Bool userActive6V);
+
+int32_t HALSIM_RegisterRoboRioUserVoltage5VCallback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserVoltage5VCallback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioUserVoltage5V(int32_t index);
+void HALSIM_SetRoboRioUserVoltage5V(int32_t index, double userVoltage5V);
+
+int32_t HALSIM_RegisterRoboRioUserCurrent5VCallback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserCurrent5VCallback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioUserCurrent5V(int32_t index);
+void HALSIM_SetRoboRioUserCurrent5V(int32_t index, double userCurrent5V);
+
+int32_t HALSIM_RegisterRoboRioUserActive5VCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserActive5VCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRoboRioUserActive5V(int32_t index);
+void HALSIM_SetRoboRioUserActive5V(int32_t index, HAL_Bool userActive5V);
+
+int32_t HALSIM_RegisterRoboRioUserVoltage3V3Callback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserVoltage3V3Callback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioUserVoltage3V3(int32_t index);
+void HALSIM_SetRoboRioUserVoltage3V3(int32_t index, double userVoltage3V3);
+
+int32_t HALSIM_RegisterRoboRioUserCurrent3V3Callback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserCurrent3V3Callback(int32_t index, int32_t uid);
+double HALSIM_GetRoboRioUserCurrent3V3(int32_t index);
+void HALSIM_SetRoboRioUserCurrent3V3(int32_t index, double userCurrent3V3);
+
+int32_t HALSIM_RegisterRoboRioUserActive3V3Callback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserActive3V3Callback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetRoboRioUserActive3V3(int32_t index);
+void HALSIM_SetRoboRioUserActive3V3(int32_t index, HAL_Bool userActive3V3);
+
+int32_t HALSIM_RegisterRoboRioUserFaults6VCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserFaults6VCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetRoboRioUserFaults6V(int32_t index);
+void HALSIM_SetRoboRioUserFaults6V(int32_t index, int32_t userFaults6V);
+
+int32_t HALSIM_RegisterRoboRioUserFaults5VCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserFaults5VCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetRoboRioUserFaults5V(int32_t index);
+void HALSIM_SetRoboRioUserFaults5V(int32_t index, int32_t userFaults5V);
+
+int32_t HALSIM_RegisterRoboRioUserFaults3V3Callback(int32_t index,
+                                                    HAL_NotifyCallback callback,
+                                                    void* param,
+                                                    HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioUserFaults3V3Callback(int32_t index, int32_t uid);
+int32_t HALSIM_GetRoboRioUserFaults3V3(int32_t index);
+void HALSIM_SetRoboRioUserFaults3V3(int32_t index, int32_t userFaults3V3);
+
+void HALSIM_RegisterRoboRioAllCallbacks(int32_t index,
+                                        HAL_NotifyCallback callback,
+                                        void* param, HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..6e37f40
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/SPIAccelerometerData.h
@@ -0,0 +1,67 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetSPIAccelerometerData(int32_t index);
+int32_t HALSIM_RegisterSPIAccelerometerActiveCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelSPIAccelerometerActiveCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetSPIAccelerometerActive(int32_t index);
+void HALSIM_SetSPIAccelerometerActive(int32_t index, HAL_Bool active);
+
+int32_t HALSIM_RegisterSPIAccelerometerRangeCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelSPIAccelerometerRangeCallback(int32_t index, int32_t uid);
+int32_t HALSIM_GetSPIAccelerometerRange(int32_t index);
+void HALSIM_SetSPIAccelerometerRange(int32_t index, int32_t range);
+
+int32_t HALSIM_RegisterSPIAccelerometerXCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelSPIAccelerometerXCallback(int32_t index, int32_t uid);
+double HALSIM_GetSPIAccelerometerX(int32_t index);
+void HALSIM_SetSPIAccelerometerX(int32_t index, double x);
+
+int32_t HALSIM_RegisterSPIAccelerometerYCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelSPIAccelerometerYCallback(int32_t index, int32_t uid);
+double HALSIM_GetSPIAccelerometerY(int32_t index);
+void HALSIM_SetSPIAccelerometerY(int32_t index, double y);
+
+int32_t HALSIM_RegisterSPIAccelerometerZCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelSPIAccelerometerZCallback(int32_t index, int32_t uid);
+double HALSIM_GetSPIAccelerometerZ(int32_t index);
+void HALSIM_SetSPIAccelerometerZ(int32_t index, double z);
+
+void HALSIM_RegisterSPIAccelerometerAllCallbcaks(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+
+#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
new file mode 100644
index 0000000..54a2ec9
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/SPIData.h
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "NotifyListener.h"
+#include "hal/Types.h"
+
+typedef void (*HAL_SpiReadAutoReceiveBufferCallback)(const char* name,
+                                                     void* param,
+                                                     uint32_t* buffer,
+                                                     int32_t numToRead,
+                                                     int32_t* outputCount);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetSPIData(int32_t index);
+
+int32_t HALSIM_RegisterSPIInitializedCallback(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+void HALSIM_CancelSPIInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetSPIInitialized(int32_t index);
+void HALSIM_SetSPIInitialized(int32_t index, HAL_Bool initialized);
+
+int32_t HALSIM_RegisterSPIReadCallback(int32_t index,
+                                       HAL_BufferCallback callback,
+                                       void* param);
+void HALSIM_CancelSPIReadCallback(int32_t index, int32_t uid);
+
+int32_t HALSIM_RegisterSPIWriteCallback(int32_t index,
+                                        HAL_ConstBufferCallback callback,
+                                        void* param);
+void HALSIM_CancelSPIWriteCallback(int32_t index, int32_t uid);
+
+int32_t HALSIM_RegisterSPIReadAutoReceivedDataCallback(
+    int32_t index, HAL_SpiReadAutoReceiveBufferCallback callback, void* param);
+void HALSIM_CancelSPIReadAutoReceivedDataCallback(int32_t index, int32_t uid);
+
+#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
new file mode 100644
index 0000000..da3f0f9
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/SimCallbackRegistry.h
@@ -0,0 +1,151 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <memory>
+#include <utility>
+
+#include <wpi/Compiler.h>
+#include <wpi/UidVector.h>
+#include <wpi/spinlock.h>
+
+#include "mockdata/NotifyListener.h"
+
+namespace hal {
+
+namespace impl {
+
+class SimCallbackRegistryBase {
+ public:
+  using RawFunctor = void (*)();
+
+ protected:
+  using CallbackVector = wpi::UidVector<HalCallbackListener<RawFunctor>, 4>;
+
+ public:
+  void Cancel(int32_t uid) {
+    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    if (m_callbacks) m_callbacks->erase(uid - 1);
+  }
+
+  void Reset() {
+    std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
+    DoReset();
+  }
+
+  wpi::recursive_spinlock& GetMutex() { return m_mutex; }
+
+ protected:
+  int32_t DoRegister(RawFunctor 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, callback) + 1;
+  }
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE void DoReset() {
+    if (m_callbacks) m_callbacks->clear();
+  }
+
+  mutable wpi::recursive_spinlock m_mutex;
+  std::unique_ptr<CallbackVector> m_callbacks;
+};
+
+}  // namespace impl
+
+/**
+ * Simulation callback registry.  Provides callback functionality.
+ *
+ * @tparam CallbackFunction callback function type (e.g. HAL_BufferCallback)
+ * @tparam GetName function that returns a const char* for the name
+ */
+template <typename CallbackFunction, const char* (*GetName)()>
+class SimCallbackRegistry : public impl::SimCallbackRegistryBase {
+ public:
+  int32_t Register(CallbackFunction callback, void* param) {
+    std::lock_guard<wpi::recursive_spinlock> 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);
+    if (m_callbacks) {
+      const char* name = GetName();
+      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)...);
+  }
+};
+
+/**
+ * Define a name functor for use with SimCallbackRegistry.
+ * This creates a function named GetNAMEName() that returns "NAME".
+ * @param NAME the name to return
+ */
+#define HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(NAME)           \
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr const char* \
+      Get##NAME##Name() {                                   \
+    return #NAME;                                           \
+  }
+
+/**
+ * Define a standard C API for SimCallbackRegistry.
+ *
+ * Functions defined:
+ * - int32 NS_RegisterCAPINAMECallback(
+ *      int32_t index, TYPE callback, void* param)
+ * - void NS_CancelCAPINAMECallback(int32_t index, int32_t uid)
+ *
+ * @param TYPE the underlying callback type (e.g. HAL_BufferCallback)
+ * @param NS the "namespace" (e.g. HALSIM)
+ * @param CAPINAME the C API name (usually first letter capitalized)
+ * @param DATA the backing data array
+ * @param LOWERNAME the lowercase name of the backing data registry
+ */
+#define HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI(TYPE, NS, CAPINAME, DATA,     \
+                                            LOWERNAME)                    \
+  int32_t NS##_Register##CAPINAME##Callback(int32_t index, TYPE callback, \
+                                            void* param) {                \
+    return DATA[index].LOWERNAME.Register(callback, param);               \
+  }                                                                       \
+                                                                          \
+  void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t uid) {      \
+    DATA[index].LOWERNAME.Cancel(uid);                                    \
+  }
+
+/**
+ * Define a standard C API for SimCallbackRegistry (no index variant).
+ *
+ * Functions defined:
+ * - int32 NS_RegisterCAPINAMECallback(TYPE callback, void* param)
+ * - void NS_CancelCAPINAMECallback(int32_t uid)
+ *
+ * @param TYPE the underlying callback type (e.g. HAL_BufferCallback)
+ * @param NS the "namespace" (e.g. HALSIM)
+ * @param CAPINAME the C API name (usually first letter capitalized)
+ * @param DATA the backing data pointer
+ * @param LOWERNAME the lowercase name of the backing data registry
+ */
+#define HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI_NOINDEX(TYPE, NS, CAPINAME, DATA, \
+                                                    LOWERNAME)                \
+  int32_t NS##_Register##CAPINAME##Callback(TYPE callback, void* param) {     \
+    return DATA->LOWERNAME.Register(callback, param);                         \
+  }                                                                           \
+                                                                              \
+  void NS##_Cancel##CAPINAME##Callback(int32_t uid) {                         \
+    DATA->LOWERNAME.Cancel(uid);                                              \
+  }
+
+}  // namespace hal
diff --git a/hal/src/main/native/include/mockdata/SimDataValue.h b/hal/src/main/native/include/mockdata/SimDataValue.h
new file mode 100644
index 0000000..3b518b9
--- /dev/null
+++ b/hal/src/main/native/include/mockdata/SimDataValue.h
@@ -0,0 +1,227 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <memory>
+
+#include <wpi/Compiler.h>
+#include <wpi/UidVector.h>
+#include <wpi/spinlock.h>
+
+#include "mockdata/NotifyListener.h"
+#include "mockdata/SimCallbackRegistry.h"
+
+namespace hal {
+
+namespace impl {
+template <typename T, HAL_Value (*MakeValue)(T)>
+class SimDataValueBase : protected SimCallbackRegistryBase {
+ public:
+  explicit SimDataValueBase(T value) : m_value(value) {}
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE void CancelCallback(int32_t uid) { Cancel(uid); }
+
+  T Get() const {
+    std::lock_guard<wpi::recursive_spinlock> 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);
+    DoReset();
+    m_value = value;
+  }
+
+  wpi::recursive_spinlock& GetMutex() { return m_mutex; }
+
+ protected:
+  int32_t DoRegisterCallback(HAL_NotifyCallback callback, void* param,
+                             HAL_Bool initialNotify, const char* name) {
+    std::unique_lock<wpi::recursive_spinlock> lock(m_mutex);
+    int32_t newUid = DoRegister(reinterpret_cast<RawFunctor>(callback), param);
+    if (newUid == -1) return -1;
+    if (initialNotify) {
+      // We know that the callback is not null because of earlier null check
+      HAL_Value value = MakeValue(m_value);
+      lock.unlock();
+      callback(name, param, &value);
+    }
+    return newUid + 1;
+  }
+
+  void DoSet(T value, const char* name) {
+    std::lock_guard<wpi::recursive_spinlock> lock(this->m_mutex);
+    if (m_value != value) {
+      m_value = value;
+      if (m_callbacks) {
+        HAL_Value halValue = MakeValue(value);
+        for (auto&& cb : *m_callbacks)
+          reinterpret_cast<HAL_NotifyCallback>(cb.callback)(name, cb.param,
+                                                            &halValue);
+      }
+    }
+  }
+
+  T m_value;
+};
+}  // namespace impl
+
+/**
+ * Simulation data value wrapper.  Provides callback functionality when the
+ * data value is changed.
+ *
+ * @tparam T value type (e.g. double)
+ * @tparam MakeValue function that takes a T and returns a HAL_Value
+ * @tparam GetName function that returns a const char* for the name
+ * @tparam GetDefault function that returns the default T (used only for
+ *                    default constructor)
+ */
+template <typename T, HAL_Value (*MakeValue)(T), const char* (*GetName)(),
+          T (*GetDefault)() = nullptr>
+class SimDataValue final : public impl::SimDataValueBase<T, MakeValue> {
+ public:
+  SimDataValue()
+      : impl::SimDataValueBase<T, MakeValue>(
+            GetDefault != nullptr ? GetDefault() : T()) {}
+  explicit SimDataValue(T value)
+      : impl::SimDataValueBase<T, MakeValue>(value) {}
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE int32_t RegisterCallback(
+      HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {
+    return this->DoRegisterCallback(callback, param, initialNotify, GetName());
+  }
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE void Set(T value) {
+    this->DoSet(value, GetName());
+  }
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE SimDataValue& operator=(T value) {
+    Set(value);
+    return *this;
+  }
+};
+
+/**
+ * Define a name functor for use with SimDataValue.
+ * This creates a function named GetNAMEName() that returns "NAME".
+ * @param NAME the name to return
+ */
+#define HAL_SIMDATAVALUE_DEFINE_NAME(NAME)                  \
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr const char* \
+      Get##NAME##Name() {                                   \
+    return #NAME;                                           \
+  }
+
+/**
+ * Define a standard C API for simulation data.
+ *
+ * Functions defined:
+ * - int32 NS_RegisterCAPINAMECallback(
+ *      int32_t index, HAL_NotifyCallback callback, void* param,
+ *      HAL_Bool initialNotify)
+ * - void NS_CancelCAPINAMECallback(int32_t index, int32_t uid)
+ * - TYPE NS_GetCAPINAME(int32_t index)
+ * - void NS_SetCAPINAME(int32_t index, TYPE value)
+ *
+ * @param TYPE the underlying value type (e.g. double)
+ * @param NS the "namespace" (e.g. HALSIM)
+ * @param CAPINAME the C API name (usually first letter capitalized)
+ * @param DATA the backing data array
+ * @param LOWERNAME the lowercase name of the backing data variable
+ */
+#define HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, NS, CAPINAME, DATA, LOWERNAME)  \
+  int32_t NS##_Register##CAPINAME##Callback(                               \
+      int32_t index, HAL_NotifyCallback callback, void* param,             \
+      HAL_Bool initialNotify) {                                            \
+    return DATA[index].LOWERNAME.RegisterCallback(callback, param,         \
+                                                  initialNotify);          \
+  }                                                                        \
+                                                                           \
+  void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t uid) {       \
+    DATA[index].LOWERNAME.CancelCallback(uid);                             \
+  }                                                                        \
+                                                                           \
+  TYPE NS##_Get##CAPINAME(int32_t index) { return DATA[index].LOWERNAME; } \
+                                                                           \
+  void NS##_Set##CAPINAME(int32_t index, TYPE LOWERNAME) {                 \
+    DATA[index].LOWERNAME = LOWERNAME;                                     \
+  }
+
+/**
+ * Define a standard C API for simulation data (channel variant).
+ *
+ * Functions defined:
+ * - int32 NS_RegisterCAPINAMECallback(
+ *      int32_t index, int32_t channel, HAL_NotifyCallback callback,
+ *      void* param, HAL_Bool initialNotify)
+ * - void NS_CancelCAPINAMECallback(int32_t index, int32_t channel, int32_t uid)
+ * - TYPE NS_GetCAPINAME(int32_t index, int32_t channel)
+ * - void NS_SetCAPINAME(int32_t index, int32_t channel, TYPE value)
+ *
+ * @param TYPE the underlying value type (e.g. double)
+ * @param NS the "namespace" (e.g. HALSIM)
+ * @param CAPINAME the C API name (usually first letter capitalized)
+ * @param DATA the backing data array
+ * @param LOWERNAME the lowercase name of the backing data variable array
+ */
+#define HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(TYPE, NS, CAPINAME, DATA,      \
+                                             LOWERNAME)                     \
+  int32_t NS##_Register##CAPINAME##Callback(                                \
+      int32_t index, int32_t channel, HAL_NotifyCallback callback,          \
+      void* param, HAL_Bool initialNotify) {                                \
+    return DATA[index].LOWERNAME[channel].RegisterCallback(callback, param, \
+                                                           initialNotify);  \
+  }                                                                         \
+                                                                            \
+  void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t channel,      \
+                                       int32_t uid) {                       \
+    DATA[index].LOWERNAME[channel].CancelCallback(uid);                     \
+  }                                                                         \
+                                                                            \
+  TYPE NS##_Get##CAPINAME(int32_t index, int32_t channel) {                 \
+    return DATA[index].LOWERNAME[channel];                                  \
+  }                                                                         \
+                                                                            \
+  void NS##_Set##CAPINAME(int32_t index, int32_t channel, TYPE LOWERNAME) { \
+    DATA[index].LOWERNAME[channel] = LOWERNAME;                             \
+  }
+
+/**
+ * Define a standard C API for simulation data (no index variant).
+ *
+ * Functions defined:
+ * - int32 NS_RegisterCAPINAMECallback(
+ *      HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify)
+ * - void NS_CancelCAPINAMECallback(int32_t uid)
+ * - TYPE NS_GetCAPINAME(void)
+ * - void NS_SetCAPINAME(TYPE value)
+ *
+ * @param TYPE the underlying value type (e.g. double)
+ * @param NS the "namespace" (e.g. HALSIM)
+ * @param CAPINAME the C API name (usually first letter capitalized)
+ * @param DATA the backing data pointer
+ * @param LOWERNAME the lowercase name of the backing data variable
+ */
+#define HAL_SIMDATAVALUE_DEFINE_CAPI_NOINDEX(TYPE, NS, CAPINAME, DATA,       \
+                                             LOWERNAME)                      \
+  int32_t NS##_Register##CAPINAME##Callback(                                 \
+      HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {    \
+    return DATA->LOWERNAME.RegisterCallback(callback, param, initialNotify); \
+  }                                                                          \
+                                                                             \
+  void NS##_Cancel##CAPINAME##Callback(int32_t uid) {                        \
+    DATA->LOWERNAME.CancelCallback(uid);                                     \
+  }                                                                          \
+                                                                             \
+  TYPE NS##_Get##CAPINAME(void) { return DATA->LOWERNAME; }                  \
+                                                                             \
+  void NS##_Set##CAPINAME(TYPE LOWERNAME) { DATA->LOWERNAME = LOWERNAME; }
+
+}  // namespace hal
diff --git a/hal/src/main/native/include/simulation/AccelerometerSim.h b/hal/src/main/native/include/simulation/AccelerometerSim.h
new file mode 100644
index 0000000..ea873c7
--- /dev/null
+++ b/hal/src/main/native/include/simulation/AccelerometerSim.h
@@ -0,0 +1,102 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/AccelerometerData.h"
+
+namespace frc {
+namespace sim {
+class AccelerometerSim {
+ public:
+  explicit AccelerometerSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterActiveCallback(NotifyCallback callback,
+                                                        bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAccelerometerActiveCallback);
+    store->SetUid(HALSIM_RegisterAccelerometerActiveCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetActive() const { return HALSIM_GetAccelerometerActive(m_index); }
+
+  void SetActive(bool active) {
+    HALSIM_SetAccelerometerActive(m_index, active);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterRangeCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAccelerometerRangeCallback);
+    store->SetUid(HALSIM_RegisterAccelerometerRangeCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  HAL_AccelerometerRange GetRange() const {
+    return HALSIM_GetAccelerometerRange(m_index);
+  }
+
+  void SetRange(HAL_AccelerometerRange range) {
+    HALSIM_SetAccelerometerRange(m_index, range);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterXCallback(NotifyCallback callback,
+                                                   bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAccelerometerXCallback);
+    store->SetUid(HALSIM_RegisterAccelerometerXCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetX() const { return HALSIM_GetAccelerometerX(m_index); }
+
+  void SetX(double x) { HALSIM_SetAccelerometerX(m_index, x); }
+
+  std::unique_ptr<CallbackStore> RegisterYCallback(NotifyCallback callback,
+                                                   bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAccelerometerYCallback);
+    store->SetUid(HALSIM_RegisterAccelerometerYCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetY() const { return HALSIM_GetAccelerometerY(m_index); }
+
+  void SetY(double y) { HALSIM_SetAccelerometerY(m_index, y); }
+
+  std::unique_ptr<CallbackStore> RegisterZCallback(NotifyCallback callback,
+                                                   bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAccelerometerZCallback);
+    store->SetUid(HALSIM_RegisterAccelerometerZCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetZ() const { return HALSIM_GetAccelerometerZ(m_index); }
+
+  void SetZ(double z) { HALSIM_SetAccelerometerZ(m_index, z); }
+
+  void ResetData() { HALSIM_ResetAccelerometerData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..b4c48ca
--- /dev/null
+++ b/hal/src/main/native/include/simulation/AnalogGyroSim.h
@@ -0,0 +1,74 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/AnalogGyroData.h"
+
+namespace frc {
+namespace sim {
+class AnalogGyroSim {
+ public:
+  explicit AnalogGyroSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterAngleCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogGyroAngleCallback);
+    store->SetUid(HALSIM_RegisterAnalogGyroAngleCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetAngle() const { return HALSIM_GetAnalogGyroAngle(m_index); }
+
+  void SetAngle(double angle) { HALSIM_SetAnalogGyroAngle(m_index, angle); }
+
+  std::unique_ptr<CallbackStore> RegisterRateCallback(NotifyCallback callback,
+                                                      bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogGyroRateCallback);
+    store->SetUid(HALSIM_RegisterAnalogGyroRateCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetRate() const { return HALSIM_GetAnalogGyroRate(m_index); }
+
+  void SetRate(double rate) { HALSIM_SetAnalogGyroRate(m_index, rate); }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogGyroInitializedCallback);
+    store->SetUid(HALSIM_RegisterAnalogGyroInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const {
+    return HALSIM_GetAnalogGyroInitialized(m_index);
+  }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetAnalogGyroInitialized(m_index, initialized);
+  }
+
+  void ResetData() { HALSIM_ResetAnalogGyroData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..a513c33
--- /dev/null
+++ b/hal/src/main/native/include/simulation/AnalogInSim.h
@@ -0,0 +1,180 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/AnalogInData.h"
+
+namespace frc {
+namespace sim {
+class AnalogInSim {
+ public:
+  explicit AnalogInSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogInInitializedCallback);
+    store->SetUid(HALSIM_RegisterAnalogInInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const { return HALSIM_GetAnalogInInitialized(m_index); }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetAnalogInInitialized(m_index, initialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterAverageBitsCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogInAverageBitsCallback);
+    store->SetUid(HALSIM_RegisterAnalogInAverageBitsCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetAverageBits() const { return HALSIM_GetAnalogInAverageBits(m_index); }
+
+  void SetAverageBits(int averageBits) {
+    HALSIM_SetAnalogInAverageBits(m_index, averageBits);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterOversampleBitsCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogInOversampleBitsCallback);
+    store->SetUid(HALSIM_RegisterAnalogInOversampleBitsCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetOversampleBits() const {
+    return HALSIM_GetAnalogInOversampleBits(m_index);
+  }
+
+  void SetOversampleBits(int oversampleBits) {
+    HALSIM_SetAnalogInOversampleBits(m_index, oversampleBits);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterVoltageCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogInVoltageCallback);
+    store->SetUid(HALSIM_RegisterAnalogInVoltageCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetVoltage() const { return HALSIM_GetAnalogInVoltage(m_index); }
+
+  void SetVoltage(double voltage) {
+    HALSIM_SetAnalogInVoltage(m_index, voltage);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterAccumulatorInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback,
+        &HALSIM_CancelAnalogInAccumulatorInitializedCallback);
+    store->SetUid(HALSIM_RegisterAnalogInAccumulatorInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetAccumulatorInitialized() const {
+    return HALSIM_GetAnalogInAccumulatorInitialized(m_index);
+  }
+
+  void SetAccumulatorInitialized(bool accumulatorInitialized) {
+    HALSIM_SetAnalogInAccumulatorInitialized(m_index, accumulatorInitialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterAccumulatorValueCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogInAccumulatorValueCallback);
+    store->SetUid(HALSIM_RegisterAnalogInAccumulatorValueCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int64_t GetAccumulatorValue() const {
+    return HALSIM_GetAnalogInAccumulatorValue(m_index);
+  }
+
+  void SetAccumulatorValue(int64_t accumulatorValue) {
+    HALSIM_SetAnalogInAccumulatorValue(m_index, accumulatorValue);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterAccumulatorCountCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogInAccumulatorCountCallback);
+    store->SetUid(HALSIM_RegisterAnalogInAccumulatorCountCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int64_t GetAccumulatorCount() const {
+    return HALSIM_GetAnalogInAccumulatorCount(m_index);
+  }
+
+  void SetAccumulatorCount(int64_t accumulatorCount) {
+    HALSIM_SetAnalogInAccumulatorCount(m_index, accumulatorCount);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterAccumulatorCenterCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogInAccumulatorCenterCallback);
+    store->SetUid(HALSIM_RegisterAnalogInAccumulatorCenterCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetAccumulatorCenter() const {
+    return HALSIM_GetAnalogInAccumulatorCenter(m_index);
+  }
+
+  void SetAccumulatorCenter(int accumulatorCenter) {
+    HALSIM_SetAnalogInAccumulatorCenter(m_index, accumulatorCenter);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterAccumulatorDeadbandCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback,
+        &HALSIM_CancelAnalogInAccumulatorDeadbandCallback);
+    store->SetUid(HALSIM_RegisterAnalogInAccumulatorDeadbandCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetAccumulatorDeadband() const {
+    return HALSIM_GetAnalogInAccumulatorDeadband(m_index);
+  }
+
+  void SetAccumulatorDeadband(int accumulatorDeadband) {
+    HALSIM_SetAnalogInAccumulatorDeadband(m_index, accumulatorDeadband);
+  }
+
+  void ResetData() { HALSIM_ResetAnalogInData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..3617a66
--- /dev/null
+++ b/hal/src/main/native/include/simulation/AnalogOutSim.h
@@ -0,0 +1,63 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/AnalogOutData.h"
+
+namespace frc {
+namespace sim {
+class AnalogOutSim {
+ public:
+  explicit AnalogOutSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterVoltageCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogOutVoltageCallback);
+    store->SetUid(HALSIM_RegisterAnalogOutVoltageCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetVoltage() const { return HALSIM_GetAnalogOutVoltage(m_index); }
+
+  void SetVoltage(double voltage) {
+    HALSIM_SetAnalogOutVoltage(m_index, voltage);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogOutInitializedCallback);
+    store->SetUid(HALSIM_RegisterAnalogOutInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const {
+    return HALSIM_GetAnalogOutInitialized(m_index);
+  }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetAnalogOutInitialized(m_index, initialized);
+  }
+
+  void ResetData() { HALSIM_ResetAnalogOutData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..04faf05
--- /dev/null
+++ b/hal/src/main/native/include/simulation/AnalogTriggerSim.h
@@ -0,0 +1,84 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/AnalogTriggerData.h"
+
+namespace frc {
+namespace sim {
+class AnalogTriggerSim {
+ public:
+  explicit AnalogTriggerSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelAnalogTriggerInitializedCallback);
+    store->SetUid(HALSIM_RegisterAnalogTriggerInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const {
+    return HALSIM_GetAnalogTriggerInitialized(m_index);
+  }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetAnalogTriggerInitialized(m_index, initialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterTriggerLowerBoundCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback,
+        &HALSIM_CancelAnalogTriggerTriggerLowerBoundCallback);
+    store->SetUid(HALSIM_RegisterAnalogTriggerTriggerLowerBoundCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetTriggerLowerBound() const {
+    return HALSIM_GetAnalogTriggerTriggerLowerBound(m_index);
+  }
+
+  void SetTriggerLowerBound(double triggerLowerBound) {
+    HALSIM_SetAnalogTriggerTriggerLowerBound(m_index, triggerLowerBound);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterTriggerUpperBoundCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback,
+        &HALSIM_CancelAnalogTriggerTriggerUpperBoundCallback);
+    store->SetUid(HALSIM_RegisterAnalogTriggerTriggerUpperBoundCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetTriggerUpperBound() const {
+    return HALSIM_GetAnalogTriggerTriggerUpperBound(m_index);
+  }
+
+  void SetTriggerUpperBound(double triggerUpperBound) {
+    HALSIM_SetAnalogTriggerTriggerUpperBound(m_index, triggerUpperBound);
+  }
+
+  void ResetData() { HALSIM_ResetAnalogTriggerData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..967e963
--- /dev/null
+++ b/hal/src/main/native/include/simulation/CallbackStore.h
@@ -0,0 +1,93 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <functional>
+
+#include <wpi/StringRef.h>
+
+#include "mockdata/HAL_Value.h"
+
+namespace frc {
+namespace sim {
+
+using NotifyCallback = std::function<void(wpi::StringRef, const HAL_Value*)>;
+typedef void (*CancelCallbackFunc)(int32_t index, int32_t uid);
+typedef void (*CancelCallbackNoIndexFunc)(int32_t uid);
+typedef void (*CancelCallbackChannelFunc)(int32_t index, int32_t channel,
+                                          int32_t uid);
+
+void CallbackStoreThunk(const char* name, void* param, const HAL_Value* value);
+
+class CallbackStore {
+ public:
+  CallbackStore(int32_t i, NotifyCallback cb, CancelCallbackNoIndexFunc ccf) {
+    index = i;
+    callback = cb;
+    this->ccnif = ccf;
+    cancelType = NoIndex;
+  }
+
+  CallbackStore(int32_t i, int32_t u, NotifyCallback cb,
+                CancelCallbackFunc ccf) {
+    index = i;
+    uid = u;
+    callback = cb;
+    this->ccf = ccf;
+    cancelType = Normal;
+  }
+
+  CallbackStore(int32_t i, int32_t c, int32_t u, NotifyCallback cb,
+                CancelCallbackChannelFunc ccf) {
+    index = i;
+    channel = c;
+    uid = u;
+    callback = cb;
+    this->cccf = ccf;
+    cancelType = Channel;
+  }
+
+  ~CallbackStore() {
+    switch (cancelType) {
+      case Normal:
+        ccf(index, uid);
+        break;
+      case Channel:
+        cccf(index, channel, uid);
+        break;
+      case NoIndex:
+        ccnif(uid);
+        break;
+    }
+  }
+
+  void SetUid(int32_t uid) { this->uid = uid; }
+
+  friend void CallbackStoreThunk(const char* name, void* param,
+                                 const HAL_Value* value);
+
+ private:
+  int32_t index;
+  int32_t channel;
+  int32_t uid;
+
+  NotifyCallback callback;
+  union {
+    CancelCallbackFunc ccf;
+    CancelCallbackChannelFunc cccf;
+    CancelCallbackNoIndexFunc ccnif;
+  };
+  enum CancelType { Normal, Channel, NoIndex };
+  CancelType cancelType;
+};
+}  // 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
new file mode 100644
index 0000000..b4fe947
--- /dev/null
+++ b/hal/src/main/native/include/simulation/DIOSim.h
@@ -0,0 +1,102 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/DIOData.h"
+
+namespace frc {
+namespace sim {
+class DIOSim {
+ public:
+  explicit DIOSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDIOInitializedCallback);
+    store->SetUid(HALSIM_RegisterDIOInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const { return HALSIM_GetDIOInitialized(m_index); }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetDIOInitialized(m_index, initialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterValueCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDIOValueCallback);
+    store->SetUid(HALSIM_RegisterDIOValueCallback(m_index, &CallbackStoreThunk,
+                                                  store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetValue() const { return HALSIM_GetDIOValue(m_index); }
+
+  void SetValue(bool value) { HALSIM_SetDIOValue(m_index, value); }
+
+  std::unique_ptr<CallbackStore> RegisterPulseLengthCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDIOPulseLengthCallback);
+    store->SetUid(HALSIM_RegisterDIOPulseLengthCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetPulseLength() const { return HALSIM_GetDIOPulseLength(m_index); }
+
+  void SetPulseLength(double pulseLength) {
+    HALSIM_SetDIOPulseLength(m_index, pulseLength);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterIsInputCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDIOIsInputCallback);
+    store->SetUid(HALSIM_RegisterDIOIsInputCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetIsInput() const { return HALSIM_GetDIOIsInput(m_index); }
+
+  void SetIsInput(bool isInput) { HALSIM_SetDIOIsInput(m_index, isInput); }
+
+  std::unique_ptr<CallbackStore> RegisterFilterIndexCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDIOFilterIndexCallback);
+    store->SetUid(HALSIM_RegisterDIOFilterIndexCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetFilterIndex() const { return HALSIM_GetDIOFilterIndex(m_index); }
+
+  void SetFilterIndex(int filterIndex) {
+    HALSIM_SetDIOFilterIndex(m_index, filterIndex);
+  }
+
+  void ResetData() { HALSIM_ResetDIOData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..ecfc56d
--- /dev/null
+++ b/hal/src/main/native/include/simulation/DigitalPWMSim.h
@@ -0,0 +1,76 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/DigitalPWMData.h"
+
+namespace frc {
+namespace sim {
+class DigitalPWMSim {
+ public:
+  explicit DigitalPWMSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDigitalPWMInitializedCallback);
+    store->SetUid(HALSIM_RegisterDigitalPWMInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const {
+    return HALSIM_GetDigitalPWMInitialized(m_index);
+  }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetDigitalPWMInitialized(m_index, initialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterDutyCycleCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDigitalPWMDutyCycleCallback);
+    store->SetUid(HALSIM_RegisterDigitalPWMDutyCycleCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetDutyCycle() const { return HALSIM_GetDigitalPWMDutyCycle(m_index); }
+
+  void SetDutyCycle(double dutyCycle) {
+    HALSIM_SetDigitalPWMDutyCycle(m_index, dutyCycle);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterPinCallback(NotifyCallback callback,
+                                                     bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelDigitalPWMPinCallback);
+    store->SetUid(HALSIM_RegisterDigitalPWMPinCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetPin() const { return HALSIM_GetDigitalPWMPin(m_index); }
+
+  void SetPin(int pin) { HALSIM_SetDigitalPWMPin(m_index, pin); }
+
+  void ResetData() { HALSIM_ResetDigitalPWMData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..55c38a9
--- /dev/null
+++ b/hal/src/main/native/include/simulation/DriverStationSim.h
@@ -0,0 +1,112 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/DriverStationData.h"
+
+namespace frc {
+namespace sim {
+class DriverStationSim {
+ public:
+  std::unique_ptr<CallbackStore> RegisterEnabledCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        -1, callback, &HALSIM_CancelDriverStationEnabledCallback);
+    store->SetUid(HALSIM_RegisterDriverStationEnabledCallback(
+        &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetEnabled() const { return HALSIM_GetDriverStationEnabled(); }
+
+  void SetEnabled(bool enabled) { HALSIM_SetDriverStationEnabled(enabled); }
+
+  std::unique_ptr<CallbackStore> RegisterAutonomousCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        -1, callback, &HALSIM_CancelDriverStationAutonomousCallback);
+    store->SetUid(HALSIM_RegisterDriverStationAutonomousCallback(
+        &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetAutonomous() const { return HALSIM_GetDriverStationAutonomous(); }
+
+  void SetAutonomous(bool autonomous) {
+    HALSIM_SetDriverStationAutonomous(autonomous);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterTestCallback(NotifyCallback callback,
+                                                      bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        -1, callback, &HALSIM_CancelDriverStationTestCallback);
+    store->SetUid(HALSIM_RegisterDriverStationTestCallback(
+        &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetTest() const { return HALSIM_GetDriverStationTest(); }
+
+  void SetTest(bool test) { HALSIM_SetDriverStationTest(test); }
+
+  std::unique_ptr<CallbackStore> RegisterEStopCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        -1, callback, &HALSIM_CancelDriverStationEStopCallback);
+    store->SetUid(HALSIM_RegisterDriverStationEStopCallback(
+        &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetEStop() const { return HALSIM_GetDriverStationEStop(); }
+
+  void SetEStop(bool eStop) { HALSIM_SetDriverStationEStop(eStop); }
+
+  std::unique_ptr<CallbackStore> RegisterFmsAttachedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        -1, callback, &HALSIM_CancelDriverStationFmsAttachedCallback);
+    store->SetUid(HALSIM_RegisterDriverStationFmsAttachedCallback(
+        &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetFmsAttached() const { return HALSIM_GetDriverStationFmsAttached(); }
+
+  void SetFmsAttached(bool fmsAttached) {
+    HALSIM_SetDriverStationFmsAttached(fmsAttached);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterDsAttachedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        -1, callback, &HALSIM_CancelDriverStationDsAttachedCallback);
+    store->SetUid(HALSIM_RegisterDriverStationDsAttachedCallback(
+        &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetDsAttached() const { return HALSIM_GetDriverStationDsAttached(); }
+
+  void SetDsAttached(bool dsAttached) {
+    HALSIM_SetDriverStationDsAttached(dsAttached);
+  }
+
+  void NotifyNewData() { HALSIM_NotifyDriverStationNewData(); }
+
+  void ResetData() { HALSIM_ResetDriverStationData(); }
+};
+}  // 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
new file mode 100644
index 0000000..493f338
--- /dev/null
+++ b/hal/src/main/native/include/simulation/EncoderSim.h
@@ -0,0 +1,166 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/EncoderData.h"
+
+namespace frc {
+namespace sim {
+class EncoderSim {
+ public:
+  explicit EncoderSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderInitializedCallback);
+    store->SetUid(HALSIM_RegisterEncoderInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const { return HALSIM_GetEncoderInitialized(m_index); }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetEncoderInitialized(m_index, initialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterCountCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderCountCallback);
+    store->SetUid(HALSIM_RegisterEncoderCountCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetCount() const { return HALSIM_GetEncoderCount(m_index); }
+
+  void SetCount(int count) { HALSIM_SetEncoderCount(m_index, count); }
+
+  std::unique_ptr<CallbackStore> RegisterPeriodCallback(NotifyCallback callback,
+                                                        bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderPeriodCallback);
+    store->SetUid(HALSIM_RegisterEncoderPeriodCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetPeriod() const { return HALSIM_GetEncoderPeriod(m_index); }
+
+  void SetPeriod(double period) { HALSIM_SetEncoderPeriod(m_index, period); }
+
+  std::unique_ptr<CallbackStore> RegisterResetCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderResetCallback);
+    store->SetUid(HALSIM_RegisterEncoderResetCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetReset() const { return HALSIM_GetEncoderReset(m_index); }
+
+  void SetReset(bool reset) { HALSIM_SetEncoderReset(m_index, reset); }
+
+  std::unique_ptr<CallbackStore> RegisterMaxPeriodCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderMaxPeriodCallback);
+    store->SetUid(HALSIM_RegisterEncoderMaxPeriodCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetMaxPeriod() const { return HALSIM_GetEncoderMaxPeriod(m_index); }
+
+  void SetMaxPeriod(double maxPeriod) {
+    HALSIM_SetEncoderMaxPeriod(m_index, maxPeriod);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterDirectionCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderDirectionCallback);
+    store->SetUid(HALSIM_RegisterEncoderDirectionCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetDirection() const { return HALSIM_GetEncoderDirection(m_index); }
+
+  void SetDirection(bool direction) {
+    HALSIM_SetEncoderDirection(m_index, direction);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterReverseDirectionCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderReverseDirectionCallback);
+    store->SetUid(HALSIM_RegisterEncoderReverseDirectionCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetReverseDirection() const {
+    return HALSIM_GetEncoderReverseDirection(m_index);
+  }
+
+  void SetReverseDirection(bool reverseDirection) {
+    HALSIM_SetEncoderReverseDirection(m_index, reverseDirection);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterSamplesToAverageCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderSamplesToAverageCallback);
+    store->SetUid(HALSIM_RegisterEncoderSamplesToAverageCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetSamplesToAverage() const {
+    return HALSIM_GetEncoderSamplesToAverage(m_index);
+  }
+
+  void SetSamplesToAverage(int samplesToAverage) {
+    HALSIM_SetEncoderSamplesToAverage(m_index, samplesToAverage);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterDistancePerPulseCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelEncoderDistancePerPulseCallback);
+    store->SetUid(HALSIM_RegisterEncoderDistancePerPulseCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetDistancePerPulse() const {
+    return HALSIM_GetEncoderDistancePerPulse(m_index);
+  }
+
+  void SetDistancePerPulse(double distancePerPulse) {
+    HALSIM_SetEncoderDistancePerPulse(m_index, distancePerPulse);
+  }
+
+  void ResetData() { HALSIM_ResetEncoderData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..bfefa6e
--- /dev/null
+++ b/hal/src/main/native/include/simulation/PCMSim.h
@@ -0,0 +1,150 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/PCMData.h"
+
+namespace frc {
+namespace sim {
+class PCMSim {
+ public:
+  explicit PCMSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterSolenoidInitializedCallback(
+      int channel, NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, channel, -1, callback,
+        &HALSIM_CancelPCMSolenoidInitializedCallback);
+    store->SetUid(HALSIM_RegisterPCMSolenoidInitializedCallback(
+        m_index, channel, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetSolenoidInitialized(int channel) const {
+    return HALSIM_GetPCMSolenoidInitialized(m_index, channel);
+  }
+
+  void SetSolenoidInitialized(int channel, bool solenoidInitialized) {
+    HALSIM_SetPCMSolenoidInitialized(m_index, channel, solenoidInitialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterSolenoidOutputCallback(
+      int channel, NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, channel, -1, callback,
+        &HALSIM_CancelPCMSolenoidOutputCallback);
+    store->SetUid(HALSIM_RegisterPCMSolenoidOutputCallback(
+        m_index, channel, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetSolenoidOutput(int channel) const {
+    return HALSIM_GetPCMSolenoidOutput(m_index, channel);
+  }
+
+  void SetSolenoidOutput(int channel, bool solenoidOutput) {
+    HALSIM_SetPCMSolenoidOutput(m_index, channel, solenoidOutput);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterCompressorInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPCMCompressorInitializedCallback);
+    store->SetUid(HALSIM_RegisterPCMCompressorInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetCompressorInitialized() const {
+    return HALSIM_GetPCMCompressorInitialized(m_index);
+  }
+
+  void SetCompressorInitialized(bool compressorInitialized) {
+    HALSIM_SetPCMCompressorInitialized(m_index, compressorInitialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterCompressorOnCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPCMCompressorOnCallback);
+    store->SetUid(HALSIM_RegisterPCMCompressorOnCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetCompressorOn() const { return HALSIM_GetPCMCompressorOn(m_index); }
+
+  void SetCompressorOn(bool compressorOn) {
+    HALSIM_SetPCMCompressorOn(m_index, compressorOn);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterClosedLoopEnabledCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPCMClosedLoopEnabledCallback);
+    store->SetUid(HALSIM_RegisterPCMClosedLoopEnabledCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetClosedLoopEnabled() const {
+    return HALSIM_GetPCMClosedLoopEnabled(m_index);
+  }
+
+  void SetClosedLoopEnabled(bool closedLoopEnabled) {
+    HALSIM_SetPCMClosedLoopEnabled(m_index, closedLoopEnabled);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterPressureSwitchCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPCMPressureSwitchCallback);
+    store->SetUid(HALSIM_RegisterPCMPressureSwitchCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetPressureSwitch() const {
+    return HALSIM_GetPCMPressureSwitch(m_index);
+  }
+
+  void SetPressureSwitch(bool pressureSwitch) {
+    HALSIM_SetPCMPressureSwitch(m_index, pressureSwitch);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterCompressorCurrentCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPCMCompressorCurrentCallback);
+    store->SetUid(HALSIM_RegisterPCMCompressorCurrentCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetCompressorCurrent() const {
+    return HALSIM_GetPCMCompressorCurrent(m_index);
+  }
+
+  void SetCompressorCurrent(double compressorCurrent) {
+    HALSIM_SetPCMCompressorCurrent(m_index, compressorCurrent);
+  }
+
+  void ResetData() { HALSIM_ResetPCMData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..7677ec2
--- /dev/null
+++ b/hal/src/main/native/include/simulation/PDPSim.h
@@ -0,0 +1,91 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/PDPData.h"
+
+namespace frc {
+namespace sim {
+class PDPSim {
+ public:
+  explicit PDPSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPDPInitializedCallback);
+    store->SetUid(HALSIM_RegisterPDPInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const { return HALSIM_GetPDPInitialized(m_index); }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetPDPInitialized(m_index, initialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterTemperatureCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPDPTemperatureCallback);
+    store->SetUid(HALSIM_RegisterPDPTemperatureCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetTemperature() const { return HALSIM_GetPDPTemperature(m_index); }
+
+  void SetTemperature(double temperature) {
+    HALSIM_SetPDPTemperature(m_index, temperature);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterVoltageCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPDPVoltageCallback);
+    store->SetUid(HALSIM_RegisterPDPVoltageCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetVoltage() const { return HALSIM_GetPDPVoltage(m_index); }
+
+  void SetVoltage(double voltage) { HALSIM_SetPDPVoltage(m_index, voltage); }
+
+  std::unique_ptr<CallbackStore> RegisterCurrentCallback(
+      int channel, NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, channel, -1, callback, &HALSIM_CancelPDPCurrentCallback);
+    store->SetUid(HALSIM_RegisterPDPCurrentCallback(
+        m_index, channel, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetCurrent(int channel) const {
+    return HALSIM_GetPDPCurrent(m_index, channel);
+  }
+
+  void SetCurrent(int channel, double current) {
+    HALSIM_SetPDPCurrent(m_index, channel, current);
+  }
+
+  void ResetData() { HALSIM_ResetPDPData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..b90b76f
--- /dev/null
+++ b/hal/src/main/native/include/simulation/PWMSim.h
@@ -0,0 +1,117 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/PWMData.h"
+
+namespace frc {
+namespace sim {
+class PWMSim {
+ public:
+  explicit PWMSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPWMInitializedCallback);
+    store->SetUid(HALSIM_RegisterPWMInitializedCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitialized() const { return HALSIM_GetPWMInitialized(m_index); }
+
+  void SetInitialized(bool initialized) {
+    HALSIM_SetPWMInitialized(m_index, initialized);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterRawValueCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPWMRawValueCallback);
+    store->SetUid(HALSIM_RegisterPWMRawValueCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetRawValue() const { return HALSIM_GetPWMRawValue(m_index); }
+
+  void SetRawValue(int rawValue) { HALSIM_SetPWMRawValue(m_index, rawValue); }
+
+  std::unique_ptr<CallbackStore> RegisterSpeedCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPWMSpeedCallback);
+    store->SetUid(HALSIM_RegisterPWMSpeedCallback(m_index, &CallbackStoreThunk,
+                                                  store.get(), initialNotify));
+    return store;
+  }
+
+  double GetSpeed() const { return HALSIM_GetPWMSpeed(m_index); }
+
+  void SetSpeed(double speed) { HALSIM_SetPWMSpeed(m_index, speed); }
+
+  std::unique_ptr<CallbackStore> RegisterPositionCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPWMPositionCallback);
+    store->SetUid(HALSIM_RegisterPWMPositionCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetPosition() const { return HALSIM_GetPWMPosition(m_index); }
+
+  void SetPosition(double position) {
+    HALSIM_SetPWMPosition(m_index, position);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterPeriodScaleCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPWMPeriodScaleCallback);
+    store->SetUid(HALSIM_RegisterPWMPeriodScaleCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetPeriodScale() const { return HALSIM_GetPWMPeriodScale(m_index); }
+
+  void SetPeriodScale(int periodScale) {
+    HALSIM_SetPWMPeriodScale(m_index, periodScale);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterZeroLatchCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelPWMZeroLatchCallback);
+    store->SetUid(HALSIM_RegisterPWMZeroLatchCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetZeroLatch() const { return HALSIM_GetPWMZeroLatch(m_index); }
+
+  void SetZeroLatch(bool zeroLatch) {
+    HALSIM_SetPWMZeroLatch(m_index, zeroLatch);
+  }
+
+  void ResetData() { HALSIM_ResetPWMData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..b21a047
--- /dev/null
+++ b/hal/src/main/native/include/simulation/RelaySim.h
@@ -0,0 +1,91 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/RelayData.h"
+
+namespace frc {
+namespace sim {
+class RelaySim {
+ public:
+  explicit RelaySim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedForwardCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRelayInitializedForwardCallback);
+    store->SetUid(HALSIM_RegisterRelayInitializedForwardCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitializedForward() const {
+    return HALSIM_GetRelayInitializedForward(m_index);
+  }
+
+  void SetInitializedForward(bool initializedForward) {
+    HALSIM_SetRelayInitializedForward(m_index, initializedForward);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterInitializedReverseCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRelayInitializedReverseCallback);
+    store->SetUid(HALSIM_RegisterRelayInitializedReverseCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetInitializedReverse() const {
+    return HALSIM_GetRelayInitializedReverse(m_index);
+  }
+
+  void SetInitializedReverse(bool initializedReverse) {
+    HALSIM_SetRelayInitializedReverse(m_index, initializedReverse);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterForwardCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRelayForwardCallback);
+    store->SetUid(HALSIM_RegisterRelayForwardCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetForward() const { return HALSIM_GetRelayForward(m_index); }
+
+  void SetForward(bool forward) { HALSIM_SetRelayForward(m_index, forward); }
+
+  std::unique_ptr<CallbackStore> RegisterReverseCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRelayReverseCallback);
+    store->SetUid(HALSIM_RegisterRelayReverseCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetReverse() const { return HALSIM_GetRelayReverse(m_index); }
+
+  void SetReverse(bool reverse) { HALSIM_SetRelayReverse(m_index, reverse); }
+
+  void ResetData() { HALSIM_ResetRelayData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..0d7c31c
--- /dev/null
+++ b/hal/src/main/native/include/simulation/RoboRioSim.h
@@ -0,0 +1,276 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/RoboRioData.h"
+
+namespace frc {
+namespace sim {
+class RoboRioSim {
+ public:
+  explicit RoboRioSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterFPGAButtonCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioFPGAButtonCallback);
+    store->SetUid(HALSIM_RegisterRoboRioFPGAButtonCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetFPGAButton() const { return HALSIM_GetRoboRioFPGAButton(m_index); }
+
+  void SetFPGAButton(bool fPGAButton) {
+    HALSIM_SetRoboRioFPGAButton(m_index, fPGAButton);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterVInVoltageCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioVInVoltageCallback);
+    store->SetUid(HALSIM_RegisterRoboRioVInVoltageCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetVInVoltage() const { return HALSIM_GetRoboRioVInVoltage(m_index); }
+
+  void SetVInVoltage(double vInVoltage) {
+    HALSIM_SetRoboRioVInVoltage(m_index, vInVoltage);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterVInCurrentCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioVInCurrentCallback);
+    store->SetUid(HALSIM_RegisterRoboRioVInCurrentCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetVInCurrent() const { return HALSIM_GetRoboRioVInCurrent(m_index); }
+
+  void SetVInCurrent(double vInCurrent) {
+    HALSIM_SetRoboRioVInCurrent(m_index, vInCurrent);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserVoltage6VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserVoltage6VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserVoltage6VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetUserVoltage6V() const {
+    return HALSIM_GetRoboRioUserVoltage6V(m_index);
+  }
+
+  void SetUserVoltage6V(double userVoltage6V) {
+    HALSIM_SetRoboRioUserVoltage6V(m_index, userVoltage6V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserCurrent6VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserCurrent6VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserCurrent6VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetUserCurrent6V() const {
+    return HALSIM_GetRoboRioUserCurrent6V(m_index);
+  }
+
+  void SetUserCurrent6V(double userCurrent6V) {
+    HALSIM_SetRoboRioUserCurrent6V(m_index, userCurrent6V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserActive6VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserActive6VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserActive6VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetUserActive6V() const {
+    return HALSIM_GetRoboRioUserActive6V(m_index);
+  }
+
+  void SetUserActive6V(bool userActive6V) {
+    HALSIM_SetRoboRioUserActive6V(m_index, userActive6V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserVoltage5VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserVoltage5VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserVoltage5VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetUserVoltage5V() const {
+    return HALSIM_GetRoboRioUserVoltage5V(m_index);
+  }
+
+  void SetUserVoltage5V(double userVoltage5V) {
+    HALSIM_SetRoboRioUserVoltage5V(m_index, userVoltage5V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserCurrent5VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserCurrent5VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserCurrent5VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetUserCurrent5V() const {
+    return HALSIM_GetRoboRioUserCurrent5V(m_index);
+  }
+
+  void SetUserCurrent5V(double userCurrent5V) {
+    HALSIM_SetRoboRioUserCurrent5V(m_index, userCurrent5V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserActive5VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserActive5VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserActive5VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetUserActive5V() const {
+    return HALSIM_GetRoboRioUserActive5V(m_index);
+  }
+
+  void SetUserActive5V(bool userActive5V) {
+    HALSIM_SetRoboRioUserActive5V(m_index, userActive5V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserVoltage3V3Callback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserVoltage3V3Callback);
+    store->SetUid(HALSIM_RegisterRoboRioUserVoltage3V3Callback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetUserVoltage3V3() const {
+    return HALSIM_GetRoboRioUserVoltage3V3(m_index);
+  }
+
+  void SetUserVoltage3V3(double userVoltage3V3) {
+    HALSIM_SetRoboRioUserVoltage3V3(m_index, userVoltage3V3);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserCurrent3V3Callback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserCurrent3V3Callback);
+    store->SetUid(HALSIM_RegisterRoboRioUserCurrent3V3Callback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetUserCurrent3V3() const {
+    return HALSIM_GetRoboRioUserCurrent3V3(m_index);
+  }
+
+  void SetUserCurrent3V3(double userCurrent3V3) {
+    HALSIM_SetRoboRioUserCurrent3V3(m_index, userCurrent3V3);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserActive3V3Callback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserActive3V3Callback);
+    store->SetUid(HALSIM_RegisterRoboRioUserActive3V3Callback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetUserActive3V3() const {
+    return HALSIM_GetRoboRioUserActive3V3(m_index);
+  }
+
+  void SetUserActive3V3(bool userActive3V3) {
+    HALSIM_SetRoboRioUserActive3V3(m_index, userActive3V3);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserFaults6VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserFaults6VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserFaults6VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetUserFaults6V() const { return HALSIM_GetRoboRioUserFaults6V(m_index); }
+
+  void SetUserFaults6V(int userFaults6V) {
+    HALSIM_SetRoboRioUserFaults6V(m_index, userFaults6V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserFaults5VCallback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserFaults5VCallback);
+    store->SetUid(HALSIM_RegisterRoboRioUserFaults5VCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetUserFaults5V() const { return HALSIM_GetRoboRioUserFaults5V(m_index); }
+
+  void SetUserFaults5V(int userFaults5V) {
+    HALSIM_SetRoboRioUserFaults5V(m_index, userFaults5V);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterUserFaults3V3Callback(
+      NotifyCallback callback, bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelRoboRioUserFaults3V3Callback);
+    store->SetUid(HALSIM_RegisterRoboRioUserFaults3V3Callback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetUserFaults3V3() const {
+    return HALSIM_GetRoboRioUserFaults3V3(m_index);
+  }
+
+  void SetUserFaults3V3(int userFaults3V3) {
+    HALSIM_SetRoboRioUserFaults3V3(m_index, userFaults3V3);
+  }
+
+  void ResetData() { HALSIM_ResetRoboRioData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..4369938
--- /dev/null
+++ b/hal/src/main/native/include/simulation/SPIAccelerometerSim.h
@@ -0,0 +1,98 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include <memory>
+#include <utility>
+
+#include "CallbackStore.h"
+#include "mockdata/SPIAccelerometerData.h"
+
+namespace frc {
+namespace sim {
+class SPIAccelerometerSim {
+ public:
+  explicit SPIAccelerometerSim(int index) { m_index = index; }
+
+  std::unique_ptr<CallbackStore> RegisterActiveCallback(NotifyCallback callback,
+                                                        bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelSPIAccelerometerActiveCallback);
+    store->SetUid(HALSIM_RegisterSPIAccelerometerActiveCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  bool GetActive() const { return HALSIM_GetSPIAccelerometerActive(m_index); }
+
+  void SetActive(bool active) {
+    HALSIM_SetSPIAccelerometerActive(m_index, active);
+  }
+
+  std::unique_ptr<CallbackStore> RegisterRangeCallback(NotifyCallback callback,
+                                                       bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelSPIAccelerometerRangeCallback);
+    store->SetUid(HALSIM_RegisterSPIAccelerometerRangeCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  int GetRange() const { return HALSIM_GetSPIAccelerometerRange(m_index); }
+
+  void SetRange(int range) { HALSIM_SetSPIAccelerometerRange(m_index, range); }
+
+  std::unique_ptr<CallbackStore> RegisterXCallback(NotifyCallback callback,
+                                                   bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelSPIAccelerometerXCallback);
+    store->SetUid(HALSIM_RegisterSPIAccelerometerXCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetX() const { return HALSIM_GetSPIAccelerometerX(m_index); }
+
+  void SetX(double x) { HALSIM_SetSPIAccelerometerX(m_index, x); }
+
+  std::unique_ptr<CallbackStore> RegisterYCallback(NotifyCallback callback,
+                                                   bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelSPIAccelerometerYCallback);
+    store->SetUid(HALSIM_RegisterSPIAccelerometerYCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetY() const { return HALSIM_GetSPIAccelerometerY(m_index); }
+
+  void SetY(double y) { HALSIM_SetSPIAccelerometerY(m_index, y); }
+
+  std::unique_ptr<CallbackStore> RegisterZCallback(NotifyCallback callback,
+                                                   bool initialNotify) {
+    auto store = std::make_unique<CallbackStore>(
+        m_index, -1, callback, &HALSIM_CancelSPIAccelerometerZCallback);
+    store->SetUid(HALSIM_RegisterSPIAccelerometerZCallback(
+        m_index, &CallbackStoreThunk, store.get(), initialNotify));
+    return store;
+  }
+
+  double GetZ() const { return HALSIM_GetSPIAccelerometerZ(m_index); }
+
+  void SetZ(double z) { HALSIM_SetSPIAccelerometerZ(m_index, z); }
+
+  void ResetData() { HALSIM_ResetSPIAccelerometerData(m_index); }
+
+ private:
+  int m_index;
+};
+}  // 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
new file mode 100644
index 0000000..6f03952
--- /dev/null
+++ b/hal/src/main/native/include/simulation/SimHooks.h
@@ -0,0 +1,28 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+#ifndef __FRC_ROBORIO__
+
+#include "mockdata/MockHooks.h"
+
+namespace frc {
+namespace sim {
+
+void WaitForProgramStart() { HALSIM_WaitForProgramStart(); }
+
+void SetProgramStarted() { HALSIM_SetProgramStarted(); }
+
+bool GetProgramStarted() { return HALSIM_GetProgramStarted(); }
+
+void RestartTiming() { HALSIM_RestartTiming(); }
+
+}  // namespace sim
+}  // namespace frc
+
+#endif
diff --git a/hal/src/main/native/sim/Accelerometer.cpp b/hal/src/main/native/sim/Accelerometer.cpp
new file mode 100644
index 0000000..1435fd5
--- /dev/null
+++ b/hal/src/main/native/sim/Accelerometer.cpp
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Accelerometer.h"
+
+#include "mockdata/AccelerometerDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAccelerometer() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+void HAL_SetAccelerometerActive(HAL_Bool active) {
+  SimAccelerometerData[0].active = active;
+}
+
+void HAL_SetAccelerometerRange(HAL_AccelerometerRange range) {
+  SimAccelerometerData[0].range = range;
+}
+double HAL_GetAccelerometerX(void) { return SimAccelerometerData[0].x; }
+double HAL_GetAccelerometerY(void) { return SimAccelerometerData[0].y; }
+double HAL_GetAccelerometerZ(void) { return SimAccelerometerData[0].z; }
+}  // extern "C"
diff --git a/hal/src/main/native/sim/AnalogAccumulator.cpp b/hal/src/main/native/sim/AnalogAccumulator.cpp
new file mode 100644
index 0000000..537aa15
--- /dev/null
+++ b/hal/src/main/native/sim/AnalogAccumulator.cpp
@@ -0,0 +1,112 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogAccumulator.h"
+
+#include "AnalogInternal.h"
+#include "mockdata/AnalogInDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAnalogAccumulator() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_Bool HAL_IsAccumulatorChannel(HAL_AnalogInputHandle analogPortHandle,
+                                  int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  for (int32_t i = 0; i < kNumAccumulators; i++) {
+    if (port->channel == kAccumulatorChannels[i]) return true;
+  }
+  return false;
+}
+void HAL_InitAccumulator(HAL_AnalogInputHandle analogPortHandle,
+                         int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (!HAL_IsAccumulatorChannel(analogPortHandle, status)) {
+    *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
+    return;
+  }
+
+  SimAnalogInData[port->channel].accumulatorInitialized = true;
+}
+void HAL_ResetAccumulator(HAL_AnalogInputHandle analogPortHandle,
+                          int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimAnalogInData[port->channel].accumulatorCenter = 0;
+  SimAnalogInData[port->channel].accumulatorCount = 0;
+  SimAnalogInData[port->channel].accumulatorValue = 0;
+}
+void HAL_SetAccumulatorCenter(HAL_AnalogInputHandle analogPortHandle,
+                              int32_t center, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimAnalogInData[port->channel].accumulatorCenter = center;
+}
+void HAL_SetAccumulatorDeadband(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t deadband, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimAnalogInData[port->channel].accumulatorDeadband = deadband;
+}
+int64_t HAL_GetAccumulatorValue(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimAnalogInData[port->channel].accumulatorValue;
+}
+int64_t HAL_GetAccumulatorCount(HAL_AnalogInputHandle analogPortHandle,
+                                int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimAnalogInData[port->channel].accumulatorCount;
+}
+void HAL_GetAccumulatorOutput(HAL_AnalogInputHandle analogPortHandle,
+                              int64_t* value, int64_t* count, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  *count = SimAnalogInData[port->channel].accumulatorCount;
+  *value = SimAnalogInData[port->channel].accumulatorValue;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/AnalogGyro.cpp b/hal/src/main/native/sim/AnalogGyro.cpp
new file mode 100644
index 0000000..b7d84d9
--- /dev/null
+++ b/hal/src/main/native/sim/AnalogGyro.cpp
@@ -0,0 +1,147 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogGyro.h"
+
+#include <chrono>
+#include <thread>
+
+#include "AnalogInternal.h"
+#include "HALInitializer.h"
+#include "hal/AnalogAccumulator.h"
+#include "hal/AnalogInput.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "mockdata/AnalogGyroDataInternal.h"
+
+namespace {
+struct AnalogGyro {
+  HAL_AnalogInputHandle handle;
+  uint8_t index;
+};
+}  // namespace
+
+using namespace hal;
+
+static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
+                             HAL_HandleEnum::AnalogGyro>* analogGyroHandles;
+
+namespace hal {
+namespace init {
+void InitializeAnalogGyro() {
+  static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
+                               HAL_HandleEnum::AnalogGyro>
+      agH;
+  analogGyroHandles = &agH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  if (!HAL_IsAccumulatorChannel(analogHandle, status)) {
+    if (*status == 0) {
+      *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
+    }
+    return HAL_kInvalidHandle;
+  }
+
+  // handle known to be correct, so no need to type check
+  int16_t channel = getHandleIndex(analogHandle);
+
+  auto handle = analogGyroHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  // Initialize port structure
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {  // would only error on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  gyro->handle = analogHandle;
+  gyro->index = channel;
+
+  SimAnalogGyroData[channel].initialized = true;
+
+  return handle;
+}
+
+void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
+  // No op
+}
+
+void HAL_FreeAnalogGyro(HAL_GyroHandle handle) {
+  auto gyro = analogGyroHandles->Get(handle);
+  analogGyroHandles->Free(handle);
+  if (gyro == nullptr) return;
+  SimAnalogGyroData[gyro->index].initialized = false;
+}
+
+void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
+                                 double voltsPerDegreePerSecond, double offset,
+                                 int32_t center, int32_t* status) {
+  // No op
+}
+
+void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
+                                              double voltsPerDegreePerSecond,
+                                              int32_t* status) {
+  // No op
+}
+
+void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimAnalogGyroData[gyro->index].angle = 0.0;
+}
+
+void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
+  // Just do a reset
+  HAL_ResetAnalogGyro(handle, status);
+}
+
+void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
+                               int32_t* status) {
+  // No op
+}
+
+double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimAnalogGyroData[gyro->index].angle;
+}
+
+double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status) {
+  auto gyro = analogGyroHandles->Get(handle);
+  if (gyro == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimAnalogGyroData[gyro->index].rate;
+}
+
+double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status) {
+  return 0.0;
+}
+
+int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status) {
+  return 0;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/AnalogInput.cpp b/hal/src/main/native/sim/AnalogInput.cpp
new file mode 100644
index 0000000..a0f44a7
--- /dev/null
+++ b/hal/src/main/native/sim/AnalogInput.cpp
@@ -0,0 +1,179 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogInput.h"
+
+#include "AnalogInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/AnalogAccumulator.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/AnalogInDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAnalogInput() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle,
+                                                    int32_t* status) {
+  hal::init::CheckInit();
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  HAL_AnalogInputHandle handle = analogInputHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  // Initialize port structure
+  auto analog_port = analogInputHandles->Get(handle);
+  if (analog_port == nullptr) {  // would only error on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  analog_port->channel = static_cast<uint8_t>(channel);
+  if (HAL_IsAccumulatorChannel(handle, status)) {
+    analog_port->isAccumulator = true;
+  } else {
+    analog_port->isAccumulator = false;
+  }
+
+  SimAnalogInData[channel].initialized = true;
+  SimAnalogInData[channel].accumulatorInitialized = false;
+
+  return handle;
+}
+void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  // no status, so no need to check for a proper free.
+  analogInputHandles->Free(analogPortHandle);
+  if (port == nullptr) return;
+  SimAnalogInData[port->channel].initialized = false;
+  SimAnalogInData[port->channel].accumulatorInitialized = false;
+}
+
+HAL_Bool HAL_CheckAnalogModule(int32_t module) { return module == 1; }
+
+HAL_Bool HAL_CheckAnalogInputChannel(int32_t channel) {
+  return channel < kNumAnalogInputs && channel >= 0;
+}
+
+void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status) {
+  // No op
+}
+double HAL_GetAnalogSampleRate(int32_t* status) { return kDefaultSampleRate; }
+void HAL_SetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
+                              int32_t bits, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimAnalogInData[port->channel].averageBits = bits;
+}
+int32_t HAL_GetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
+                                 int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimAnalogInData[port->channel].averageBits;
+}
+void HAL_SetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
+                                 int32_t bits, int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimAnalogInData[port->channel].oversampleBits = bits;
+}
+int32_t HAL_GetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
+                                    int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimAnalogInData[port->channel].oversampleBits;
+}
+int32_t HAL_GetAnalogValue(HAL_AnalogInputHandle analogPortHandle,
+                           int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  double voltage = SimAnalogInData[port->channel].voltage;
+  return HAL_GetAnalogVoltsToValue(analogPortHandle, voltage, status);
+}
+int32_t HAL_GetAnalogAverageValue(HAL_AnalogInputHandle analogPortHandle,
+                                  int32_t* status) {
+  // No averaging supported
+  return HAL_GetAnalogValue(analogPortHandle, status);
+}
+int32_t HAL_GetAnalogVoltsToValue(HAL_AnalogInputHandle analogPortHandle,
+                                  double voltage, int32_t* status) {
+  if (voltage > 5.0) {
+    voltage = 5.0;
+    *status = VOLTAGE_OUT_OF_RANGE;
+  }
+  if (voltage < 0.0) {
+    voltage = 0.0;
+    *status = VOLTAGE_OUT_OF_RANGE;
+  }
+  int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogPortHandle, status);
+  int32_t offset = HAL_GetAnalogOffset(analogPortHandle, status);
+  int32_t value =
+      static_cast<int32_t>((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9));
+  return value;
+}
+double HAL_GetAnalogVoltage(HAL_AnalogInputHandle analogPortHandle,
+                            int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+
+  return SimAnalogInData[port->channel].voltage;
+}
+double HAL_GetAnalogAverageVoltage(HAL_AnalogInputHandle analogPortHandle,
+                                   int32_t* status) {
+  auto port = analogInputHandles->Get(analogPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+
+  // No averaging supported
+  return SimAnalogInData[port->channel].voltage;
+}
+int32_t HAL_GetAnalogLSBWeight(HAL_AnalogInputHandle analogPortHandle,
+                               int32_t* status) {
+  return 1220703;
+}
+int32_t HAL_GetAnalogOffset(HAL_AnalogInputHandle analogPortHandle,
+                            int32_t* status) {
+  return 0;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/AnalogInternal.cpp b/hal/src/main/native/sim/AnalogInternal.cpp
new file mode 100644
index 0000000..1e6a755
--- /dev/null
+++ b/hal/src/main/native/sim/AnalogInternal.cpp
@@ -0,0 +1,27 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "AnalogInternal.h"
+
+#include "PortsInternal.h"
+#include "hal/AnalogInput.h"
+
+namespace hal {
+IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort, kNumAnalogInputs,
+                      HAL_HandleEnum::AnalogInput>* analogInputHandles;
+}  // namespace hal
+
+namespace hal {
+namespace init {
+void InitializeAnalogInternal() {
+  static IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
+                               kNumAnalogInputs, HAL_HandleEnum::AnalogInput>
+      aiH;
+  analogInputHandles = &aiH;
+}
+}  // namespace init
+}  // namespace hal
diff --git a/hal/src/main/native/sim/AnalogInternal.h b/hal/src/main/native/sim/AnalogInternal.h
new file mode 100644
index 0000000..bcc5c95
--- /dev/null
+++ b/hal/src/main/native/sim/AnalogInternal.h
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <memory>
+
+#include "PortsInternal.h"
+#include "hal/Ports.h"
+#include "hal/handles/IndexedHandleResource.h"
+
+namespace hal {
+constexpr int32_t kTimebase = 40000000;  ///< 40 MHz clock
+constexpr int32_t kDefaultOversampleBits = 0;
+constexpr int32_t kDefaultAverageBits = 7;
+constexpr double kDefaultSampleRate = 50000.0;
+static constexpr uint32_t kAccumulatorChannels[] = {0, 1};
+
+struct AnalogPort {
+  uint8_t channel;
+  bool isAccumulator;
+};
+
+extern IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
+                             kNumAnalogInputs, HAL_HandleEnum::AnalogInput>*
+    analogInputHandles;
+
+int32_t GetAnalogTriggerInputIndex(HAL_AnalogTriggerHandle handle,
+                                   int32_t* status);
+}  // namespace hal
diff --git a/hal/src/main/native/sim/AnalogOutput.cpp b/hal/src/main/native/sim/AnalogOutput.cpp
new file mode 100644
index 0000000..2e3a348
--- /dev/null
+++ b/hal/src/main/native/sim/AnalogOutput.cpp
@@ -0,0 +1,102 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogOutput.h"
+
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "mockdata/AnalogOutDataInternal.h"
+
+using namespace hal;
+
+namespace {
+struct AnalogOutput {
+  uint8_t channel;
+};
+}  // namespace
+
+static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
+                             kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>*
+    analogOutputHandles;
+
+namespace hal {
+namespace init {
+void InitializeAnalogOutput() {
+  static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
+                               kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>
+      aoH;
+  analogOutputHandles = &aoH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle,
+                                                      int32_t* status) {
+  hal::init::CheckInit();
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  HAL_AnalogOutputHandle handle =
+      analogOutputHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = analogOutputHandles->Get(handle);
+  if (port == nullptr) {  // would only error on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  port->channel = static_cast<uint8_t>(channel);
+
+  // Initialize sim analog input
+  SimAnalogOutData[channel].initialized = true;
+  return handle;
+}
+
+void HAL_FreeAnalogOutputPort(HAL_AnalogOutputHandle analogOutputHandle) {
+  // no status, so no need to check for a proper free.
+  auto port = analogOutputHandles->Get(analogOutputHandle);
+  if (port == nullptr) return;
+  analogOutputHandles->Free(analogOutputHandle);
+  SimAnalogOutData[port->channel].initialized = false;
+}
+
+HAL_Bool HAL_CheckAnalogOutputChannel(int32_t channel) {
+  return channel < kNumAnalogOutputs && channel >= 0;
+}
+
+void HAL_SetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
+                         double voltage, int32_t* status) {
+  auto port = analogOutputHandles->Get(analogOutputHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimAnalogOutData[port->channel].voltage = voltage;
+}
+
+double HAL_GetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
+                           int32_t* status) {
+  auto port = analogOutputHandles->Get(analogOutputHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+
+  return SimAnalogOutData[port->channel].voltage;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/AnalogTrigger.cpp b/hal/src/main/native/sim/AnalogTrigger.cpp
new file mode 100644
index 0000000..53b165c
--- /dev/null
+++ b/hal/src/main/native/sim/AnalogTrigger.cpp
@@ -0,0 +1,261 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/AnalogTrigger.h"
+
+#include "AnalogInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/AnalogInput.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+#include "mockdata/AnalogInDataInternal.h"
+#include "mockdata/AnalogTriggerDataInternal.h"
+
+namespace {
+struct AnalogTrigger {
+  HAL_AnalogInputHandle analogHandle;
+  uint8_t index;
+  HAL_Bool trigState;
+};
+}  // namespace
+
+using namespace hal;
+
+static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
+                             kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>*
+    analogTriggerHandles;
+
+namespace hal {
+namespace init {
+void InitializeAnalogTrigger() {
+  static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
+                               kNumAnalogTriggers,
+                               HAL_HandleEnum::AnalogTrigger>
+      atH;
+  analogTriggerHandles = &atH;
+}
+}  // namespace init
+}  // namespace hal
+
+int32_t hal::GetAnalogTriggerInputIndex(HAL_AnalogTriggerHandle handle,
+                                        int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(handle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
+  }
+
+  auto analog_port = analogInputHandles->Get(trigger->analogHandle);
+  if (analog_port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
+  }
+
+  return analog_port->channel;
+}
+
+extern "C" {
+
+HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
+    HAL_AnalogInputHandle portHandle, int32_t* index, int32_t* status) {
+  hal::init::CheckInit();
+  // ensure we are given a valid and active AnalogInput handle
+  auto analog_port = analogInputHandles->Get(portHandle);
+  if (analog_port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  HAL_AnalogTriggerHandle handle = analogTriggerHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto trigger = analogTriggerHandles->Get(handle);
+  if (trigger == nullptr) {  // would only occur on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  trigger->analogHandle = portHandle;
+  trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
+  *index = trigger->index;
+
+  SimAnalogTriggerData[trigger->index].initialized = true;
+
+  trigger->trigState = false;
+
+  return handle;
+}
+
+void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
+                            int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  analogTriggerHandles->Free(analogTriggerHandle);
+  if (trigger == nullptr) return;
+  SimAnalogTriggerData[trigger->index].initialized = false;
+  // caller owns the analog input handle.
+}
+
+static double GetAnalogValueToVoltage(
+    HAL_AnalogTriggerHandle analogTriggerHandle, int32_t value,
+    int32_t* status) {
+  int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogTriggerHandle, status);
+  int32_t offset = HAL_GetAnalogOffset(analogTriggerHandle, status);
+
+  double voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
+  return voltage;
+}
+
+void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                   int32_t lower, int32_t upper,
+                                   int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (lower > upper) {
+    *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
+  }
+
+  double trigLower =
+      GetAnalogValueToVoltage(trigger->analogHandle, lower, status);
+  if (status != 0) return;
+  double trigUpper =
+      GetAnalogValueToVoltage(trigger->analogHandle, upper, status);
+  if (status != 0) return;
+
+  SimAnalogTriggerData[trigger->index].triggerUpperBound = trigUpper;
+  SimAnalogTriggerData[trigger->index].triggerLowerBound = trigLower;
+}
+void HAL_SetAnalogTriggerLimitsVoltage(
+    HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
+    int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (lower > upper) {
+    *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
+  }
+
+  SimAnalogTriggerData[trigger->index].triggerUpperBound = upper;
+  SimAnalogTriggerData[trigger->index].triggerLowerBound = lower;
+}
+void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                  HAL_Bool useAveragedValue, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
+
+  if (triggerData->triggerMode.Get() == HALSIM_AnalogTriggerFiltered) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  auto setVal = useAveragedValue ? HALSIM_AnalogTriggerAveraged
+                                 : HALSIM_AnalogTriggerUnassigned;
+  triggerData->triggerMode = setVal;
+}
+void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                  HAL_Bool useFilteredValue, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
+
+  if (triggerData->triggerMode.Get() == HALSIM_AnalogTriggerAveraged) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  auto setVal = useFilteredValue ? HALSIM_AnalogTriggerAveraged
+                                 : HALSIM_AnalogTriggerUnassigned;
+  triggerData->triggerMode = setVal;
+}
+
+static double GetTriggerValue(AnalogTrigger* trigger, int32_t* status) {
+  auto analogIn = analogInputHandles->Get(trigger->analogHandle);
+  if (analogIn == nullptr) {
+    // Returning HAL Handle Error, but going to ignore lower down
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+
+  return SimAnalogInData[analogIn->channel].voltage;
+}
+
+HAL_Bool HAL_GetAnalogTriggerInWindow(
+    HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  double voltage = GetTriggerValue(trigger.get(), status);
+  if (*status == HAL_HANDLE_ERROR) {
+    // Don't error if analog has been destroyed
+    *status = 0;
+    return false;
+  }
+
+  double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
+  double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
+
+  return voltage >= trigLower && voltage <= trigUpper;
+}
+HAL_Bool HAL_GetAnalogTriggerTriggerState(
+    HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
+  auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
+  if (trigger == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  double voltage = GetTriggerValue(trigger.get(), status);
+  if (*status == HAL_HANDLE_ERROR) {
+    // Don't error if analog has been destroyed
+    *status = 0;
+    return false;
+  }
+
+  double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
+  double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
+
+  if (voltage < trigLower) {
+    trigger->trigState = false;
+    return false;
+  }
+  if (voltage > trigUpper) {
+    trigger->trigState = true;
+    return true;
+  }
+  return trigger->trigState;
+}
+HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
+                                    HAL_AnalogTriggerType type,
+                                    int32_t* status) {
+  if (type == HAL_Trigger_kInWindow) {
+    return HAL_GetAnalogTriggerInWindow(analogTriggerHandle, status);
+  } else if (type == HAL_Trigger_kState) {
+    return HAL_GetAnalogTriggerTriggerState(analogTriggerHandle, status);
+  } else {
+    *status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
+    return false;
+  }
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/CAN.cpp b/hal/src/main/native/sim/CAN.cpp
new file mode 100644
index 0000000..d55eafd
--- /dev/null
+++ b/hal/src/main/native/sim/CAN.cpp
@@ -0,0 +1,55 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/CAN.h"
+
+#include "mockdata/CanDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeCAN() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
+                         uint8_t dataSize, int32_t periodMs, int32_t* status) {
+  SimCanData->sendMessage(messageID, data, dataSize, periodMs, status);
+}
+void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
+                            uint8_t* data, uint8_t* dataSize,
+                            uint32_t* timeStamp, int32_t* status) {
+  SimCanData->receiveMessage(messageID, messageIDMask, data, dataSize,
+                             timeStamp, status);
+}
+void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
+                               uint32_t messageIDMask, uint32_t maxMessages,
+                               int32_t* status) {
+  SimCanData->openStreamSession(sessionHandle, messageID, messageIDMask,
+                                maxMessages, status);
+}
+void HAL_CAN_CloseStreamSession(uint32_t sessionHandle) {
+  SimCanData->closeStreamSession(sessionHandle);
+}
+void HAL_CAN_ReadStreamSession(uint32_t sessionHandle,
+                               struct HAL_CANStreamMessage* messages,
+                               uint32_t messagesToRead, uint32_t* messagesRead,
+                               int32_t* status) {
+  SimCanData->readStreamSession(sessionHandle, messages, messagesToRead,
+                                messagesRead, status);
+}
+void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
+                          uint32_t* txFullCount, uint32_t* receiveErrorCount,
+                          uint32_t* transmitErrorCount, int32_t* status) {
+  SimCanData->getCANStatus(percentBusUtilization, busOffCount, txFullCount,
+                           receiveErrorCount, transmitErrorCount, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/CANAPI.cpp b/hal/src/main/native/sim/CANAPI.cpp
new file mode 100644
index 0000000..a54f06f
--- /dev/null
+++ b/hal/src/main/native/sim/CANAPI.cpp
@@ -0,0 +1,335 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/CANAPI.h"
+
+#include <atomic>
+#include <ctime>
+
+#include <wpi/DenseMap.h>
+
+#include "CANAPIInternal.h"
+#include "HALInitializer.h"
+#include "hal/CAN.h"
+#include "hal/Errors.h"
+#include "hal/HAL.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+struct Receives {
+  uint64_t lastTimeStamp;
+  uint8_t data[8];
+  uint8_t length;
+};
+
+struct CANStorage {
+  HAL_CANManufacturer manufacturer;
+  HAL_CANDeviceType deviceType;
+  uint8_t deviceId;
+  wpi::mutex mapMutex;
+  wpi::SmallDenseMap<int32_t, int32_t> periodicSends;
+  wpi::SmallDenseMap<int32_t, Receives> receives;
+};
+}  // namespace
+
+static UnlimitedHandleResource<HAL_CANHandle, CANStorage, HAL_HandleEnum::CAN>*
+    canHandles;
+
+static uint32_t GetPacketBaseTime() {
+  int status = 0;
+  auto basetime = HAL_GetFPGATime(&status);
+  // us to ms
+  return (basetime / 1000ull) & 0xFFFFFFFF;
+}
+
+namespace hal {
+namespace init {
+void InitializeCANAPI() {
+  static UnlimitedHandleResource<HAL_CANHandle, CANStorage, HAL_HandleEnum::CAN>
+      cH;
+  canHandles = &cH;
+}
+}  // namespace init
+namespace can {
+int32_t GetCANModuleFromHandle(HAL_CANHandle handle, int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
+  }
+  return can->deviceId;
+}
+}  // namespace can
+}  // namespace hal
+
+static int32_t CreateCANId(CANStorage* storage, int32_t apiId) {
+  int32_t createdId = 0;
+  createdId |= (static_cast<int32_t>(storage->deviceType) & 0x1F) << 24;
+  createdId |= (static_cast<int32_t>(storage->manufacturer) & 0xFF) << 16;
+  createdId |= (apiId & 0x3FF) << 6;
+  createdId |= (storage->deviceId & 0x3F);
+  return createdId;
+}
+
+HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
+                                int32_t deviceId, HAL_CANDeviceType deviceType,
+                                int32_t* status) {
+  hal::init::CheckInit();
+  auto can = std::make_shared<CANStorage>();
+
+  auto handle = canHandles->Allocate(can);
+
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+
+  can->deviceId = deviceId;
+  can->deviceType = deviceType;
+  can->manufacturer = manufacturer;
+
+  return handle;
+}
+
+void HAL_CleanCAN(HAL_CANHandle handle) {
+  auto data = canHandles->Free(handle);
+
+  std::lock_guard<wpi::mutex> 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);
+    i.second = -1;
+  }
+}
+
+void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
+                        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);
+
+  HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  can->periodicSends[apiId] = -1;
+}
+
+void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
+                                 int32_t length, int32_t apiId,
+                                 int32_t repeatMs, int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  auto id = CreateCANId(can.get(), apiId);
+
+  HAL_CAN_SendMessage(id, data, length, repeatMs, status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  can->periodicSends[apiId] = repeatMs;
+}
+
+void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
+                                int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  auto id = CreateCANId(can.get(), apiId);
+
+  HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING,
+                      status);
+
+  if (*status != 0) {
+    return;
+  }
+  std::lock_guard<wpi::mutex> lock(can->mapMutex);
+  can->periodicSends[apiId] = -1;
+}
+
+void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
+                          int32_t* length, uint64_t* receivedTimestamp,
+                          int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint32_t messageId = CreateCANId(can.get(), apiId);
+  uint8_t dataSize = 0;
+  uint32_t ts = 0;
+  HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
+
+  if (*status == 0) {
+    std::lock_guard<wpi::mutex> lock(can->mapMutex);
+    auto& msg = can->receives[messageId];
+    msg.length = dataSize;
+    msg.lastTimeStamp = ts;
+    // The NetComm call placed in data, copy into the msg
+    std::memcpy(msg.data, data, dataSize);
+  }
+  *length = dataSize;
+  *receivedTimestamp = ts;
+}
+
+void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
+                             int32_t* length, uint64_t* receivedTimestamp,
+                             int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint32_t messageId = CreateCANId(can.get(), apiId);
+  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()) {
+      // 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;
+    }
+  }
+}
+
+void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
+                              uint8_t* data, int32_t* length,
+                              uint64_t* receivedTimestamp, int32_t timeoutMs,
+                              int32_t* status) {
+  auto can = canHandles->Get(handle);
+  if (!can) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint32_t messageId = CreateCANId(can.get(), apiId);
+  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;
+    }
+  }
+}
+
+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)) {
+        *status = 0;
+        // 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;
+        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;
+    }
+  }
+}
diff --git a/hal/src/main/native/sim/CANAPIInternal.h b/hal/src/main/native/sim/CANAPIInternal.h
new file mode 100644
index 0000000..074f682
--- /dev/null
+++ b/hal/src/main/native/sim/CANAPIInternal.h
@@ -0,0 +1,16 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "hal/Types.h"
+
+namespace hal {
+namespace can {
+int32_t GetCANModuleFromHandle(HAL_CANHandle handle, int32_t* status);
+}  // namespace can
+}  // namespace hal
diff --git a/hal/src/main/native/sim/CallbackStore.cpp b/hal/src/main/native/sim/CallbackStore.cpp
new file mode 100644
index 0000000..d278b93
--- /dev/null
+++ b/hal/src/main/native/sim/CallbackStore.cpp
@@ -0,0 +1,13 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "simulation/CallbackStore.h"
+
+void frc::sim::CallbackStoreThunk(const char* name, void* param,
+                                  const HAL_Value* value) {
+  reinterpret_cast<CallbackStore*>(param)->callback(name, value);
+}
diff --git a/hal/src/main/native/sim/Compressor.cpp b/hal/src/main/native/sim/Compressor.cpp
new file mode 100644
index 0000000..b5c5867
--- /dev/null
+++ b/hal/src/main/native/sim/Compressor.cpp
@@ -0,0 +1,123 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Compressor.h"
+
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/PCMDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeCompressor() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_CompressorHandle HAL_InitializeCompressor(int32_t module, int32_t* status) {
+  hal::init::CheckInit();
+  // As compressors can have unlimited objects, just create a
+  // handle with the module number as the index.
+
+  SimPCMData[module].compressorInitialized = true;
+  return (HAL_CompressorHandle)createHandle(static_cast<int16_t>(module),
+                                            HAL_HandleEnum::Compressor, 0);
+}
+
+HAL_Bool HAL_CheckCompressorModule(int32_t module) {
+  return module < kNumPCMModules && module >= 0;
+}
+
+HAL_Bool HAL_GetCompressor(HAL_CompressorHandle compressorHandle,
+                           int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimPCMData[index].compressorOn;
+}
+
+void HAL_SetCompressorClosedLoopControl(HAL_CompressorHandle compressorHandle,
+                                        HAL_Bool value, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimPCMData[index].closedLoopEnabled = value;
+}
+
+HAL_Bool HAL_GetCompressorClosedLoopControl(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimPCMData[index].closedLoopEnabled;
+}
+
+HAL_Bool HAL_GetCompressorPressureSwitch(HAL_CompressorHandle compressorHandle,
+                                         int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimPCMData[index].pressureSwitch;
+}
+
+double HAL_GetCompressorCurrent(HAL_CompressorHandle compressorHandle,
+                                int32_t* status) {
+  int16_t index =
+      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
+  if (index == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimPCMData[index].compressorCurrent;
+}
+HAL_Bool HAL_GetCompressorCurrentTooHighFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  return false;
+}
+HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  return false;
+}
+HAL_Bool HAL_GetCompressorShortedStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  return false;
+}
+HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
+                                       int32_t* status) {
+  return false;
+}
+HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  return false;
+}
+HAL_Bool HAL_GetCompressorNotConnectedFault(
+    HAL_CompressorHandle compressorHandle, int32_t* status) {
+  return false;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/Constants.cpp b/hal/src/main/native/sim/Constants.cpp
new file mode 100644
index 0000000..64cb52b
--- /dev/null
+++ b/hal/src/main/native/sim/Constants.cpp
@@ -0,0 +1,24 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Constants.h"
+
+#include "ConstantsInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeConstants() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+int32_t HAL_GetSystemClockTicksPerMicrosecond(void) {
+  return kSystemClockTicksPerMicrosecond;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/ConstantsInternal.h b/hal/src/main/native/sim/ConstantsInternal.h
new file mode 100644
index 0000000..c3a6e8f
--- /dev/null
+++ b/hal/src/main/native/sim/ConstantsInternal.h
@@ -0,0 +1,14 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+namespace hal {
+constexpr int32_t kSystemClockTicksPerMicrosecond = 40;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/Counter.cpp b/hal/src/main/native/sim/Counter.cpp
new file mode 100644
index 0000000..37454d0
--- /dev/null
+++ b/hal/src/main/native/sim/Counter.cpp
@@ -0,0 +1,98 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Counter.h"
+
+#include "CounterInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+namespace hal {
+
+LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
+                      HAL_HandleEnum::Counter>* counterHandles;
+}  // namespace hal
+
+namespace hal {
+namespace init {
+void InitializeCounter() {
+  static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
+                               HAL_HandleEnum::Counter>
+      cH;
+  counterHandles = &cH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  return 0;
+}
+void HAL_FreeCounter(HAL_CounterHandle counterHandle, int32_t* status) {}
+void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
+                               int32_t* status) {}
+void HAL_SetCounterUpSource(HAL_CounterHandle counterHandle,
+                            HAL_Handle digitalSourceHandle,
+                            HAL_AnalogTriggerType analogTriggerType,
+                            int32_t* status) {}
+void HAL_SetCounterUpSourceEdge(HAL_CounterHandle counterHandle,
+                                HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                int32_t* status) {}
+void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle,
+                              int32_t* status) {}
+void HAL_SetCounterDownSource(HAL_CounterHandle counterHandle,
+                              HAL_Handle digitalSourceHandle,
+                              HAL_AnalogTriggerType analogTriggerType,
+                              int32_t* status) {}
+void HAL_SetCounterDownSourceEdge(HAL_CounterHandle counterHandle,
+                                  HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                  int32_t* status) {}
+void HAL_ClearCounterDownSource(HAL_CounterHandle counterHandle,
+                                int32_t* status) {}
+void HAL_SetCounterUpDownMode(HAL_CounterHandle counterHandle,
+                              int32_t* status) {}
+void HAL_SetCounterExternalDirectionMode(HAL_CounterHandle counterHandle,
+                                         int32_t* status) {}
+void HAL_SetCounterSemiPeriodMode(HAL_CounterHandle counterHandle,
+                                  HAL_Bool highSemiPeriod, int32_t* status) {}
+void HAL_SetCounterPulseLengthMode(HAL_CounterHandle counterHandle,
+                                   double threshold, int32_t* status) {}
+int32_t HAL_GetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
+                                       int32_t* status) {
+  return 0;
+}
+void HAL_SetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
+                                    int32_t samplesToAverage, int32_t* status) {
+}
+void HAL_ResetCounter(HAL_CounterHandle counterHandle, int32_t* status) {}
+int32_t HAL_GetCounter(HAL_CounterHandle counterHandle, int32_t* status) {
+  return 0;
+}
+double HAL_GetCounterPeriod(HAL_CounterHandle counterHandle, int32_t* status) {
+  return 0.0;
+}
+void HAL_SetCounterMaxPeriod(HAL_CounterHandle counterHandle, double maxPeriod,
+                             int32_t* status) {}
+void HAL_SetCounterUpdateWhenEmpty(HAL_CounterHandle counterHandle,
+                                   HAL_Bool enabled, int32_t* status) {}
+HAL_Bool HAL_GetCounterStopped(HAL_CounterHandle counterHandle,
+                               int32_t* status) {
+  return false;
+}
+HAL_Bool HAL_GetCounterDirection(HAL_CounterHandle counterHandle,
+                                 int32_t* status) {
+  return false;
+}
+void HAL_SetCounterReverseDirection(HAL_CounterHandle counterHandle,
+                                    HAL_Bool reverseDirection,
+                                    int32_t* status) {}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/CounterInternal.h b/hal/src/main/native/sim/CounterInternal.h
new file mode 100644
index 0000000..70fbe54
--- /dev/null
+++ b/hal/src/main/native/sim/CounterInternal.h
@@ -0,0 +1,23 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "PortsInternal.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+namespace hal {
+
+struct Counter {
+  uint8_t index;
+};
+
+extern LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
+                             HAL_HandleEnum::Counter>* counterHandles;
+
+}  // namespace hal
diff --git a/hal/src/main/native/sim/DIO.cpp b/hal/src/main/native/sim/DIO.cpp
new file mode 100644
index 0000000..e67b756
--- /dev/null
+++ b/hal/src/main/native/sim/DIO.cpp
@@ -0,0 +1,247 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/DIO.h"
+
+#include <cmath>
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+#include "mockdata/DIODataInternal.h"
+#include "mockdata/DigitalPWMDataInternal.h"
+
+using namespace hal;
+
+static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
+                             kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
+    digitalPWMHandles;
+
+namespace hal {
+namespace init {
+void InitializeDIO() {
+  static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
+                               kNumDigitalPWMOutputs,
+                               HAL_HandleEnum::DigitalPWM>
+      dpH;
+  digitalPWMHandles = &dpH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
+                                        HAL_Bool input, int32_t* status) {
+  hal::init::CheckInit();
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  auto handle =
+      digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  port->channel = static_cast<uint8_t>(channel);
+
+  SimDIOData[channel].initialized = true;
+
+  SimDIOData[channel].isInput = input;
+
+  return handle;
+}
+
+HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
+  return channel < kNumDigitalChannels && channel >= 0;
+}
+
+void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  // 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;
+}
+
+HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
+  auto handle = digitalPWMHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+
+  auto id = digitalPWMHandles->Get(handle);
+  if (id == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  *id = static_cast<uint8_t>(getHandleIndex(handle));
+
+  SimDigitalPWMData[*id].initialized = true;
+
+  return handle;
+}
+
+void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
+  auto port = digitalPWMHandles->Get(pwmGenerator);
+  digitalPWMHandles->Free(pwmGenerator);
+  if (port == nullptr) return;
+  int32_t id = *port;
+  SimDigitalPWMData[id].initialized = false;
+}
+
+void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
+  // Currently rounding in the log rate domain... heavy weight toward picking a
+  // higher freq.
+  // TODO: Round in the linear rate domain.
+  // uint8_t pwmPeriodPower = static_cast<uint8_t>(
+  //    std::log(1.0 / (kExpectedLoopTiming * 0.25E-6 * rate)) /
+  //        std::log(2.0) +
+  //    0.5);
+  // TODO(THAD) : Add a case to set this in the simulator
+  // digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
+}
+
+void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
+                                double dutyCycle, int32_t* status) {
+  auto port = digitalPWMHandles->Get(pwmGenerator);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  int32_t id = *port;
+  if (dutyCycle > 1.0) dutyCycle = 1.0;
+  if (dutyCycle < 0.0) dutyCycle = 0.0;
+  SimDigitalPWMData[id].dutyCycle = dutyCycle;
+}
+
+void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
+                                    int32_t channel, int32_t* status) {
+  auto port = digitalPWMHandles->Get(pwmGenerator);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  int32_t id = *port;
+  SimDigitalPWMData[id].pin = channel;
+}
+
+void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
+                int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (value != 0 && value != 1) {
+    if (value != 0) value = 1;
+  }
+  SimDIOData[port->channel].value = value;
+}
+
+void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimDIOData[port->channel].isInput = input;
+}
+
+HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  HAL_Bool value = SimDIOData[port->channel].value;
+  if (value > 1) value = 1;
+  if (value < 0) value = 0;
+  return value;
+}
+
+HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  HAL_Bool value = SimDIOData[port->channel].isInput;
+  if (value > 1) value = 1;
+  if (value < 0) value = 0;
+  return value;
+}
+
+void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
+               int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  // TODO (Thad) Add this
+}
+
+HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return false;
+  // TODO (Thad) Add this
+}
+
+HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
+  return false;  // TODO(Thad) Figure this out
+}
+
+void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // TODO(Thad) Figure this out
+}
+
+int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  return 0;
+  // TODO(Thad) Figure this out
+}
+
+void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
+  // TODO(Thad) figure this out
+}
+
+int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
+  return 0;  // TODO(Thad) figure this out
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/DigitalInternal.cpp b/hal/src/main/native/sim/DigitalInternal.cpp
new file mode 100644
index 0000000..070754a
--- /dev/null
+++ b/hal/src/main/native/sim/DigitalInternal.cpp
@@ -0,0 +1,77 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "DigitalInternal.h"
+
+#include "ConstantsInternal.h"
+#include "PortsInternal.h"
+#include "hal/AnalogTrigger.h"
+#include "hal/HAL.h"
+#include "hal/Ports.h"
+
+namespace hal {
+
+DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
+                      kNumDigitalChannels + kNumPWMHeaders>*
+    digitalChannelHandles;
+
+namespace init {
+void InitializeDigitalInternal() {
+  static DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
+                               kNumDigitalChannels + kNumPWMHeaders>
+      dcH;
+  digitalChannelHandles = &dcH;
+}
+}  // namespace init
+
+bool remapDigitalSource(HAL_Handle digitalSourceHandle,
+                        HAL_AnalogTriggerType analogTriggerType,
+                        uint8_t& channel, uint8_t& module,
+                        bool& analogTrigger) {
+  if (isHandleType(digitalSourceHandle, HAL_HandleEnum::AnalogTrigger)) {
+    // If handle passed, index is not negative
+    int32_t index = getHandleIndex(digitalSourceHandle);
+    channel = (index << 2) + analogTriggerType;
+    module = channel >> 4;
+    analogTrigger = true;
+    return true;
+  } else if (isHandleType(digitalSourceHandle, HAL_HandleEnum::DIO)) {
+    int32_t index = getHandleIndex(digitalSourceHandle);
+    if (index >= kNumDigitalHeaders) {
+      channel = remapMXPChannel(index);
+      module = 1;
+    } else {
+      channel = index;
+      module = 0;
+    }
+    analogTrigger = false;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+int32_t remapMXPChannel(int32_t channel) { return channel - 10; }
+
+int32_t remapMXPPWMChannel(int32_t channel) {
+  if (channel < 14) {
+    return channel - 10;  // first block of 4 pwms (MXP 0-3)
+  } else {
+    return channel - 6;  // block of PWMs after SPI
+  }
+}
+
+int32_t GetDigitalInputChannel(HAL_DigitalHandle handle, int32_t* status) {
+  auto digital = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
+  if (digital == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return -1;
+  }
+
+  return digital->channel;
+}
+}  // namespace hal
diff --git a/hal/src/main/native/sim/DigitalInternal.h b/hal/src/main/native/sim/DigitalInternal.h
new file mode 100644
index 0000000..89644a1
--- /dev/null
+++ b/hal/src/main/native/sim/DigitalInternal.h
@@ -0,0 +1,93 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include <memory>
+
+#include "PortsInternal.h"
+#include "hal/AnalogTrigger.h"
+#include "hal/Ports.h"
+#include "hal/Types.h"
+#include "hal/handles/DigitalHandleResource.h"
+#include "hal/handles/HandlesInternal.h"
+
+namespace hal {
+/**
+ * MXP channels when used as digital output PWM are offset from actual value
+ */
+constexpr int32_t kMXPDigitalPWMOffset = 6;
+
+constexpr int32_t kExpectedLoopTiming = 40;
+
+/**
+ * kDefaultPwmPeriod is in ms
+ *
+ * - 20ms periods (50 Hz) are the "safest" setting in that this works for all
+ *   devices
+ * - 20ms periods seem to be desirable for Vex Motors
+ * - 20ms periods are the specified period for HS-322HD servos, but work
+ *   reliably down to 10.0 ms; starting at about 8.5ms, the servo sometimes hums
+ *   and get hot; by 5.0ms the hum is nearly continuous
+ * - 10ms periods work well for Victor 884
+ * - 5ms periods allows higher update rates for Luminary Micro Jaguar speed
+ *   controllers. Due to the shipping firmware on the Jaguar, we can't run the
+ *   update period less than 5.05 ms.
+ *
+ * kDefaultPwmPeriod is the 1x period (5.05 ms).  In hardware, the period
+ * scaling is implemented as an output squelch to get longer periods for old
+ * devices.
+ */
+constexpr float kDefaultPwmPeriod = 5.05;
+/**
+ * kDefaultPwmCenter is the PWM range center in ms
+ */
+constexpr float kDefaultPwmCenter = 1.5;
+/**
+ * kDefaultPWMStepsDown is the number of PWM steps below the centerpoint
+ */
+constexpr int32_t kDefaultPwmStepsDown = 1000;
+constexpr int32_t kPwmDisabled = 0;
+
+struct DigitalPort {
+  uint8_t channel;
+  bool configSet = false;
+  bool eliminateDeadband = false;
+  int32_t maxPwm = 0;
+  int32_t deadbandMaxPwm = 0;
+  int32_t centerPwm = 0;
+  int32_t deadbandMinPwm = 0;
+  int32_t minPwm = 0;
+};
+
+extern DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
+                             kNumDigitalChannels + kNumPWMHeaders>*
+    digitalChannelHandles;
+
+/**
+ * Remap the digital source channel and set the module.
+ *
+ * If it's an analog trigger, determine the module from the high order routing
+ * channel else do normal digital input remapping based on channel number
+ * (MXP).
+ */
+bool remapDigitalSource(HAL_Handle digitalSourceHandle,
+                        HAL_AnalogTriggerType analogTriggerType,
+                        uint8_t& channel, uint8_t& module, bool& analogTrigger);
+
+/**
+ * Map DIO channel numbers from their physical number (10 to 26) to their
+ * position in the bit field.
+ */
+int32_t remapMXPChannel(int32_t channel);
+
+int32_t remapMXPPWMChannel(int32_t channel);
+
+int32_t GetDigitalInputChannel(HAL_DigitalHandle handle, int32_t* status);
+}  // namespace hal
diff --git a/hal/src/main/native/sim/DriverStation.cpp b/hal/src/main/native/sim/DriverStation.cpp
new file mode 100644
index 0000000..0c9c028
--- /dev/null
+++ b/hal/src/main/native/sim/DriverStation.cpp
@@ -0,0 +1,291 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/DriverStation.h"
+
+#ifdef __APPLE__
+#include <pthread.h>
+#endif
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include <wpi/condition_variable.h>
+#include <wpi/mutex.h>
+
+#include "HALInitializer.h"
+#include "mockdata/DriverStationDataInternal.h"
+#include "mockdata/MockHooks.h"
+
+static wpi::mutex msgMutex;
+static wpi::condition_variable* newDSDataAvailableCond;
+static wpi::mutex newDSDataAvailableMutex;
+static int newDSDataAvailableCounter{0};
+static std::atomic_bool isFinalized{false};
+
+namespace hal {
+namespace init {
+void InitializeDriverStation() {
+  static wpi::condition_variable nddaC;
+  newDSDataAvailableCond = &nddaC;
+}
+}  // namespace init
+}  // namespace hal
+
+using namespace hal;
+
+extern "C" {
+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) {
+  // 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);
+  static std::string prevMsg[KEEP_MSGS];
+  static std::chrono::time_point<std::chrono::steady_clock>
+      prevMsgTime[KEEP_MSGS];
+  static bool initialized = false;
+  if (!initialized) {
+    for (int i = 0; i < KEEP_MSGS; i++) {
+      prevMsgTime[i] =
+          std::chrono::steady_clock::now() - std::chrono::seconds(2);
+    }
+    initialized = true;
+  }
+
+  auto curTime = std::chrono::steady_clock::now();
+  int i;
+  for (i = 0; i < KEEP_MSGS; ++i) {
+    if (prevMsg[i] == details) break;
+  }
+  int retval = 0;
+  if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
+    printMsg = true;
+    if (printMsg) {
+      if (location && location[0] != '\0') {
+        std::fprintf(stderr, "%s at %s: ", isError ? "Error" : "Warning",
+                     location);
+      }
+      std::fprintf(stderr, "%s\n", details);
+      if (callStack && callStack[0] != '\0') {
+        std::fprintf(stderr, "%s\n", callStack);
+      }
+    }
+    if (i == KEEP_MSGS) {
+      // replace the oldest one
+      i = 0;
+      auto first = prevMsgTime[0];
+      for (int j = 1; j < KEEP_MSGS; ++j) {
+        if (prevMsgTime[j] < first) {
+          first = prevMsgTime[j];
+          i = j;
+        }
+      }
+      prevMsg[i] = details;
+    }
+    prevMsgTime[i] = curTime;
+  }
+  return retval;
+}
+
+int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
+  controlWord->enabled = SimDriverStationData->enabled;
+  controlWord->autonomous = SimDriverStationData->autonomous;
+  controlWord->test = SimDriverStationData->test;
+  controlWord->eStop = SimDriverStationData->eStop;
+  controlWord->fmsAttached = SimDriverStationData->fmsAttached;
+  controlWord->dsAttached = SimDriverStationData->dsAttached;
+  return 0;
+}
+
+HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
+  *status = 0;
+  return SimDriverStationData->allianceStationId;
+}
+
+int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
+  SimDriverStationData->GetJoystickAxes(joystickNum, axes);
+  return 0;
+}
+
+int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
+  SimDriverStationData->GetJoystickPOVs(joystickNum, povs);
+  return 0;
+}
+
+int32_t HAL_GetJoystickButtons(int32_t joystickNum,
+                               HAL_JoystickButtons* buttons) {
+  SimDriverStationData->GetJoystickButtons(joystickNum, buttons);
+  return 0;
+}
+
+int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
+                                  HAL_JoystickDescriptor* desc) {
+  SimDriverStationData->GetJoystickDescriptor(joystickNum, desc);
+  return 0;
+}
+
+HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
+  HAL_JoystickDescriptor desc;
+  SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
+  return desc.isXbox;
+}
+
+int32_t HAL_GetJoystickType(int32_t joystickNum) {
+  HAL_JoystickDescriptor desc;
+  SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
+  return desc.type;
+}
+
+char* HAL_GetJoystickName(int32_t joystickNum) {
+  HAL_JoystickDescriptor desc;
+  SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
+  size_t len = std::strlen(desc.name);
+  char* name = static_cast<char*>(std::malloc(len + 1));
+  std::memcpy(name, desc.name, len + 1);
+  return name;
+}
+
+void HAL_FreeJoystickName(char* name) { std::free(name); }
+
+int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) { return 0; }
+
+int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
+                               int32_t leftRumble, int32_t rightRumble) {
+  SimDriverStationData->SetJoystickOutputs(joystickNum, outputs, leftRumble,
+                                           rightRumble);
+  return 0;
+}
+
+double HAL_GetMatchTime(int32_t* status) {
+  return SimDriverStationData->matchTime;
+}
+
+int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
+  SimDriverStationData->GetMatchInfo(info);
+  return 0;
+}
+
+void HAL_ObserveUserProgramStarting(void) { HALSIM_SetProgramStarted(); }
+
+void HAL_ObserveUserProgramDisabled(void) {
+  // TODO
+}
+
+void HAL_ObserveUserProgramAutonomous(void) {
+  // TODO
+}
+
+void HAL_ObserveUserProgramTeleop(void) {
+  // TODO
+}
+
+void HAL_ObserveUserProgramTest(void) {
+  // TODO
+}
+
+#ifdef __APPLE__
+static pthread_key_t lastCountKey;
+static pthread_once_t lastCountKeyOnce = PTHREAD_ONCE_INIT;
+
+static void InitLastCountKey(void) {
+  pthread_key_create(&lastCountKey, std::free);
+}
+#endif
+
+HAL_Bool HAL_IsNewControlData(void) {
+#ifdef __APPLE__
+  pthread_once(&lastCountKeyOnce, InitLastCountKey);
+  int* lastCountPtr = static_cast<int*>(pthread_getspecific(lastCountKey));
+  if (!lastCountPtr) {
+    lastCountPtr = static_cast<int*>(std::malloc(sizeof(int)));
+    *lastCountPtr = -1;
+    pthread_setspecific(lastCountKey, lastCountPtr);
+  }
+  int& lastCount = *lastCountPtr;
+#else
+  thread_local int lastCount{-1};
+#endif
+  // There is a rollover error condition here. At Packet# = n * (uintmax), this
+  // will return false when instead it should return true. However, this at a
+  // 20ms rate occurs once every 2.7 years of DS connected runtime, so not
+  // worth the cycles to check.
+  int currentCount = 0;
+  {
+    std::unique_lock<wpi::mutex> lock(newDSDataAvailableMutex);
+    currentCount = newDSDataAvailableCounter;
+  }
+  if (lastCount == currentCount) return false;
+  lastCount = currentCount;
+  return true;
+}
+
+void HAL_WaitForDSData(void) { HAL_WaitForDSDataTimeout(0); }
+
+HAL_Bool HAL_WaitForDSDataTimeout(double timeout) {
+  if (isFinalized.load()) {
+    return false;
+  }
+  auto timeoutTime =
+      std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
+
+  std::unique_lock<wpi::mutex> lock(newDSDataAvailableMutex);
+  int currentCount = newDSDataAvailableCounter;
+  while (newDSDataAvailableCounter == currentCount) {
+    if (timeout > 0) {
+      auto timedOut = newDSDataAvailableCond->wait_until(lock, timeoutTime);
+      if (timedOut == std::cv_status::timeout) {
+        return false;
+      }
+    } else {
+      newDSDataAvailableCond->wait(lock);
+    }
+  }
+  return true;
+}
+
+// Constant number to be used for our occur handle
+constexpr int32_t refNumber = 42;
+
+static int32_t newDataOccur(uint32_t refNum) {
+  // 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);
+  // Nofify all threads
+  newDSDataAvailableCounter++;
+  newDSDataAvailableCond->notify_all();
+  return 0;
+}
+
+void HAL_InitializeDriverStation(void) {
+  hal::init::CheckInit();
+  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;
+
+  SimDriverStationData->ResetData();
+
+  std::atexit([]() {
+    isFinalized.store(true);
+    HAL_ReleaseDSMutex();
+  });
+
+  initialized = true;
+}
+
+void HAL_ReleaseDSMutex(void) { newDataOccur(refNumber); }
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/Encoder.cpp b/hal/src/main/native/sim/Encoder.cpp
new file mode 100644
index 0000000..3f197a2
--- /dev/null
+++ b/hal/src/main/native/sim/Encoder.cpp
@@ -0,0 +1,345 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Encoder.h"
+
+#include "CounterInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/Counter.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+#include "mockdata/EncoderDataInternal.h"
+
+using namespace hal;
+
+namespace {
+struct Encoder {
+  HAL_Handle nativeHandle;
+  HAL_EncoderEncodingType encodingType;
+  double distancePerPulse;
+  uint8_t index;
+};
+struct Empty {};
+}  // namespace
+
+static LimitedHandleResource<HAL_EncoderHandle, Encoder,
+                             kNumEncoders + kNumCounters,
+                             HAL_HandleEnum::Encoder>* encoderHandles;
+
+static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
+                             HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
+
+namespace hal {
+namespace init {
+void InitializeEncoder() {
+  static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
+                               HAL_HandleEnum::FPGAEncoder>
+      feH;
+  fpgaEncoderHandles = &feH;
+  static LimitedHandleResource<HAL_EncoderHandle, Encoder,
+                               kNumEncoders + kNumCounters,
+                               HAL_HandleEnum::Encoder>
+      eH;
+  encoderHandles = &eH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_EncoderHandle HAL_InitializeEncoder(
+    HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
+    HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
+    HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
+    int32_t* status) {
+  hal::init::CheckInit();
+  HAL_Handle nativeHandle = HAL_kInvalidHandle;
+  if (encodingType == HAL_EncoderEncodingType::HAL_Encoder_k4X) {
+    // k4x, allocate encoder
+    nativeHandle = fpgaEncoderHandles->Allocate();
+  } else {
+    // k2x or k1x, allocate counter
+    nativeHandle = counterHandles->Allocate();
+  }
+  if (nativeHandle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto handle = encoderHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto encoder = encoderHandles->Get(handle);
+  if (encoder == nullptr) {  // would only occur on thread issue
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  int16_t index = getHandleIndex(handle);
+  SimEncoderData[index].digitalChannelA = getHandleIndex(digitalSourceHandleA);
+  SimEncoderData[index].initialized = true;
+  SimEncoderData[index].reverseDirection = reverseDirection;
+  // TODO: Add encoding type to Sim data
+  encoder->index = index;
+  encoder->nativeHandle = nativeHandle;
+  encoder->encodingType = encodingType;
+  encoder->distancePerPulse = 1.0;
+  return handle;
+}
+
+void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  encoderHandles->Free(encoderHandle);
+  if (encoder == nullptr) return;
+  if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::FPGAEncoder)) {
+    fpgaEncoderHandles->Free(encoder->nativeHandle);
+  } else if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::Counter)) {
+    counterHandles->Free(encoder->nativeHandle);
+  }
+  SimEncoderData[encoder->index].initialized = false;
+}
+
+static inline int EncodingScaleFactor(Encoder* encoder) {
+  switch (encoder->encodingType) {
+    case HAL_Encoder_k1X:
+      return 1;
+    case HAL_Encoder_k2X:
+      return 2;
+    case HAL_Encoder_k4X:
+      return 4;
+    default:
+      return 0;
+  }
+}
+
+static inline double DecodingScaleFactor(Encoder* encoder) {
+  switch (encoder->encodingType) {
+    case HAL_Encoder_k1X:
+      return 1.0;
+    case HAL_Encoder_k2X:
+      return 0.5;
+    case HAL_Encoder_k4X:
+      return 0.25;
+    default:
+      return 0.0;
+  }
+}
+
+int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimEncoderData[encoder->index].count;
+}
+int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimEncoderData[encoder->index].count /
+         DecodingScaleFactor(encoder.get());
+}
+int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
+                                    int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return EncodingScaleFactor(encoder.get());
+}
+void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimEncoderData[encoder->index].count = 0;
+  SimEncoderData[encoder->index].period = std::numeric_limits<double>::max();
+  SimEncoderData[encoder->index].reset = true;
+}
+double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimEncoderData[encoder->index].period;
+}
+void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
+                             int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimEncoderData[encoder->index].maxPeriod = maxPeriod;
+}
+HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
+                               int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimEncoderData[encoder->index].period >
+         SimEncoderData[encoder->index].maxPeriod;
+}
+HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
+                                 int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimEncoderData[encoder->index].direction;
+}
+double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
+                              int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimEncoderData[encoder->index].count * encoder->distancePerPulse;
+}
+double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return encoder->distancePerPulse / SimEncoderData[encoder->index].period;
+}
+void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
+                           int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (minRate == 0.0) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+
+  SimEncoderData[encoder->index].maxPeriod =
+      encoder->distancePerPulse / minRate;
+}
+void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
+                                    double distancePerPulse, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (distancePerPulse == 0.0) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return;
+  }
+  encoder->distancePerPulse = distancePerPulse;
+  SimEncoderData[encoder->index].distancePerPulse = distancePerPulse;
+}
+void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
+                                    HAL_Bool reverseDirection,
+                                    int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimEncoderData[encoder->index].reverseDirection = reverseDirection;
+}
+void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
+                                    int32_t samplesToAverage, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimEncoderData[encoder->index].samplesToAverage = samplesToAverage;
+}
+int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
+                                       int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimEncoderData[encoder->index].samplesToAverage;
+}
+
+void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
+                               HAL_Handle digitalSourceHandle,
+                               HAL_AnalogTriggerType analogTriggerType,
+                               HAL_EncoderIndexingType type, int32_t* status) {
+  // Not implemented yet
+}
+
+int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
+                                int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return encoder->index;
+}
+
+double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
+                                         int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+
+  return DecodingScaleFactor(encoder.get());
+}
+
+double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
+                                      int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0.0;
+  }
+
+  return encoder->distancePerPulse;
+}
+
+HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
+    HAL_EncoderHandle encoderHandle, int32_t* status) {
+  auto encoder = encoderHandles->Get(encoderHandle);
+  if (encoder == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_Encoder_k4X;  // default to k4x
+  }
+
+  return encoder->encodingType;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/ErrorsInternal.h b/hal/src/main/native/sim/ErrorsInternal.h
new file mode 100644
index 0000000..55372d8
--- /dev/null
+++ b/hal/src/main/native/sim/ErrorsInternal.h
@@ -0,0 +1,448 @@
+/*----------------------------------------------------------------------------*/
+/* 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
+
+typedef enum {
+  CTR_OKAY,       // No Error - Function executed as expected
+  CTR_RxTimeout,  // CAN frame has not been received within specified period of
+                  // time.
+  CTR_TxTimeout,  // Not used.
+  CTR_InvalidParamValue,  // Caller passed an invalid param
+  CTR_UnexpectedArbId,    // Specified CAN Id is invalid.
+  CTR_TxFailed,           // Could not transmit the CAN frame.
+  CTR_SigNotUpdated,      // Have not received an value response for signal.
+  CTR_BufferFull,  // Caller attempted to insert data into a buffer that is
+                   // full.
+} CTR_Code;
+
+// VISA Error
+#define _VI_ERROR (-2147483647L - 1)
+#define VI_ERROR_SYSTEM_ERROR (_VI_ERROR + 0x3FFF0000L)
+#define VI_ERROR_INV_OBJECT (_VI_ERROR + 0x3FFF000EL)
+#define VI_ERROR_RSRC_LOCKED (_VI_ERROR + 0x3FFF000FL)
+#define VI_ERROR_INV_EXPR (_VI_ERROR + 0x3FFF0010L)
+#define VI_ERROR_RSRC_NFOUND (_VI_ERROR + 0x3FFF0011L)
+#define VI_ERROR_INV_RSRC_NAME (_VI_ERROR + 0x3FFF0012L)
+#define VI_ERROR_INV_ACC_MODE (_VI_ERROR + 0x3FFF0013L)
+#define VI_ERROR_TMO (_VI_ERROR + 0x3FFF0015L)
+#define VI_ERROR_CLOSING_FAILED (_VI_ERROR + 0x3FFF0016L)
+#define VI_ERROR_INV_DEGREE (_VI_ERROR + 0x3FFF001BL)
+#define VI_ERROR_INV_JOB_ID (_VI_ERROR + 0x3FFF001CL)
+#define VI_ERROR_NSUP_ATTR (_VI_ERROR + 0x3FFF001DL)
+#define VI_ERROR_NSUP_ATTR_STATE (_VI_ERROR + 0x3FFF001EL)
+#define VI_ERROR_ATTR_READONLY (_VI_ERROR + 0x3FFF001FL)
+#define VI_ERROR_INV_LOCK_TYPE (_VI_ERROR + 0x3FFF0020L)
+#define VI_ERROR_INV_ACCESS_KEY (_VI_ERROR + 0x3FFF0021L)
+#define VI_ERROR_INV_EVENT (_VI_ERROR + 0x3FFF0026L)
+#define VI_ERROR_INV_MECH (_VI_ERROR + 0x3FFF0027L)
+#define VI_ERROR_HNDLR_NINSTALLED (_VI_ERROR + 0x3FFF0028L)
+#define VI_ERROR_INV_HNDLR_REF (_VI_ERROR + 0x3FFF0029L)
+#define VI_ERROR_INV_CONTEXT (_VI_ERROR + 0x3FFF002AL)
+#define VI_ERROR_QUEUE_OVERFLOW (_VI_ERROR + 0x3FFF002DL)
+#define VI_ERROR_NENABLED (_VI_ERROR + 0x3FFF002FL)
+#define VI_ERROR_ABORT (_VI_ERROR + 0x3FFF0030L)
+#define VI_ERROR_RAW_WR_PROT_VIOL (_VI_ERROR + 0x3FFF0034L)
+#define VI_ERROR_RAW_RD_PROT_VIOL (_VI_ERROR + 0x3FFF0035L)
+#define VI_ERROR_OUTP_PROT_VIOL (_VI_ERROR + 0x3FFF0036L)
+#define VI_ERROR_INP_PROT_VIOL (_VI_ERROR + 0x3FFF0037L)
+#define VI_ERROR_BERR (_VI_ERROR + 0x3FFF0038L)
+#define VI_ERROR_IN_PROGRESS (_VI_ERROR + 0x3FFF0039L)
+#define VI_ERROR_INV_SETUP (_VI_ERROR + 0x3FFF003AL)
+#define VI_ERROR_QUEUE_ERROR (_VI_ERROR + 0x3FFF003BL)
+#define VI_ERROR_ALLOC (_VI_ERROR + 0x3FFF003CL)
+#define VI_ERROR_INV_MASK (_VI_ERROR + 0x3FFF003DL)
+#define VI_ERROR_IO (_VI_ERROR + 0x3FFF003EL)
+#define VI_ERROR_INV_FMT (_VI_ERROR + 0x3FFF003FL)
+#define VI_ERROR_NSUP_FMT (_VI_ERROR + 0x3FFF0041L)
+#define VI_ERROR_LINE_IN_USE (_VI_ERROR + 0x3FFF0042L)
+#define VI_ERROR_NSUP_MODE (_VI_ERROR + 0x3FFF0046L)
+#define VI_ERROR_SRQ_NOCCURRED (_VI_ERROR + 0x3FFF004AL)
+#define VI_ERROR_INV_SPACE (_VI_ERROR + 0x3FFF004EL)
+#define VI_ERROR_INV_OFFSET (_VI_ERROR + 0x3FFF0051L)
+#define VI_ERROR_INV_WIDTH (_VI_ERROR + 0x3FFF0052L)
+#define VI_ERROR_NSUP_OFFSET (_VI_ERROR + 0x3FFF0054L)
+#define VI_ERROR_NSUP_VAR_WIDTH (_VI_ERROR + 0x3FFF0055L)
+#define VI_ERROR_WINDOW_NMAPPED (_VI_ERROR + 0x3FFF0057L)
+#define VI_ERROR_RESP_PENDING (_VI_ERROR + 0x3FFF0059L)
+#define VI_ERROR_NLISTENERS (_VI_ERROR + 0x3FFF005FL)
+#define VI_ERROR_NCIC (_VI_ERROR + 0x3FFF0060L)
+#define VI_ERROR_NSYS_CNTLR (_VI_ERROR + 0x3FFF0061L)
+#define VI_ERROR_NSUP_OPER (_VI_ERROR + 0x3FFF0067L)
+#define VI_ERROR_INTR_PENDING (_VI_ERROR + 0x3FFF0068L)
+#define VI_ERROR_ASRL_PARITY (_VI_ERROR + 0x3FFF006AL)
+#define VI_ERROR_ASRL_FRAMING (_VI_ERROR + 0x3FFF006BL)
+#define VI_ERROR_ASRL_OVERRUN (_VI_ERROR + 0x3FFF006CL)
+#define VI_ERROR_TRIG_NMAPPED (_VI_ERROR + 0x3FFF006EL)
+#define VI_ERROR_NSUP_ALIGN_OFFSET (_VI_ERROR + 0x3FFF0070L)
+#define VI_ERROR_USER_BUF (_VI_ERROR + 0x3FFF0071L)
+#define VI_ERROR_RSRC_BUSY (_VI_ERROR + 0x3FFF0072L)
+#define VI_ERROR_NSUP_WIDTH (_VI_ERROR + 0x3FFF0076L)
+#define VI_ERROR_INV_PARAMETER (_VI_ERROR + 0x3FFF0078L)
+#define VI_ERROR_INV_PROT (_VI_ERROR + 0x3FFF0079L)
+#define VI_ERROR_INV_SIZE (_VI_ERROR + 0x3FFF007BL)
+#define VI_ERROR_WINDOW_MAPPED (_VI_ERROR + 0x3FFF0080L)
+#define VI_ERROR_NIMPL_OPER (_VI_ERROR + 0x3FFF0081L)
+#define VI_ERROR_INV_LENGTH (_VI_ERROR + 0x3FFF0083L)
+#define VI_ERROR_INV_MODE (_VI_ERROR + 0x3FFF0091L)
+#define VI_ERROR_SESN_NLOCKED (_VI_ERROR + 0x3FFF009CL)
+#define VI_ERROR_MEM_NSHARED (_VI_ERROR + 0x3FFF009DL)
+#define VI_ERROR_LIBRARY_NFOUND (_VI_ERROR + 0x3FFF009EL)
+#define VI_ERROR_NSUP_INTR (_VI_ERROR + 0x3FFF009FL)
+#define VI_ERROR_INV_LINE (_VI_ERROR + 0x3FFF00A0L)
+#define VI_ERROR_FILE_ACCESS (_VI_ERROR + 0x3FFF00A1L)
+#define VI_ERROR_FILE_IO (_VI_ERROR + 0x3FFF00A2L)
+#define VI_ERROR_NSUP_LINE (_VI_ERROR + 0x3FFF00A3L)
+#define VI_ERROR_NSUP_MECH (_VI_ERROR + 0x3FFF00A4L)
+#define VI_ERROR_INTF_NUM_NCONFIG (_VI_ERROR + 0x3FFF00A5L)
+#define VI_ERROR_CONN_LOST (_VI_ERROR + 0x3FFF00A6L)
+#define VI_ERROR_MACHINE_NAVAIL (_VI_ERROR + 0x3FFF00A7L)
+#define VI_ERROR_NPERMISSION (_VI_ERROR + 0x3FFF00A8L)
+
+// FPGA Errors
+
+/**
+ * Represents the resulting status of a function call through its return value.
+ * 0 is success, negative values are errors, and positive values are warnings.
+ */
+typedef int32_t NiFpga_Status;
+
+/**
+ * No errors or warnings.
+ */
+static const NiFpga_Status NiFpga_Status_Success = 0;
+
+/**
+ * The timeout expired before the FIFO operation could complete.
+ */
+static const NiFpga_Status NiFpga_Status_FifoTimeout = -50400;
+
+/**
+ * No transfer is in progress because the transfer was aborted by the client.
+ * The operation could not be completed as specified.
+ */
+static const NiFpga_Status NiFpga_Status_TransferAborted = -50405;
+
+/**
+ * A memory allocation failed. Try again after rebooting.
+ */
+static const NiFpga_Status NiFpga_Status_MemoryFull = -52000;
+
+/**
+ * An unexpected software error occurred.
+ */
+static const NiFpga_Status NiFpga_Status_SoftwareFault = -52003;
+
+/**
+ * A parameter to a function was not valid. This could be a NULL pointer, a bad
+ * value, etc.
+ */
+static const NiFpga_Status NiFpga_Status_InvalidParameter = -52005;
+
+/**
+ * A required resource was not found. The NiFpga.* library, the RIO resource, or
+ * some other resource may be missing.
+ */
+static const NiFpga_Status NiFpga_Status_ResourceNotFound = -52006;
+
+/**
+ * A required resource was not properly initialized. This could occur if
+ * NiFpga_Initialize was not called or a required NiFpga_IrqContext was not
+ * reserved.
+ */
+static const NiFpga_Status NiFpga_Status_ResourceNotInitialized = -52010;
+
+/**
+ * A hardware failure has occurred. The operation could not be completed as
+ * specified.
+ */
+static const NiFpga_Status NiFpga_Status_HardwareFault = -52018;
+
+/**
+ * The FPGA is already running.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaAlreadyRunning = -61003;
+
+/**
+ * An error occurred downloading the VI to the FPGA device. Verify that
+ * the target is connected and powered and that the resource of the target
+ * is properly configured.
+ */
+static const NiFpga_Status NiFpga_Status_DownloadError = -61018;
+
+/**
+ * The bitfile was not compiled for the specified resource's device type.
+ */
+static const NiFpga_Status NiFpga_Status_DeviceTypeMismatch = -61024;
+
+/**
+ * An error was detected in the communication between the host computer and the
+ * FPGA target.
+ */
+static const NiFpga_Status NiFpga_Status_CommunicationTimeout = -61046;
+
+/**
+ * The timeout expired before any of the IRQs were asserted.
+ */
+static const NiFpga_Status NiFpga_Status_IrqTimeout = -61060;
+
+/**
+ * The specified bitfile is invalid or corrupt.
+ */
+static const NiFpga_Status NiFpga_Status_CorruptBitfile = -61070;
+
+/**
+ * The requested FIFO depth is invalid. It is either 0 or an amount not
+ * supported by the hardware.
+ */
+static const NiFpga_Status NiFpga_Status_BadDepth = -61072;
+
+/**
+ * The number of FIFO elements is invalid. Either the number is greater than the
+ * depth of the host memory DMA FIFO, or more elements were requested for
+ * release than had been acquired.
+ */
+static const NiFpga_Status NiFpga_Status_BadReadWriteCount = -61073;
+
+/**
+ * A hardware clocking error occurred. A derived clock lost lock with its base
+ * clock during the execution of the LabVIEW FPGA VI. If any base clocks with
+ * derived clocks are referencing an external source, make sure that the
+ * external source is connected and within the supported frequency, jitter,
+ * accuracy, duty cycle, and voltage specifications. Also verify that the
+ * characteristics of the base clock match the configuration specified in the
+ * FPGA Base Clock Properties. If all base clocks with derived clocks are
+ * generated from free-running, on-board sources, please contact National
+ * Instruments technical support at ni.com/support.
+ */
+static const NiFpga_Status NiFpga_Status_ClockLostLock = -61083;
+
+/**
+ * The operation could not be performed because the FPGA is busy. Stop all
+ * activities on the FPGA before requesting this operation. If the target is in
+ * Scan Interface programming mode, put it in FPGA Interface programming mode.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaBusy = -61141;
+
+/**
+ * The operation could not be performed because the FPGA is busy operating in
+ * FPGA Interface C API mode. Stop all activities on the FPGA before requesting
+ * this operation.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaBusyFpgaInterfaceCApi = -61200;
+
+/**
+ * The chassis is in Scan Interface programming mode. In order to run FPGA VIs,
+ * you must go to the chassis properties page, select FPGA programming mode, and
+ * deploy settings.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaBusyScanInterface = -61201;
+
+/**
+ * The operation could not be performed because the FPGA is busy operating in
+ * FPGA Interface mode. Stop all activities on the FPGA before requesting this
+ * operation.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaBusyFpgaInterface = -61202;
+
+/**
+ * The operation could not be performed because the FPGA is busy operating in
+ * Interactive mode. Stop all activities on the FPGA before requesting this
+ * operation.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaBusyInteractive = -61203;
+
+/**
+ * The operation could not be performed because the FPGA is busy operating in
+ * Emulation mode. Stop all activities on the FPGA before requesting this
+ * operation.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaBusyEmulation = -61204;
+
+/**
+ * LabVIEW FPGA does not support the Reset method for bitfiles that allow
+ * removal of implicit enable signals in single-cycle Timed Loops.
+ */
+static const NiFpga_Status NiFpga_Status_ResetCalledWithImplicitEnableRemoval =
+    -61211;
+
+/**
+ * LabVIEW FPGA does not support the Abort method for bitfiles that allow
+ * removal of implicit enable signals in single-cycle Timed Loops.
+ */
+static const NiFpga_Status NiFpga_Status_AbortCalledWithImplicitEnableRemoval =
+    -61212;
+
+/**
+ * LabVIEW FPGA does not support Close and Reset if Last Reference for bitfiles
+ * that allow removal of implicit enable signals in single-cycle Timed Loops.
+ * Pass the NiFpga_CloseAttribute_NoResetIfLastSession attribute to NiFpga_Close
+ * instead of 0.
+ */
+static const NiFpga_Status
+    NiFpga_Status_CloseAndResetCalledWithImplicitEnableRemoval = -61213;
+
+/**
+ * For bitfiles that allow removal of implicit enable signals in single-cycle
+ * Timed Loops, LabVIEW FPGA does not support this method prior to running the
+ * bitfile.
+ */
+static const NiFpga_Status NiFpga_Status_ImplicitEnableRemovalButNotYetRun =
+    -61214;
+
+/**
+ * Bitfiles that allow removal of implicit enable signals in single-cycle Timed
+ * Loops can run only once. Download the bitfile again before re-running the VI.
+ */
+static const NiFpga_Status
+    NiFpga_Status_RunAfterStoppedCalledWithImplicitEnableRemoval = -61215;
+
+/**
+ * A gated clock has violated the handshaking protocol. If you are using
+ * external gated clocks, ensure that they follow the required clock gating
+ * protocol. If you are generating your clocks internally, please contact
+ * National Instruments Technical Support.
+ */
+static const NiFpga_Status NiFpga_Status_GatedClockHandshakingViolation =
+    -61216;
+
+/**
+ * The number of elements requested must be less than or equal to the number of
+ * unacquired elements left in the host memory DMA FIFO. There are currently
+ * fewer unacquired elements left in the FIFO than are being requested. Release
+ * some acquired elements before acquiring more elements.
+ */
+static const NiFpga_Status NiFpga_Status_ElementsNotPermissibleToBeAcquired =
+    -61219;
+
+/**
+ * The operation could not be performed because the FPGA is in configuration or
+ * discovery mode. Wait for configuration or discovery to complete and retry
+ * your operation.
+ */
+static const NiFpga_Status NiFpga_Status_FpgaBusyConfiguration = -61252;
+
+/**
+ * An unexpected internal error occurred.
+ */
+static const NiFpga_Status NiFpga_Status_InternalError = -61499;
+
+/**
+ * The NI-RIO driver was unable to allocate memory for a FIFO. This can happen
+ * when the combined depth of all DMA FIFOs exceeds the maximum depth for the
+ * controller, or when the controller runs out of system memory. You may be able
+ * to reconfigure the controller with a greater maximum FIFO depth. For more
+ * information, refer to the NI KnowledgeBase article 65OF2ERQ.
+ */
+static const NiFpga_Status NiFpga_Status_TotalDmaFifoDepthExceeded = -63003;
+
+/**
+ * Access to the remote system was denied. Use MAX to check the Remote Device
+ * Access settings under Software>>NI-RIO>>NI-RIO Settings on the remote system.
+ */
+static const NiFpga_Status NiFpga_Status_AccessDenied = -63033;
+
+/**
+ * The NI-RIO software on the host is not compatible with the software on the
+ * target. Upgrade the NI-RIO software on the host in order to connect to this
+ * target.
+ */
+static const NiFpga_Status NiFpga_Status_HostVersionMismatch = -63038;
+
+/**
+ * A connection could not be established to the specified remote device. Ensure
+ * that the device is on and accessible over the network, that NI-RIO software
+ * is installed, and that the RIO server is running and properly configured.
+ */
+static const NiFpga_Status NiFpga_Status_RpcConnectionError = -63040;
+
+/**
+ * The RPC session is invalid. The target may have reset or been rebooted. Check
+ * the network connection and retry the operation.
+ */
+static const NiFpga_Status NiFpga_Status_RpcSessionError = -63043;
+
+/**
+ * The operation could not complete because another session is accessing the
+ * FIFO. Close the other session and retry.
+ */
+static const NiFpga_Status NiFpga_Status_FifoReserved = -63082;
+
+/**
+ * A Configure FIFO, Stop FIFO, Read FIFO, or Write FIFO function was called
+ * while the host had acquired elements of the FIFO. Release all acquired
+ * elements before configuring, stopping, reading, or writing.
+ */
+static const NiFpga_Status NiFpga_Status_FifoElementsCurrentlyAcquired = -63083;
+
+/**
+ * A function was called using a misaligned address. The address must be a
+ * multiple of the size of the datatype.
+ */
+static const NiFpga_Status NiFpga_Status_MisalignedAccess = -63084;
+
+/**
+ * The FPGA Read/Write Control Function is accessing a control or indicator
+ * with data that exceeds the maximum size supported on the current target.
+ * Refer to the hardware documentation for the limitations on data types for
+ * this target.
+ */
+static const NiFpga_Status NiFpga_Status_ControlOrIndicatorTooLarge = -63085;
+
+/**
+ * A valid .lvbitx bitfile is required. If you are using a valid .lvbitx
+ * bitfile, the bitfile may not be compatible with the software you are using.
+ * Determine which version of LabVIEW was used to make the bitfile, update your
+ * software to that version or later, and try again.
+ */
+static const NiFpga_Status NiFpga_Status_BitfileReadError = -63101;
+
+/**
+ * The specified signature does not match the signature of the bitfile. If the
+ * bitfile has been recompiled, regenerate the C API and rebuild the
+ * application.
+ */
+static const NiFpga_Status NiFpga_Status_SignatureMismatch = -63106;
+
+/**
+ * The bitfile you are trying to use is incompatible with the version
+ * of NI-RIO installed on the target and/or host. Update the version
+ * of NI-RIO on the target and/or host to the same version (or later)
+ * used to compile the bitfile. Alternatively, recompile the bitfile
+ * with the same version of NI-RIO that is currently installed on the
+ * target and/or host.
+ */
+static const NiFpga_Status NiFpga_Status_IncompatibleBitfile = -63107;
+
+/**
+ * Either the supplied resource name is invalid as a RIO resource name, or the
+ * device was not found. Use MAX to find the proper resource name for the
+ * intended device.
+ */
+static const NiFpga_Status NiFpga_Status_InvalidResourceName = -63192;
+
+/**
+ * The requested feature is not supported.
+ */
+static const NiFpga_Status NiFpga_Status_FeatureNotSupported = -63193;
+
+/**
+ * The NI-RIO software on the target system is not compatible with this
+ * software. Upgrade the NI-RIO software on the target system.
+ */
+static const NiFpga_Status NiFpga_Status_VersionMismatch = -63194;
+
+/**
+ * The session is invalid or has been closed.
+ */
+static const NiFpga_Status NiFpga_Status_InvalidSession = -63195;
+
+/**
+ * The maximum number of open FPGA sessions has been reached. Close some open
+ * sessions.
+ */
+static const NiFpga_Status NiFpga_Status_OutOfHandles = -63198;
diff --git a/hal/src/main/native/sim/Extensions.cpp b/hal/src/main/native/sim/Extensions.cpp
new file mode 100644
index 0000000..6ef7903
--- /dev/null
+++ b/hal/src/main/native/sim/Extensions.cpp
@@ -0,0 +1,85 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Extensions.h"
+
+#include <wpi/SmallString.h>
+#include <wpi/StringRef.h>
+
+#include "hal/HAL.h"
+
+#if defined(WIN32) || defined(_WIN32)
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+#if defined(WIN32) || defined(_WIN32)
+#define DELIM ';'
+#define HTYPE HMODULE
+#define DLOPEN(a) LoadLibrary(a)
+#define DLSYM GetProcAddress
+#define DLCLOSE FreeLibrary
+#else
+#define DELIM ':'
+#define HTYPE void*
+#define PREFIX "lib"
+#define DLOPEN(a) dlopen(a, RTLD_LAZY)
+#define DLSYM dlsym
+#define DLCLOSE dlclose
+#endif
+
+namespace hal {
+namespace init {
+void InitializeExtensions() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+int HAL_LoadOneExtension(const char* library) {
+  int rc = 1;  // It is expected and reasonable not to find an extra simulation
+  HTYPE handle = DLOPEN(library);
+#if !defined(WIN32) && !defined(_WIN32)
+  if (!handle) {
+    wpi::SmallString<128> libraryName("lib");
+    libraryName += library;
+#if defined(__APPLE__)
+    libraryName += ".dylib";
+#else
+    libraryName += ".so";
+#endif
+    handle = DLOPEN(libraryName.c_str());
+  }
+#endif
+  if (!handle) return rc;
+
+  auto init = reinterpret_cast<halsim_extension_init_func_t*>(
+      DLSYM(handle, "HALSIM_InitExtension"));
+
+  if (init) rc = (*init)();
+
+  if (rc != 0) DLCLOSE(handle);
+  return rc;
+}
+
+int HAL_LoadExtensions(void) {
+  int rc = 1;
+  wpi::SmallVector<wpi::StringRef, 2> libraries;
+  const char* e = std::getenv("HALSIM_EXTENSIONS");
+  if (!e) return rc;
+  wpi::StringRef env{e};
+  env.split(libraries, DELIM, -1, false);
+  for (auto& libref : libraries) {
+    wpi::SmallString<128> library(libref);
+    rc = HAL_LoadOneExtension(library.c_str());
+    if (rc < 0) break;
+  }
+  return rc;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp
new file mode 100644
index 0000000..d058c1a
--- /dev/null
+++ b/hal/src/main/native/sim/HAL.cpp
@@ -0,0 +1,256 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/HAL.h"
+
+#include <wpi/mutex.h>
+#include <wpi/raw_ostream.h>
+
+#include "ErrorsInternal.h"
+#include "HALInitializer.h"
+#include "MockHooksInternal.h"
+#include "hal/DriverStation.h"
+#include "hal/Errors.h"
+#include "hal/Extensions.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/RoboRioDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeHAL() {
+  InitializeAccelerometerData();
+  InitializeAnalogGyroData();
+  InitializeAnalogInData();
+  InitializeAnalogOutData();
+  InitializeAnalogTriggerData();
+  InitializeCanData();
+  InitializeCANAPI();
+  InitializeDigitalPWMData();
+  InitializeDIOData();
+  InitializeDriverStationData();
+  InitializeEncoderData();
+  InitializeI2CData();
+  InitializePCMData();
+  InitializePDPData();
+  InitializePWMData();
+  InitializeRelayData();
+  InitializeRoboRioData();
+  InitializeSPIAccelerometerData();
+  InitializeSPIData();
+  InitializeAccelerometer();
+  InitializeAnalogAccumulator();
+  InitializeAnalogGyro();
+  InitializeAnalogInput();
+  InitializeAnalogInternal();
+  InitializeAnalogOutput();
+  InitializeCAN();
+  InitializeCompressor();
+  InitializeConstants();
+  InitializeCounter();
+  InitializeDigitalInternal();
+  InitializeDIO();
+  InitializeDriverStation();
+  InitializeEncoder();
+  InitializeExtensions();
+  InitializeI2C();
+  InitializeInterrupts();
+  InitializeMockHooks();
+  InitializeNotifier();
+  InitializePDP();
+  InitializePorts();
+  InitializePower();
+  InitializePWM();
+  InitializeRelay();
+  InitializeSerialPort();
+  InitializeSolenoid();
+  InitializeSPI();
+  InitializeThreads();
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_PortHandle HAL_GetPort(int32_t channel) {
+  // Dont allow a number that wouldn't fit in a uint8_t
+  if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
+  return createPortHandle(channel, 1);
+}
+
+HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
+  // Dont allow a number that wouldn't fit in a uint8_t
+  if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
+  if (module < 0 || module >= 255) return HAL_kInvalidHandle;
+  return createPortHandle(channel, module);
+}
+
+const char* HAL_GetErrorMessage(int32_t code) {
+  switch (code) {
+    case 0:
+      return "";
+    case CTR_RxTimeout:
+      return CTR_RxTimeout_MESSAGE;
+    case CTR_TxTimeout:
+      return CTR_TxTimeout_MESSAGE;
+    case CTR_InvalidParamValue:
+      return CTR_InvalidParamValue_MESSAGE;
+    case CTR_UnexpectedArbId:
+      return CTR_UnexpectedArbId_MESSAGE;
+    case CTR_TxFailed:
+      return CTR_TxFailed_MESSAGE;
+    case CTR_SigNotUpdated:
+      return CTR_SigNotUpdated_MESSAGE;
+    case NiFpga_Status_FifoTimeout:
+      return NiFpga_Status_FifoTimeout_MESSAGE;
+    case NiFpga_Status_TransferAborted:
+      return NiFpga_Status_TransferAborted_MESSAGE;
+    case NiFpga_Status_MemoryFull:
+      return NiFpga_Status_MemoryFull_MESSAGE;
+    case NiFpga_Status_SoftwareFault:
+      return NiFpga_Status_SoftwareFault_MESSAGE;
+    case NiFpga_Status_InvalidParameter:
+      return NiFpga_Status_InvalidParameter_MESSAGE;
+    case NiFpga_Status_ResourceNotFound:
+      return NiFpga_Status_ResourceNotFound_MESSAGE;
+    case NiFpga_Status_ResourceNotInitialized:
+      return NiFpga_Status_ResourceNotInitialized_MESSAGE;
+    case NiFpga_Status_HardwareFault:
+      return NiFpga_Status_HardwareFault_MESSAGE;
+    case NiFpga_Status_IrqTimeout:
+      return NiFpga_Status_IrqTimeout_MESSAGE;
+    case SAMPLE_RATE_TOO_HIGH:
+      return SAMPLE_RATE_TOO_HIGH_MESSAGE;
+    case VOLTAGE_OUT_OF_RANGE:
+      return VOLTAGE_OUT_OF_RANGE_MESSAGE;
+    case LOOP_TIMING_ERROR:
+      return LOOP_TIMING_ERROR_MESSAGE;
+    case SPI_WRITE_NO_MOSI:
+      return SPI_WRITE_NO_MOSI_MESSAGE;
+    case SPI_READ_NO_MISO:
+      return SPI_READ_NO_MISO_MESSAGE;
+    case SPI_READ_NO_DATA:
+      return SPI_READ_NO_DATA_MESSAGE;
+    case INCOMPATIBLE_STATE:
+      return INCOMPATIBLE_STATE_MESSAGE;
+    case NO_AVAILABLE_RESOURCES:
+      return NO_AVAILABLE_RESOURCES_MESSAGE;
+    case RESOURCE_IS_ALLOCATED:
+      return RESOURCE_IS_ALLOCATED_MESSAGE;
+    case RESOURCE_OUT_OF_RANGE:
+      return RESOURCE_OUT_OF_RANGE_MESSAGE;
+    case HAL_INVALID_ACCUMULATOR_CHANNEL:
+      return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
+    case HAL_HANDLE_ERROR:
+      return HAL_HANDLE_ERROR_MESSAGE;
+    case NULL_PARAMETER:
+      return NULL_PARAMETER_MESSAGE;
+    case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
+      return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
+    case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
+      return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
+    case PARAMETER_OUT_OF_RANGE:
+      return PARAMETER_OUT_OF_RANGE_MESSAGE;
+    case HAL_COUNTER_NOT_SUPPORTED:
+      return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
+    case HAL_ERR_CANSessionMux_InvalidBuffer:
+      return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
+    case HAL_ERR_CANSessionMux_MessageNotFound:
+      return ERR_CANSessionMux_MessageNotFound_MESSAGE;
+    case HAL_WARN_CANSessionMux_NoToken:
+      return WARN_CANSessionMux_NoToken_MESSAGE;
+    case HAL_ERR_CANSessionMux_NotAllowed:
+      return ERR_CANSessionMux_NotAllowed_MESSAGE;
+    case HAL_ERR_CANSessionMux_NotInitialized:
+      return ERR_CANSessionMux_NotInitialized_MESSAGE;
+    case VI_ERROR_SYSTEM_ERROR:
+      return VI_ERROR_SYSTEM_ERROR_MESSAGE;
+    case VI_ERROR_INV_OBJECT:
+      return VI_ERROR_INV_OBJECT_MESSAGE;
+    case VI_ERROR_RSRC_LOCKED:
+      return VI_ERROR_RSRC_LOCKED_MESSAGE;
+    case VI_ERROR_RSRC_NFOUND:
+      return VI_ERROR_RSRC_NFOUND_MESSAGE;
+    case VI_ERROR_INV_RSRC_NAME:
+      return VI_ERROR_INV_RSRC_NAME_MESSAGE;
+    case VI_ERROR_QUEUE_OVERFLOW:
+      return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
+    case VI_ERROR_IO:
+      return VI_ERROR_IO_MESSAGE;
+    case VI_ERROR_ASRL_PARITY:
+      return VI_ERROR_ASRL_PARITY_MESSAGE;
+    case VI_ERROR_ASRL_FRAMING:
+      return VI_ERROR_ASRL_FRAMING_MESSAGE;
+    case VI_ERROR_ASRL_OVERRUN:
+      return VI_ERROR_ASRL_OVERRUN_MESSAGE;
+    case VI_ERROR_RSRC_BUSY:
+      return VI_ERROR_RSRC_BUSY_MESSAGE;
+    case VI_ERROR_INV_PARAMETER:
+      return VI_ERROR_INV_PARAMETER_MESSAGE;
+    case HAL_PWM_SCALE_ERROR:
+      return HAL_PWM_SCALE_ERROR_MESSAGE;
+    case HAL_CAN_TIMEOUT:
+      return HAL_CAN_TIMEOUT_MESSAGE;
+    default:
+      return "Unknown error status";
+  }
+}
+
+HAL_RuntimeType HAL_GetRuntimeType(void) { return HAL_Mock; }
+
+int32_t HAL_GetFPGAVersion(int32_t* status) {
+  return 2018;  // Automatically script this at some point
+}
+
+int64_t HAL_GetFPGARevision(int32_t* status) {
+  return 0;  // TODO: Find a better number to return;
+}
+
+uint64_t HAL_GetFPGATime(int32_t* status) { return hal::GetFPGATime(); }
+
+HAL_Bool HAL_GetFPGAButton(int32_t* status) {
+  return SimRoboRioData[0].fpgaButton;
+}
+
+HAL_Bool HAL_GetSystemActive(int32_t* status) {
+  return true;  // Figure out if we need to handle this
+}
+
+HAL_Bool HAL_GetBrownedOut(int32_t* status) {
+  return false;  // Figure out if we need to detect a brownout condition
+}
+
+HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
+  static std::atomic_bool initialized{false};
+  static wpi::mutex initializeMutex;
+  // Initial check, as if it's true initialization has finished
+  if (initialized) return true;
+
+  std::lock_guard<wpi::mutex> lock(initializeMutex);
+  // Second check in case another thread was waiting
+  if (initialized) return true;
+
+  hal::init::InitializeHAL();
+
+  hal::init::HAL_IsInitialized.store(true);
+
+  wpi::outs().SetUnbuffered();
+  if (HAL_LoadExtensions() < 0) return false;
+  hal::RestartTiming();
+  HAL_InitializeDriverStation();
+
+  initialized = true;
+  return true;  // Add initialization if we need to at a later point
+}
+
+int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
+                   const char* feature) {
+  return 0;  // Do nothing for now
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/HALInitializer.cpp b/hal/src/main/native/sim/HALInitializer.cpp
new file mode 100644
index 0000000..a0456d4
--- /dev/null
+++ b/hal/src/main/native/sim/HALInitializer.cpp
@@ -0,0 +1,17 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HALInitializer.h"
+
+#include "hal/HAL.h"
+
+namespace hal {
+namespace init {
+std::atomic_bool HAL_IsInitialized{false};
+void RunInitialize() { HAL_Initialize(500, 0); }
+}  // namespace init
+}  // namespace hal
diff --git a/hal/src/main/native/sim/HALInitializer.h b/hal/src/main/native/sim/HALInitializer.h
new file mode 100644
index 0000000..d369a3b
--- /dev/null
+++ b/hal/src/main/native/sim/HALInitializer.h
@@ -0,0 +1,71 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <atomic>
+
+namespace hal {
+namespace init {
+extern std::atomic_bool HAL_IsInitialized;
+extern void RunInitialize();
+static inline void CheckInit() {
+  if (HAL_IsInitialized.load(std::memory_order_relaxed)) return;
+  RunInitialize();
+}
+
+extern void InitializeAccelerometerData();
+extern void InitializeAnalogGyroData();
+extern void InitializeAnalogInData();
+extern void InitializeAnalogOutData();
+extern void InitializeAnalogTriggerData();
+extern void InitializeCanData();
+extern void InitializeCANAPI();
+extern void InitializeDigitalPWMData();
+extern void InitializeDIOData();
+extern void InitializeDriverStationData();
+extern void InitializeEncoderData();
+extern void InitializeI2CData();
+extern void InitializePCMData();
+extern void InitializePDPData();
+extern void InitializePWMData();
+extern void InitializeRelayData();
+extern void InitializeRoboRioData();
+extern void InitializeSPIAccelerometerData();
+extern void InitializeSPIData();
+extern void InitializeAccelerometer();
+extern void InitializeAnalogAccumulator();
+extern void InitializeAnalogGyro();
+extern void InitializeAnalogInput();
+extern void InitializeAnalogInternal();
+extern void InitializeAnalogOutput();
+extern void InitializeCAN();
+extern void InitializeCompressor();
+extern void InitializeConstants();
+extern void InitializeCounter();
+extern void InitializeDigitalInternal();
+extern void InitializeDIO();
+extern void InitializeDriverStation();
+extern void InitializeEncoder();
+extern void InitializeExtensions();
+extern void InitializeHAL();
+extern void InitializeI2C();
+extern void InitializeInterrupts();
+extern void InitializeMockHooks();
+extern void InitializeNotifier();
+extern void InitializePDP();
+extern void InitializePorts();
+extern void InitializePower();
+extern void InitializePWM();
+extern void InitializeRelay();
+extern void InitializeSerialPort();
+extern void InitializeSolenoid();
+extern void InitializeSPI();
+extern void InitializeThreads();
+
+}  // namespace init
+}  // namespace hal
diff --git a/hal/src/main/native/sim/I2C.cpp b/hal/src/main/native/sim/I2C.cpp
new file mode 100644
index 0000000..fe4952f
--- /dev/null
+++ b/hal/src/main/native/sim/I2C.cpp
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/I2C.h"
+
+#include "HALInitializer.h"
+#include "mockdata/I2CDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeI2C() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status) {
+  hal::init::CheckInit();
+  SimI2CData[port].initialized = true;
+}
+int32_t HAL_TransactionI2C(HAL_I2CPort port, int32_t deviceAddress,
+                           const uint8_t* dataToSend, int32_t sendSize,
+                           uint8_t* dataReceived, int32_t receiveSize) {
+  SimI2CData[port].Write(deviceAddress, dataToSend, sendSize);
+  SimI2CData[port].Read(deviceAddress, dataReceived, receiveSize);
+  return 0;
+}
+int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress,
+                     const uint8_t* dataToSend, int32_t sendSize) {
+  SimI2CData[port].Write(deviceAddress, dataToSend, sendSize);
+  return 0;
+}
+int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer,
+                    int32_t count) {
+  SimI2CData[port].Read(deviceAddress, buffer, count);
+  return 0;
+}
+void HAL_CloseI2C(HAL_I2CPort port) { SimI2CData[port].initialized = false; }
+}  // extern "C"
diff --git a/hal/src/main/native/sim/Interrupts.cpp b/hal/src/main/native/sim/Interrupts.cpp
new file mode 100644
index 0000000..75247ca
--- /dev/null
+++ b/hal/src/main/native/sim/Interrupts.cpp
@@ -0,0 +1,565 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Interrupts.h"
+
+#include <memory>
+
+#include <wpi/condition_variable.h>
+
+#include "AnalogInternal.h"
+#include "DigitalInternal.h"
+#include "ErrorsInternal.h"
+#include "HALInitializer.h"
+#include "MockHooksInternal.h"
+#include "PortsInternal.h"
+#include "hal/AnalogTrigger.h"
+#include "hal/Errors.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"
+
+using namespace hal;
+
+enum WaitResult {
+  Timeout = 0x0,
+  RisingEdge = 0x1,
+  FallingEdge = 0x100,
+  Both = 0x101,
+};
+
+namespace {
+struct Interrupt {
+  bool isAnalog;
+  HAL_Handle portHandle;
+  uint8_t index;
+  HAL_AnalogTriggerType trigType;
+  bool watcher;
+  int64_t risingTimestamp;
+  int64_t fallingTimestamp;
+  bool previousState;
+  bool fireOnUp;
+  bool fireOnDown;
+  int32_t callbackId;
+
+  void* callbackParam;
+  HAL_InterruptHandlerFunction callbackFunction;
+};
+
+struct SynchronousWaitData {
+  HAL_InterruptHandle interruptHandle;
+  wpi::condition_variable waitCond;
+  HAL_Bool waitPredicate;
+};
+}  // namespace
+
+static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+                             HAL_HandleEnum::Interrupt>* interruptHandles;
+
+typedef HAL_Handle SynchronousWaitDataHandle;
+static UnlimitedHandleResource<SynchronousWaitDataHandle, SynchronousWaitData,
+                               HAL_HandleEnum::Vendor>*
+    synchronousInterruptHandles;
+
+namespace hal {
+namespace init {
+void InitializeInterrupts() {
+  static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+                               HAL_HandleEnum::Interrupt>
+      iH;
+  interruptHandles = &iH;
+  static UnlimitedHandleResource<SynchronousWaitDataHandle, SynchronousWaitData,
+                                 HAL_HandleEnum::Vendor>
+      siH;
+  synchronousInterruptHandles = &siH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
+                                             int32_t* status) {
+  hal::init::CheckInit();
+  HAL_InterruptHandle handle = interruptHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto anInterrupt = interruptHandles->Get(handle);
+  if (anInterrupt == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  anInterrupt->index = getHandleIndex(handle);
+  anInterrupt->callbackId = -1;
+
+  anInterrupt->watcher = watcher;
+
+  return handle;
+}
+void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
+                          int32_t* status) {
+  HAL_DisableInterrupts(interruptHandle, status);
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  interruptHandles->Free(interruptHandle);
+  if (anInterrupt == nullptr) {
+    return nullptr;
+  }
+  return anInterrupt->callbackParam;
+}
+
+static void ProcessInterruptDigitalSynchronous(const char* name, void* param,
+                                               const struct HAL_Value* value) {
+  // void* is a SynchronousWaitDataHandle.
+  // convert to uintptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  SynchronousWaitDataHandle handle =
+      static_cast<SynchronousWaitDataHandle>(handleTmp);
+  auto interruptData = synchronousInterruptHandles->Get(handle);
+  if (interruptData == nullptr) return;
+  auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_BOOLEAN) return;
+  bool retVal = value->data.v_boolean;
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  // If its a falling change, and we dont fire on falling return
+  if (interrupt->previousState && !interrupt->fireOnDown) return;
+  // If its a rising change, and we dont fire on rising return.
+  if (!interrupt->previousState && !interrupt->fireOnUp) return;
+
+  interruptData->waitPredicate = true;
+
+  // Pulse interrupt
+  interruptData->waitCond.notify_all();
+}
+
+static double GetAnalogTriggerValue(HAL_Handle triggerHandle,
+                                    HAL_AnalogTriggerType type,
+                                    int32_t* status) {
+  return HAL_GetAnalogTriggerOutput(triggerHandle, type, status);
+}
+
+static void ProcessInterruptAnalogSynchronous(const char* name, void* param,
+                                              const struct HAL_Value* value) {
+  // void* is a SynchronousWaitDataHandle.
+  // convert to uintptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  SynchronousWaitDataHandle handle =
+      static_cast<SynchronousWaitDataHandle>(handleTmp);
+  auto interruptData = synchronousInterruptHandles->Get(handle);
+  if (interruptData == nullptr) return;
+  auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_DOUBLE) return;
+  int32_t status = 0;
+  bool retVal = GetAnalogTriggerValue(interrupt->portHandle,
+                                      interrupt->trigType, &status);
+  if (status != 0) {
+    // Interrupt and Cancel
+    interruptData->waitPredicate = true;
+    // Pulse interrupt
+    interruptData->waitCond.notify_all();
+  }
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  // If its a falling change, and we dont fire on falling return
+  if (interrupt->previousState && !interrupt->fireOnDown) return;
+  // If its a rising change, and we dont fire on rising return.
+  if (!interrupt->previousState && !interrupt->fireOnUp) return;
+
+  interruptData->waitPredicate = true;
+
+  // Pulse interrupt
+  interruptData->waitCond.notify_all();
+}
+
+static int64_t WaitForInterruptDigital(HAL_InterruptHandle handle,
+                                       Interrupt* interrupt, double timeout,
+                                       bool ignorePrevious) {
+  auto data = std::make_shared<SynchronousWaitData>();
+
+  auto dataHandle = synchronousInterruptHandles->Allocate(data);
+  if (dataHandle == HAL_kInvalidHandle) {
+    // Error allocating data
+    return WaitResult::Timeout;
+  }
+
+  // auto data = synchronousInterruptHandles->Get(dataHandle);
+  data->waitPredicate = false;
+  data->interruptHandle = handle;
+
+  int32_t status = 0;
+
+  int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
+
+  if (status != 0) return WaitResult::Timeout;
+
+  interrupt->previousState = SimDIOData[digitalIndex].value;
+
+  int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
+      &ProcessInterruptDigitalSynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(dataHandle)), false);
+
+  bool timedOut = false;
+
+  wpi::mutex waitMutex;
+
+  auto timeoutTime =
+      std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
+
+  {
+    std::unique_lock<wpi::mutex> lock(waitMutex);
+    while (!data->waitPredicate) {
+      if (data->waitCond.wait_until(lock, timeoutTime) ==
+          std::cv_status::timeout) {
+        timedOut = true;
+        break;
+      }
+    }
+  }
+
+  // Cancel our callback
+  SimDIOData[digitalIndex].value.CancelCallback(uid);
+  synchronousInterruptHandles->Free(dataHandle);
+
+  // Check for what to return
+  if (timedOut) return WaitResult::Timeout;
+  // True => false, Falling
+  if (interrupt->previousState) {
+    // Set our return value and our timestamps
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    return 1 << (8 + interrupt->index);
+  } else {
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    return 1 << (interrupt->index);
+  }
+}
+
+static int64_t WaitForInterruptAnalog(HAL_InterruptHandle handle,
+                                      Interrupt* interrupt, double timeout,
+                                      bool ignorePrevious) {
+  auto data = std::make_shared<SynchronousWaitData>();
+
+  auto dataHandle = synchronousInterruptHandles->Allocate(data);
+  if (dataHandle == HAL_kInvalidHandle) {
+    // Error allocating data
+    return WaitResult::Timeout;
+  }
+
+  data->waitPredicate = false;
+  data->interruptHandle = handle;
+
+  int32_t status = 0;
+  interrupt->previousState = GetAnalogTriggerValue(
+      interrupt->portHandle, interrupt->trigType, &status);
+
+  if (status != 0) return WaitResult::Timeout;
+
+  int32_t analogIndex =
+      GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
+
+  if (status != 0) return WaitResult::Timeout;
+
+  int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
+      &ProcessInterruptAnalogSynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(dataHandle)), false);
+
+  bool timedOut = false;
+
+  wpi::mutex waitMutex;
+
+  auto timeoutTime =
+      std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
+
+  {
+    std::unique_lock<wpi::mutex> lock(waitMutex);
+    while (!data->waitPredicate) {
+      if (data->waitCond.wait_until(lock, timeoutTime) ==
+          std::cv_status::timeout) {
+        timedOut = true;
+        break;
+      }
+    }
+  }
+
+  // Cancel our callback
+  SimAnalogInData[analogIndex].voltage.CancelCallback(uid);
+  synchronousInterruptHandles->Free(dataHandle);
+
+  // Check for what to return
+  if (timedOut) return WaitResult::Timeout;
+  // True => false, Falling
+  if (interrupt->previousState) {
+    // Set our return value and our timestamps
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    return 1 << (8 + interrupt->index);
+  } else {
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    return 1 << (interrupt->index);
+  }
+}
+
+int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
+                             double timeout, HAL_Bool ignorePrevious,
+                             int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return WaitResult::Timeout;
+  }
+
+  // Check to make sure we are actually an interrupt in synchronous mode
+  if (!interrupt->watcher) {
+    *status = NiFpga_Status_InvalidParameter;
+    return WaitResult::Timeout;
+  }
+
+  if (interrupt->isAnalog) {
+    return WaitForInterruptAnalog(interruptHandle, interrupt.get(), timeout,
+                                  ignorePrevious);
+  } else {
+    return WaitForInterruptDigital(interruptHandle, interrupt.get(), timeout,
+                                   ignorePrevious);
+  }
+}
+
+static void ProcessInterruptDigitalAsynchronous(const char* name, void* param,
+                                                const struct HAL_Value* value) {
+  // void* is a HAL handle
+  // convert to uintptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
+  auto interrupt = interruptHandles->Get(handle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_BOOLEAN) return;
+  bool retVal = value->data.v_boolean;
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  int32_t mask = 0;
+  if (interrupt->previousState) {
+    interrupt->previousState = retVal;
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    mask = 1 << (8 + interrupt->index);
+    if (!interrupt->fireOnDown) return;
+  } else {
+    interrupt->previousState = retVal;
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    mask = 1 << (interrupt->index);
+    if (!interrupt->fireOnUp) return;
+  }
+
+  // run callback
+  auto callback = interrupt->callbackFunction;
+  if (callback == nullptr) return;
+  callback(mask, interrupt->callbackParam);
+}
+
+static void ProcessInterruptAnalogAsynchronous(const char* name, void* param,
+                                               const struct HAL_Value* value) {
+  // void* is a HAL handle
+  // convert to intptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
+  auto interrupt = interruptHandles->Get(handle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_DOUBLE) return;
+  int32_t status = 0;
+  bool retVal = GetAnalogTriggerValue(interrupt->portHandle,
+                                      interrupt->trigType, &status);
+  if (status != 0) return;
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  int mask = 0;
+  if (interrupt->previousState) {
+    interrupt->previousState = retVal;
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    if (!interrupt->fireOnDown) return;
+    mask = 1 << (8 + interrupt->index);
+  } else {
+    interrupt->previousState = retVal;
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    if (!interrupt->fireOnUp) return;
+    mask = 1 << (interrupt->index);
+  }
+
+  // run callback
+  auto callback = interrupt->callbackFunction;
+  if (callback == nullptr) return;
+  callback(mask, interrupt->callbackParam);
+}
+
+static void EnableInterruptsDigital(HAL_InterruptHandle handle,
+                                    Interrupt* interrupt) {
+  int32_t status = 0;
+  int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
+  if (status != 0) return;
+
+  interrupt->previousState = SimDIOData[digitalIndex].value;
+
+  int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
+      &ProcessInterruptDigitalAsynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
+  interrupt->callbackId = uid;
+}
+
+static void EnableInterruptsAnalog(HAL_InterruptHandle handle,
+                                   Interrupt* interrupt) {
+  int32_t status = 0;
+  int32_t analogIndex =
+      GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
+  if (status != 0) return;
+
+  status = 0;
+  interrupt->previousState = GetAnalogTriggerValue(
+      interrupt->portHandle, interrupt->trigType, &status);
+  if (status != 0) return;
+
+  int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
+      &ProcessInterruptAnalogAsynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
+  interrupt->callbackId = uid;
+}
+
+void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
+                          int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // If we have not had a callback set, error out
+  if (interrupt->callbackFunction == nullptr) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  // EnableInterrupts has already been called
+  if (interrupt->callbackId >= 0) {
+    // We can double enable safely.
+    return;
+  }
+
+  if (interrupt->isAnalog) {
+    EnableInterruptsAnalog(interruptHandle, interrupt.get());
+  } else {
+    EnableInterruptsDigital(interruptHandle, interrupt.get());
+  }
+}
+void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
+                           int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // No need to disable if we are already disabled
+  if (interrupt->callbackId < 0) return;
+
+  if (interrupt->isAnalog) {
+    // Do analog
+    int32_t status = 0;
+    int32_t analogIndex =
+        GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
+    if (status != 0) return;
+    SimAnalogInData[analogIndex].voltage.CancelCallback(interrupt->callbackId);
+  } else {
+    int32_t status = 0;
+    int32_t digitalIndex =
+        GetDigitalInputChannel(interrupt->portHandle, &status);
+    if (status != 0) return;
+    SimDIOData[digitalIndex].value.CancelCallback(interrupt->callbackId);
+  }
+  interrupt->callbackId = -1;
+}
+int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
+                                         int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return interrupt->risingTimestamp;
+}
+int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
+                                          int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return interrupt->fallingTimestamp;
+}
+void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
+                           HAL_Handle digitalSourceHandle,
+                           HAL_AnalogTriggerType analogTriggerType,
+                           int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  bool routingAnalogTrigger = false;
+  uint8_t routingChannel = 0;
+  uint8_t routingModule = 0;
+  bool success =
+      remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
+                         routingModule, routingAnalogTrigger);
+  if (!success) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  interrupt->isAnalog = routingAnalogTrigger;
+  interrupt->trigType = analogTriggerType;
+  interrupt->portHandle = digitalSourceHandle;
+}
+void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
+                                HAL_InterruptHandlerFunction handler,
+                                void* param, int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  interrupt->callbackFunction = handler;
+  interrupt->callbackParam = param;
+}
+
+void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
+                                        HAL_InterruptHandlerFunction handler,
+                                        void* param, int32_t* status) {
+  HAL_AttachInterruptHandler(interruptHandle, handler, param, status);
+}
+
+void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
+                                  HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                  int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  interrupt->fireOnDown = fallingEdge;
+  interrupt->fireOnUp = risingEdge;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/MockHooks.cpp b/hal/src/main/native/sim/MockHooks.cpp
new file mode 100644
index 0000000..25c1d9f
--- /dev/null
+++ b/hal/src/main/native/sim/MockHooks.cpp
@@ -0,0 +1,59 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <atomic>
+#include <chrono>
+#include <cstdio>
+#include <thread>
+
+#include <wpi/timestamp.h>
+
+#include "MockHooksInternal.h"
+
+static std::atomic<bool> programStarted{false};
+
+static std::atomic<uint64_t> programStartTime{0};
+
+namespace hal {
+namespace init {
+void InitializeMockHooks() {}
+}  // namespace init
+}  // namespace hal
+
+namespace hal {
+void RestartTiming() { programStartTime = wpi::Now(); }
+
+int64_t GetFPGATime() {
+  auto now = wpi::Now();
+  auto currentTime = now - programStartTime;
+  return currentTime;
+}
+
+double GetFPGATimestamp() { return GetFPGATime() * 1.0e-6; }
+
+void SetProgramStarted() { programStarted = true; }
+bool GetProgramStarted() { return programStarted; }
+}  // namespace hal
+
+using namespace hal;
+
+extern "C" {
+void HALSIM_WaitForProgramStart(void) {
+  int count = 0;
+  while (!programStarted) {
+    count++;
+    std::printf("Waiting for program start signal: %d\n", count);
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+  }
+}
+
+void HALSIM_SetProgramStarted(void) { SetProgramStarted(); }
+
+HAL_Bool HALSIM_GetProgramStarted(void) { return GetProgramStarted(); }
+
+void HALSIM_RestartTiming(void) { RestartTiming(); }
+}  // extern "C"
diff --git a/hal/src/main/native/sim/MockHooksInternal.h b/hal/src/main/native/sim/MockHooksInternal.h
new file mode 100644
index 0000000..e8c09a9
--- /dev/null
+++ b/hal/src/main/native/sim/MockHooksInternal.h
@@ -0,0 +1,22 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+#include "mockdata/MockHooks.h"
+
+namespace hal {
+void RestartTiming();
+
+int64_t GetFPGATime();
+
+double GetFPGATimestamp();
+
+void SetProgramStarted();
+}  // namespace hal
diff --git a/hal/src/main/native/sim/Notifier.cpp b/hal/src/main/native/sim/Notifier.cpp
new file mode 100644
index 0000000..9f549d5
--- /dev/null
+++ b/hal/src/main/native/sim/Notifier.cpp
@@ -0,0 +1,159 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Notifier.h"
+
+#include <chrono>
+
+#include <wpi/condition_variable.h>
+#include <wpi/mutex.h>
+#include <wpi/timestamp.h>
+
+#include "HALInitializer.h"
+#include "hal/HAL.h"
+#include "hal/cpp/fpga_clock.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+
+namespace {
+struct Notifier {
+  uint64_t waitTime;
+  bool updatedAlarm = false;
+  bool active = true;
+  bool running = false;
+  wpi::mutex mutex;
+  wpi::condition_variable cond;
+};
+}  // namespace
+
+using namespace hal;
+
+class NotifierHandleContainer
+    : public UnlimitedHandleResource<HAL_NotifierHandle, Notifier,
+                                     HAL_HandleEnum::Notifier> {
+ public:
+  ~NotifierHandleContainer() {
+    ForEach([](HAL_NotifierHandle handle, Notifier* notifier) {
+      {
+        std::lock_guard<wpi::mutex> lock(notifier->mutex);
+        notifier->active = false;
+        notifier->running = false;
+      }
+      notifier->cond.notify_all();  // wake up any waiting threads
+    });
+  }
+};
+
+static NotifierHandleContainer* notifierHandles;
+
+namespace hal {
+namespace init {
+void InitializeNotifier() {
+  static NotifierHandleContainer nH;
+  notifierHandles = &nH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_NotifierHandle HAL_InitializeNotifier(int32_t* status) {
+  hal::init::CheckInit();
+  std::shared_ptr<Notifier> notifier = std::make_shared<Notifier>();
+  HAL_NotifierHandle handle = notifierHandles->Allocate(notifier);
+  if (handle == HAL_kInvalidHandle) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  return handle;
+}
+
+void HAL_StopNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return;
+
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->active = false;
+    notifier->running = false;
+  }
+  notifier->cond.notify_all();
+}
+
+void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) {
+  auto notifier = notifierHandles->Free(notifierHandle);
+  if (!notifier) return;
+
+  // Just in case HAL_StopNotifier() wasn't called...
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->active = false;
+    notifier->running = false;
+  }
+  notifier->cond.notify_all();
+}
+
+void HAL_UpdateNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                             uint64_t triggerTime, int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return;
+
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->waitTime = triggerTime;
+    notifier->running = true;
+    notifier->updatedAlarm = true;
+  }
+
+  // We wake up any waiters to change how long they're sleeping for
+  notifier->cond.notify_all();
+}
+
+void HAL_CancelNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                             int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return;
+
+  {
+    std::lock_guard<wpi::mutex> lock(notifier->mutex);
+    notifier->running = false;
+  }
+}
+
+uint64_t HAL_WaitForNotifierAlarm(HAL_NotifierHandle notifierHandle,
+                                  int32_t* status) {
+  auto notifier = notifierHandles->Get(notifierHandle);
+  if (!notifier) return 0;
+
+  std::unique_lock<wpi::mutex> lock(notifier->mutex);
+  while (notifier->active) {
+    double waitTime;
+    if (!notifier->running) {
+      waitTime = (HAL_GetFPGATime(status) * 1e-6) + 1000.0;
+      // If not running, wait 1000 seconds
+    } else {
+      waitTime = notifier->waitTime * 1e-6;
+    }
+
+    // Don't wait twice
+    notifier->updatedAlarm = false;
+
+    auto timeoutTime =
+        hal::fpga_clock::epoch() + std::chrono::duration<double>(waitTime);
+    notifier->cond.wait_until(lock, timeoutTime);
+    if (notifier->updatedAlarm) {
+      notifier->updatedAlarm = false;
+      continue;
+    }
+    if (!notifier->running) continue;
+    if (!notifier->active) break;
+    notifier->running = false;
+    return HAL_GetFPGATime(status);
+  }
+  return 0;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/PDP.cpp b/hal/src/main/native/sim/PDP.cpp
new file mode 100644
index 0000000..07f4dcd
--- /dev/null
+++ b/hal/src/main/native/sim/PDP.cpp
@@ -0,0 +1,92 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/PDP.h"
+
+#include "CANAPIInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/CANAPI.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "mockdata/PDPDataInternal.h"
+
+using namespace hal;
+
+static constexpr HAL_CANManufacturer manufacturer =
+    HAL_CANManufacturer::HAL_CAN_Man_kCTRE;
+
+static constexpr HAL_CANDeviceType deviceType =
+    HAL_CANDeviceType::HAL_CAN_Dev_kPowerDistribution;
+
+namespace hal {
+namespace init {
+void InitializePDP() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status) {
+  if (!HAL_CheckPDPModule(module)) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+  hal::init::CheckInit();
+  SimPDPData[module].initialized = true;
+  auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
+
+  if (*status != 0) {
+    HAL_CleanCAN(handle);
+    return HAL_kInvalidHandle;
+  }
+
+  return handle;
+}
+
+HAL_Bool HAL_CheckPDPModule(int32_t module) {
+  return module < kNumPDPModules && module >= 0;
+}
+
+HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
+  return channel < kNumPDPChannels && channel >= 0;
+}
+
+void HAL_CleanPDP(HAL_PDPHandle handle) { HAL_CleanCAN(handle); }
+
+double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return 0.0;
+  }
+  return SimPDPData[module].temperature;
+}
+double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return 0.0;
+  }
+  return SimPDPData[module].voltage;
+}
+double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
+                                int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return 0.0;
+  }
+  return SimPDPData[module].current[channel];
+}
+double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
+  return 0.0;
+}
+double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
+  return 0.0;
+}
+double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
+  return 0.0;
+}
+void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {}
+void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/PWM.cpp b/hal/src/main/native/sim/PWM.cpp
new file mode 100644
index 0000000..228b540
--- /dev/null
+++ b/hal/src/main/native/sim/PWM.cpp
@@ -0,0 +1,302 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/PWM.h"
+
+#include "ConstantsInternal.h"
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/PWMDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializePWM() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+
+HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  uint8_t origChannel = static_cast<uint8_t>(channel);
+
+  if (origChannel < kNumPWMHeaders) {
+    channel += kNumDigitalChannels;  // remap Headers to end of allocations
+  } else {
+    channel = remapMXPPWMChannel(channel) + 10;  // remap MXP to proper channel
+  }
+
+  auto handle =
+      digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  port->channel = origChannel;
+
+  SimPWMData[origChannel].initialized = true;
+
+  // Defaults to allow an always valid config.
+  HAL_SetPWMConfig(handle, 2.0, 1.501, 1.5, 1.499, 1.0, status);
+
+  return handle;
+}
+void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimPWMData[port->channel].initialized = false;
+
+  digitalChannelHandles->Free(pwmPortHandle, HAL_HandleEnum::PWM);
+}
+
+HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
+  return channel < kNumPWMChannels && channel >= 0;
+}
+
+void HAL_SetPWMConfig(HAL_DigitalHandle pwmPortHandle, double max,
+                      double deadbandMax, double center, double deadbandMin,
+                      double min, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // calculate the loop time in milliseconds
+  double loopTime =
+      HAL_GetPWMLoopTiming(status) / (kSystemClockTicksPerMicrosecond * 1e3);
+  if (*status != 0) return;
+
+  int32_t maxPwm = static_cast<int32_t>((max - kDefaultPwmCenter) / loopTime +
+                                        kDefaultPwmStepsDown - 1);
+  int32_t deadbandMaxPwm = static_cast<int32_t>(
+      (deadbandMax - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
+  int32_t centerPwm = static_cast<int32_t>(
+      (center - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
+  int32_t deadbandMinPwm = static_cast<int32_t>(
+      (deadbandMin - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
+  int32_t minPwm = static_cast<int32_t>((min - kDefaultPwmCenter) / loopTime +
+                                        kDefaultPwmStepsDown - 1);
+
+  port->maxPwm = maxPwm;
+  port->deadbandMaxPwm = deadbandMaxPwm;
+  port->deadbandMinPwm = deadbandMinPwm;
+  port->centerPwm = centerPwm;
+  port->minPwm = minPwm;
+  port->configSet = true;
+}
+
+void HAL_SetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t maxPwm,
+                         int32_t deadbandMaxPwm, int32_t centerPwm,
+                         int32_t deadbandMinPwm, int32_t minPwm,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  port->maxPwm = maxPwm;
+  port->deadbandMaxPwm = deadbandMaxPwm;
+  port->deadbandMinPwm = deadbandMinPwm;
+  port->centerPwm = centerPwm;
+  port->minPwm = minPwm;
+}
+
+void HAL_GetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t* maxPwm,
+                         int32_t* deadbandMaxPwm, int32_t* centerPwm,
+                         int32_t* deadbandMinPwm, int32_t* minPwm,
+                         int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  *maxPwm = port->maxPwm;
+  *deadbandMaxPwm = port->deadbandMaxPwm;
+  *deadbandMinPwm = port->deadbandMinPwm;
+  *centerPwm = port->centerPwm;
+  *minPwm = port->minPwm;
+}
+
+void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
+                                 HAL_Bool eliminateDeadband, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  port->eliminateDeadband = eliminateDeadband;
+}
+
+HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
+                                     int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  return port->eliminateDeadband;
+}
+
+void HAL_SetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t value,
+                   int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimPWMData[port->channel].rawValue = value;
+}
+
+void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
+                     int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  if (speed < -1.0) {
+    speed = -1.0;
+  } else if (speed > 1.0) {
+    speed = 1.0;
+  }
+
+  SimPWMData[port->channel].speed = speed;
+}
+
+void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
+                        int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  if (pos < 0.0) {
+    pos = 0.0;
+  } else if (pos > 1.0) {
+    pos = 1.0;
+  }
+
+  SimPWMData[port->channel].position = pos;
+}
+
+void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  SimPWMData[port->channel].rawValue = 0;
+  SimPWMData[port->channel].position = 0;
+  SimPWMData[port->channel].speed = 0;
+}
+
+int32_t HAL_GetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimPWMData[port->channel].rawValue;
+}
+
+double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return 0;
+  }
+
+  double speed = SimPWMData[port->channel].speed;
+  if (speed > 1) speed = 1;
+  if (speed < -1) speed = -1;
+  return speed;
+}
+
+double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+  if (!port->configSet) {
+    *status = INCOMPATIBLE_STATE;
+    return 0;
+  }
+
+  double position = SimPWMData[port->channel].position;
+  if (position > 1) position = 1;
+  if (position < 0) position = 0;
+  return position;
+}
+
+void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimPWMData[port->channel].zeroLatch = true;
+  SimPWMData[port->channel].zeroLatch = false;
+}
+
+void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
+                           int32_t* status) {
+  auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimPWMData[port->channel].periodScale = squelchMask;
+}
+
+int32_t HAL_GetPWMLoopTiming(int32_t* status) { return kExpectedLoopTiming; }
+
+uint64_t HAL_GetPWMCycleStartTime(int32_t* status) { return 0; }
+}  // extern "C"
diff --git a/hal/src/main/native/sim/Ports.cpp b/hal/src/main/native/sim/Ports.cpp
new file mode 100644
index 0000000..f50304f
--- /dev/null
+++ b/hal/src/main/native/sim/Ports.cpp
@@ -0,0 +1,40 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Ports.h"
+
+#include "PortsInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializePorts() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+int32_t HAL_GetNumAccumulators(void) { return kNumAccumulators; }
+int32_t HAL_GetNumAnalogTriggers(void) { return kNumAnalogTriggers; }
+int32_t HAL_GetNumAnalogInputs(void) { return kNumAnalogInputs; }
+int32_t HAL_GetNumAnalogOutputs(void) { return kNumAnalogOutputs; }
+int32_t HAL_GetNumCounters(void) { return kNumCounters; }
+int32_t HAL_GetNumDigitalHeaders(void) { return kNumDigitalHeaders; }
+int32_t HAL_GetNumPWMHeaders(void) { return kNumPWMHeaders; }
+int32_t HAL_GetNumDigitalChannels(void) { return kNumDigitalChannels; }
+int32_t HAL_GetNumPWMChannels(void) { return kNumPWMChannels; }
+int32_t HAL_GetNumDigitalPWMOutputs(void) { return kNumDigitalPWMOutputs; }
+int32_t HAL_GetNumEncoders(void) { return kNumEncoders; }
+int32_t HAL_GetNumInterrupts(void) { return kNumInterrupts; }
+int32_t HAL_GetNumRelayChannels(void) { return kNumRelayChannels; }
+int32_t HAL_GetNumRelayHeaders(void) { return kNumRelayHeaders; }
+int32_t HAL_GetNumPCMModules(void) { return kNumPCMModules; }
+int32_t HAL_GetNumSolenoidChannels(void) { return kNumSolenoidChannels; }
+int32_t HAL_GetNumPDPModules(void) { return kNumPDPModules; }
+int32_t HAL_GetNumPDPChannels(void) { return kNumPDPChannels; }
+int32_t HAL_GetNumCanTalons(void) { return kNumCanTalons; }
+}  // extern "C"
diff --git a/hal/src/main/native/sim/PortsInternal.h b/hal/src/main/native/sim/PortsInternal.h
new file mode 100644
index 0000000..0b899f7
--- /dev/null
+++ b/hal/src/main/native/sim/PortsInternal.h
@@ -0,0 +1,32 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <stdint.h>
+
+namespace hal {
+constexpr int32_t kNumAccumulators = 2;
+constexpr int32_t kNumAnalogTriggers = 8;
+constexpr int32_t kNumAnalogInputs = 8;
+constexpr int32_t kNumAnalogOutputs = 2;
+constexpr int32_t kNumCounters = 8;
+constexpr int32_t kNumDigitalHeaders = 10;
+constexpr int32_t kNumPWMHeaders = 10;
+constexpr int32_t kNumDigitalChannels = 26;
+constexpr int32_t kNumPWMChannels = 20;
+constexpr int32_t kNumDigitalPWMOutputs = 6;
+constexpr int32_t kNumEncoders = 8;
+constexpr int32_t kNumInterrupts = 8;
+constexpr int32_t kNumRelayChannels = 8;
+constexpr int32_t kNumRelayHeaders = kNumRelayChannels / 2;
+constexpr int32_t kNumPCMModules = 63;
+constexpr int32_t kNumSolenoidChannels = 8;
+constexpr int32_t kNumPDPModules = 63;
+constexpr int32_t kNumPDPChannels = 16;
+constexpr int32_t kNumCanTalons = 63;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/Power.cpp b/hal/src/main/native/sim/Power.cpp
new file mode 100644
index 0000000..95bb3dd
--- /dev/null
+++ b/hal/src/main/native/sim/Power.cpp
@@ -0,0 +1,64 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Power.h"
+
+#include "mockdata/RoboRioDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializePower() {}
+}  // namespace init
+}  // namespace hal
+
+// TODO: Fix the naming in here
+extern "C" {
+double HAL_GetVinVoltage(int32_t* status) {
+  return SimRoboRioData[0].vInVoltage;
+}
+double HAL_GetVinCurrent(int32_t* status) {
+  return SimRoboRioData[0].vInCurrent;
+}
+double HAL_GetUserVoltage6V(int32_t* status) {
+  return SimRoboRioData[0].userVoltage6V;
+}
+double HAL_GetUserCurrent6V(int32_t* status) {
+  return SimRoboRioData[0].userCurrent6V;
+}
+HAL_Bool HAL_GetUserActive6V(int32_t* status) {
+  return SimRoboRioData[0].userActive6V;
+}
+int32_t HAL_GetUserCurrentFaults6V(int32_t* status) {
+  return SimRoboRioData[0].userFaults6V;
+}
+double HAL_GetUserVoltage5V(int32_t* status) {
+  return SimRoboRioData[0].userVoltage5V;
+}
+double HAL_GetUserCurrent5V(int32_t* status) {
+  return SimRoboRioData[0].userCurrent5V;
+}
+HAL_Bool HAL_GetUserActive5V(int32_t* status) {
+  return SimRoboRioData[0].userActive5V;
+}
+int32_t HAL_GetUserCurrentFaults5V(int32_t* status) {
+  return SimRoboRioData[0].userFaults5V;
+}
+double HAL_GetUserVoltage3V3(int32_t* status) {
+  return SimRoboRioData[0].userVoltage3V3;
+}
+double HAL_GetUserCurrent3V3(int32_t* status) {
+  return SimRoboRioData[0].userCurrent3V3;
+}
+HAL_Bool HAL_GetUserActive3V3(int32_t* status) {
+  return SimRoboRioData[0].userActive3V3;
+}
+int32_t HAL_GetUserCurrentFaults3V3(int32_t* status) {
+  return SimRoboRioData[0].userFaults3V3;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/Relay.cpp b/hal/src/main/native/sim/Relay.cpp
new file mode 100644
index 0000000..bd1c8a8
--- /dev/null
+++ b/hal/src/main/native/sim/Relay.cpp
@@ -0,0 +1,121 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Relay.h"
+
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "mockdata/RelayDataInternal.h"
+
+using namespace hal;
+
+namespace {
+struct Relay {
+  uint8_t channel;
+  bool fwd;
+};
+}  // namespace
+
+static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
+                             HAL_HandleEnum::Relay>* relayHandles;
+
+namespace hal {
+namespace init {
+void InitializeRelay() {
+  static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
+                               HAL_HandleEnum::Relay>
+      rH;
+  relayHandles = &rH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+  if (*status != 0) return HAL_kInvalidHandle;
+
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  if (!fwd) channel += kNumRelayHeaders;  // add 4 to reverse channels
+
+  auto handle = relayHandles->Allocate(channel, status);
+
+  if (*status != 0)
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+
+  auto port = relayHandles->Get(handle);
+  if (port == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  if (!fwd) {
+    // Subtract number of headers to put channel in range
+    channel -= kNumRelayHeaders;
+
+    port->fwd = false;  // set to reverse
+
+    SimRelayData[channel].initializedReverse = true;
+  } else {
+    port->fwd = true;  // set to forward
+    SimRelayData[channel].initializedForward = true;
+  }
+
+  port->channel = static_cast<uint8_t>(channel);
+
+  return handle;
+}
+
+void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle) {
+  auto port = relayHandles->Get(relayPortHandle);
+  relayHandles->Free(relayPortHandle);
+  if (port == nullptr) return;
+  if (port->fwd)
+    SimRelayData[port->channel].initializedForward = false;
+  else
+    SimRelayData[port->channel].initializedReverse = false;
+}
+
+HAL_Bool HAL_CheckRelayChannel(int32_t channel) {
+  // roboRIO only has 4 headers, and the FPGA has
+  // seperate functions for forward and reverse,
+  // instead of seperate channel IDs
+  return channel < kNumRelayHeaders && channel >= 0;
+}
+
+void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
+                  int32_t* status) {
+  auto port = relayHandles->Get(relayPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+  if (port->fwd)
+    SimRelayData[port->channel].forward = on;
+  else
+    SimRelayData[port->channel].reverse = on;
+}
+
+HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status) {
+  auto port = relayHandles->Get(relayPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+  if (port->fwd)
+    return SimRelayData[port->channel].forward;
+  else
+    return SimRelayData[port->channel].reverse;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/SPI.cpp b/hal/src/main/native/sim/SPI.cpp
new file mode 100644
index 0000000..8c539d3
--- /dev/null
+++ b/hal/src/main/native/sim/SPI.cpp
@@ -0,0 +1,65 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/SPI.h"
+
+#include "HALInitializer.h"
+#include "mockdata/SPIDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeSPI() {}
+}  // namespace init
+}  // namespace hal
+
+void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
+  hal::init::CheckInit();
+  SimSPIData[port].initialized = true;
+}
+int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend,
+                           uint8_t* dataReceived, int32_t size) {
+  return SimSPIData[port].Transaction(dataToSend, dataReceived, size);
+}
+int32_t HAL_WriteSPI(HAL_SPIPort port, const uint8_t* dataToSend,
+                     int32_t sendSize) {
+  return SimSPIData[port].Write(dataToSend, sendSize);
+}
+int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count) {
+  return SimSPIData[port].Read(buffer, count);
+}
+void HAL_CloseSPI(HAL_SPIPort port) { SimSPIData[port].initialized = false; }
+void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed) {}
+void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
+                    HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh) {}
+void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status) {}
+void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status) {}
+int32_t HAL_GetSPIHandle(HAL_SPIPort port) { return 0; }
+void HAL_SetSPIHandle(HAL_SPIPort port, int32_t handle) {}
+
+void HAL_InitSPIAuto(HAL_SPIPort port, int32_t bufferSize, int32_t* status) {}
+void HAL_FreeSPIAuto(HAL_SPIPort port, int32_t* status) {}
+void HAL_StartSPIAutoRate(HAL_SPIPort port, double period, int32_t* status) {}
+void HAL_StartSPIAutoTrigger(HAL_SPIPort port, HAL_Handle digitalSourceHandle,
+                             HAL_AnalogTriggerType analogTriggerType,
+                             HAL_Bool triggerRising, HAL_Bool triggerFalling,
+                             int32_t* status) {}
+void HAL_StopSPIAuto(HAL_SPIPort port, int32_t* status) {}
+void HAL_SetSPIAutoTransmitData(HAL_SPIPort port, const uint8_t* dataToSend,
+                                int32_t dataSize, int32_t zeroSize,
+                                int32_t* status) {}
+void HAL_ForceSPIAutoRead(HAL_SPIPort port, int32_t* status) {}
+int32_t HAL_ReadSPIAutoReceivedData(HAL_SPIPort port, uint32_t* buffer,
+                                    int32_t numToRead, double timeout,
+                                    int32_t* status) {
+  return SimSPIData[port].ReadAutoReceivedData(buffer, numToRead, timeout,
+                                               status);
+}
+int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status) {
+  return 0;
+}
diff --git a/hal/src/main/native/sim/SerialPort.cpp b/hal/src/main/native/sim/SerialPort.cpp
new file mode 100644
index 0000000..bc08566
--- /dev/null
+++ b/hal/src/main/native/sim/SerialPort.cpp
@@ -0,0 +1,77 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/SerialPort.h"
+
+#include "HALInitializer.h"
+
+namespace hal {
+namespace init {
+void InitializeSerialPort() {}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+void HAL_InitializeSerialPort(HAL_SerialPort port, int32_t* status) {
+  hal::init::CheckInit();
+}
+
+void HAL_InitializeSerialPortDirect(HAL_SerialPort port, const char* portName,
+                                    int32_t* status) {}
+
+void HAL_SetSerialBaudRate(HAL_SerialPort port, int32_t baud, int32_t* status) {
+}
+
+void HAL_SetSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status) {
+}
+
+void HAL_SetSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status) {
+}
+
+void HAL_SetSerialStopBits(HAL_SerialPort port, int32_t stopBits,
+                           int32_t* status) {}
+
+void HAL_SetSerialWriteMode(HAL_SerialPort port, int32_t mode,
+                            int32_t* status) {}
+
+void HAL_SetSerialFlowControl(HAL_SerialPort port, int32_t flow,
+                              int32_t* status) {}
+
+void HAL_SetSerialTimeout(HAL_SerialPort port, double timeout,
+                          int32_t* status) {}
+
+void HAL_EnableSerialTermination(HAL_SerialPort port, 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,
+                                  int32_t* status) {}
+
+int32_t HAL_GetSerialBytesReceived(HAL_SerialPort port, int32_t* status) {
+  return 0;
+}
+
+int32_t HAL_ReadSerial(HAL_SerialPort port, 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) {
+  return 0;
+}
+
+void HAL_FlushSerial(HAL_SerialPort port, int32_t* status) {}
+
+void HAL_ClearSerial(HAL_SerialPort port, int32_t* status) {}
+
+void HAL_CloseSerial(HAL_SerialPort port, int32_t* status) {}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/Solenoid.cpp b/hal/src/main/native/sim/Solenoid.cpp
new file mode 100644
index 0000000..d3f0c5d
--- /dev/null
+++ b/hal/src/main/native/sim/Solenoid.cpp
@@ -0,0 +1,136 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Solenoid.h"
+
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "mockdata/PCMDataInternal.h"
+
+namespace {
+struct Solenoid {
+  uint8_t module;
+  uint8_t channel;
+};
+}  // namespace
+
+using namespace hal;
+
+static IndexedHandleResource<HAL_SolenoidHandle, Solenoid,
+                             kNumPCMModules * kNumSolenoidChannels,
+                             HAL_HandleEnum::Solenoid>* solenoidHandles;
+
+namespace hal {
+namespace init {
+void InitializeSolenoid() {
+  static IndexedHandleResource<HAL_SolenoidHandle, Solenoid,
+                               kNumPCMModules * kNumSolenoidChannels,
+                               HAL_HandleEnum::Solenoid>
+      sH;
+  solenoidHandles = &sH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle,
+                                              int32_t* status) {
+  hal::init::CheckInit();
+  int16_t channel = getPortHandleChannel(portHandle);
+  int16_t module = getPortHandleModule(portHandle);
+  if (channel == InvalidHandleIndex) {
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  if (!HAL_CheckSolenoidChannel(channel)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  if (!HAL_CheckSolenoidModule(module)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  auto handle = solenoidHandles->Allocate(
+      module * kNumSolenoidChannels + channel, status);
+  if (handle == HAL_kInvalidHandle) {  // out of resources
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto solenoidPort = solenoidHandles->Get(handle);
+  if (solenoidPort == nullptr) {  // would only occur on thread issues
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+  solenoidPort->module = static_cast<uint8_t>(module);
+  solenoidPort->channel = static_cast<uint8_t>(channel);
+
+  HALSIM_SetPCMSolenoidInitialized(module, channel, true);
+
+  return handle;
+}
+void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle) {
+  auto port = solenoidHandles->Get(solenoidPortHandle);
+  if (port == nullptr) return;
+  solenoidHandles->Free(solenoidPortHandle);
+  HALSIM_SetPCMSolenoidInitialized(port->module, port->channel, false);
+}
+HAL_Bool HAL_CheckSolenoidModule(int32_t module) {
+  return module < kNumPCMModules && module >= 0;
+}
+
+HAL_Bool HAL_CheckSolenoidChannel(int32_t channel) {
+  return channel < kNumSolenoidChannels && channel >= 0;
+}
+HAL_Bool HAL_GetSolenoid(HAL_SolenoidHandle solenoidPortHandle,
+                         int32_t* status) {
+  auto port = solenoidHandles->Get(solenoidPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return HALSIM_GetPCMSolenoidOutput(port->module, port->channel);
+}
+int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status) {
+  int32_t total = 0;
+  for (int i = 0; i < kNumSolenoidChannels; i++) {
+    int32_t channel = HALSIM_GetPCMSolenoidOutput(module, i) ? 1 : 0;
+    total = total + (channel << i);
+  }
+
+  return total;
+}
+void HAL_SetSolenoid(HAL_SolenoidHandle solenoidPortHandle, HAL_Bool value,
+                     int32_t* status) {
+  auto port = solenoidHandles->Get(solenoidPortHandle);
+  if (port == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  HALSIM_SetPCMSolenoidOutput(port->module, port->channel, value);
+}
+int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status) {
+  return 0;
+}
+HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status) {
+  return 0;
+}
+HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status) {
+  return 0;
+}
+void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status) {}
+void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
+                            int32_t durMS, int32_t* status) {}
+void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status) {}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/Threads.cpp b/hal/src/main/native/sim/Threads.cpp
new file mode 100644
index 0000000..2aa2c4b
--- /dev/null
+++ b/hal/src/main/native/sim/Threads.cpp
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Threads.h"
+
+namespace hal {
+namespace init {
+void InitializeThreads() {}
+}  // namespace init
+}  // namespace hal
+
+int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
+                              int32_t* status) {
+  return 0;
+}
+int32_t HAL_GetCurrentThreadPriority(HAL_Bool* isRealTime, int32_t* status) {
+  return 0;
+}
+HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
+                               int32_t priority, int32_t* status) {
+  return true;
+}
+HAL_Bool HAL_SetCurrentThreadPriority(HAL_Bool realTime, int32_t priority,
+                                      int32_t* status) {
+  return true;
+}
diff --git a/hal/src/main/native/sim/jni/AccelerometerDataJNI.cpp b/hal/src/main/native/sim/jni/AccelerometerDataJNI.cpp
new file mode 100644
index 0000000..8964a41
--- /dev/null
+++ b/hal/src/main/native/sim/jni/AccelerometerDataJNI.cpp
@@ -0,0 +1,279 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI.h"
+#include "mockdata/AccelerometerData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    registerActiveCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_registerActiveCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAccelerometerActiveCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    cancelActiveCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_cancelActiveCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAccelerometerActiveCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    getActive
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_getActive
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAccelerometerActive(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    setActive
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_setActive
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetAccelerometerActive(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    registerRangeCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_registerRangeCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAccelerometerRangeCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    cancelRangeCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_cancelRangeCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAccelerometerRangeCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    getRange
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_getRange
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAccelerometerRange(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    setRange
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_setRange
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetAccelerometerRange(index,
+                               static_cast<HAL_AccelerometerRange>(value));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    registerXCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_registerXCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAccelerometerXCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    cancelXCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_cancelXCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAccelerometerXCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    getX
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_getX
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAccelerometerX(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    setX
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_setX
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAccelerometerX(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    registerYCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_registerYCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAccelerometerYCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    cancelYCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_cancelYCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAccelerometerYCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    getY
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_getY
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAccelerometerY(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    setY
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_setY
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAccelerometerY(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    registerZCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_registerZCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAccelerometerZCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    cancelZCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_cancelZCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAccelerometerZCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    getZ
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_getZ
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAccelerometerZ(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    setZ
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_setZ
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAccelerometerZ(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AccelerometerDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetAccelerometerData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/AnalogGyroDataJNI.cpp b/hal/src/main/native/sim/jni/AnalogGyroDataJNI.cpp
new file mode 100644
index 0000000..08d18de
--- /dev/null
+++ b/hal/src/main/native/sim/jni/AnalogGyroDataJNI.cpp
@@ -0,0 +1,178 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI.h"
+#include "mockdata/AnalogGyroData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    registerAngleCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_registerAngleCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogGyroAngleCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    cancelAngleCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_cancelAngleCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogGyroAngleCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    getAngle
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_getAngle
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogGyroAngle(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    setAngle
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_setAngle
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAnalogGyroAngle(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    registerRateCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_registerRateCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogGyroRateCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    cancelRateCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_cancelRateCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogGyroRateCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    getRate
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_getRate
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogGyroRate(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    setRate
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_setRate
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAnalogGyroRate(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogGyroInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogGyroInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogGyroInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetAnalogGyroInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogGyroDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetAnalogGyroData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/AnalogInDataJNI.cpp b/hal/src/main/native/sim/jni/AnalogInDataJNI.cpp
new file mode 100644
index 0000000..c6cee7b
--- /dev/null
+++ b/hal/src/main/native/sim/jni/AnalogInDataJNI.cpp
@@ -0,0 +1,483 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI.h"
+#include "mockdata/AnalogInData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogInInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetAnalogInInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerAverageBitsCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerAverageBitsCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogInAverageBitsCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelAverageBitsCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelAverageBitsCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInAverageBitsCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getAverageBits
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getAverageBits
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInAverageBits(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setAverageBits
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setAverageBits
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetAnalogInAverageBits(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerOversampleBitsCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerOversampleBitsCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogInOversampleBitsCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelOversampleBitsCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelOversampleBitsCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInOversampleBitsCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getOversampleBits
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getOversampleBits
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInOversampleBits(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setOversampleBits
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setOversampleBits
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetAnalogInOversampleBits(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerVoltageCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerVoltageCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogInVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelVoltageCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelVoltageCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getVoltage
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInVoltage(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setVoltage
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setVoltage
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAnalogInVoltage(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerAccumulatorInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerAccumulatorInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogInAccumulatorInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelAccumulatorInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelAccumulatorInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(
+      env, handle, index, &HALSIM_CancelAnalogInAccumulatorInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getAccumulatorInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getAccumulatorInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInAccumulatorInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setAccumulatorInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setAccumulatorInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetAnalogInAccumulatorInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerAccumulatorValueCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerAccumulatorValueCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogInAccumulatorValueCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelAccumulatorValueCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelAccumulatorValueCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInAccumulatorValueCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getAccumulatorValue
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getAccumulatorValue
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInAccumulatorValue(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setAccumulatorValue
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setAccumulatorValue
+  (JNIEnv*, jclass, jint index, jlong value)
+{
+  HALSIM_SetAnalogInAccumulatorValue(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerAccumulatorCountCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerAccumulatorCountCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogInAccumulatorCountCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelAccumulatorCountCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelAccumulatorCountCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInAccumulatorCountCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getAccumulatorCount
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getAccumulatorCount
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInAccumulatorCount(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setAccumulatorCount
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setAccumulatorCount
+  (JNIEnv*, jclass, jint index, jlong value)
+{
+  HALSIM_SetAnalogInAccumulatorCount(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerAccumulatorCenterCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerAccumulatorCenterCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogInAccumulatorCenterCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelAccumulatorCenterCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelAccumulatorCenterCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInAccumulatorCenterCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getAccumulatorCenter
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getAccumulatorCenter
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInAccumulatorCenter(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setAccumulatorCenter
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setAccumulatorCenter
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetAnalogInAccumulatorCenter(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    registerAccumulatorDeadbandCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_registerAccumulatorDeadbandCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogInAccumulatorDeadbandCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    cancelAccumulatorDeadbandCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_cancelAccumulatorDeadbandCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogInAccumulatorDeadbandCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    getAccumulatorDeadband
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_getAccumulatorDeadband
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogInAccumulatorDeadband(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    setAccumulatorDeadband
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_setAccumulatorDeadband
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetAnalogInAccumulatorDeadband(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogInDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetAnalogInData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/AnalogOutDataJNI.cpp b/hal/src/main/native/sim/jni/AnalogOutDataJNI.cpp
new file mode 100644
index 0000000..af9d6d6
--- /dev/null
+++ b/hal/src/main/native/sim/jni/AnalogOutDataJNI.cpp
@@ -0,0 +1,128 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI.h"
+#include "mockdata/AnalogOutData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    registerVoltageCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_registerVoltageCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogOutVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    cancelVoltageCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_cancelVoltageCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogOutVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    getVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_getVoltage
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogOutVoltage(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    setVoltage
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_setVoltage
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAnalogOutVoltage(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterAnalogOutInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogOutInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogOutInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetAnalogOutInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogOutDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetAnalogOutData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/AnalogTriggerDataJNI.cpp b/hal/src/main/native/sim/jni/AnalogTriggerDataJNI.cpp
new file mode 100644
index 0000000..66af737
--- /dev/null
+++ b/hal/src/main/native/sim/jni/AnalogTriggerDataJNI.cpp
@@ -0,0 +1,181 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI.h"
+#include "mockdata/AnalogTriggerData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogTriggerInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelAnalogTriggerInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogTriggerInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetAnalogTriggerInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    registerTriggerLowerBoundCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_registerTriggerLowerBoundCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogTriggerTriggerLowerBoundCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    cancelTriggerLowerBoundCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_cancelTriggerLowerBoundCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(
+      env, handle, index, &HALSIM_CancelAnalogTriggerTriggerLowerBoundCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    getTriggerLowerBound
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_getTriggerLowerBound
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogTriggerTriggerLowerBound(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    setTriggerLowerBound
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_setTriggerLowerBound
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAnalogTriggerTriggerLowerBound(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    registerTriggerUpperBoundCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_registerTriggerUpperBoundCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterAnalogTriggerTriggerUpperBoundCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    cancelTriggerUpperBoundCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_cancelTriggerUpperBoundCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(
+      env, handle, index, &HALSIM_CancelAnalogTriggerTriggerUpperBoundCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    getTriggerUpperBound
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_getTriggerUpperBound
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetAnalogTriggerTriggerUpperBound(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    setTriggerUpperBound
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_setTriggerUpperBound
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetAnalogTriggerTriggerUpperBound(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_AnalogTriggerDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetAnalogTriggerData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/BufferCallbackStore.cpp b/hal/src/main/native/sim/jni/BufferCallbackStore.cpp
new file mode 100644
index 0000000..fbf3adc
--- /dev/null
+++ b/hal/src/main/native/sim/jni/BufferCallbackStore.cpp
@@ -0,0 +1,125 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "BufferCallbackStore.h"
+
+#include <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+
+using namespace wpi::java;
+using namespace sim;
+
+static hal::UnlimitedHandleResource<SIM_JniHandle, BufferCallbackStore,
+                                    hal::HAL_HandleEnum::SimulationJni>*
+    callbackHandles;
+
+namespace sim {
+void InitializeBufferStore() {
+  static hal::UnlimitedHandleResource<SIM_JniHandle, BufferCallbackStore,
+                                      hal::HAL_HandleEnum::SimulationJni>
+      cb;
+  callbackHandles = &cb;
+}
+}  // namespace sim
+
+void BufferCallbackStore::create(JNIEnv* env, jobject obj) {
+  m_call = JGlobal<jobject>(env, obj);
+}
+
+void BufferCallbackStore::performCallback(const char* name, uint8_t* buffer,
+                                          uint32_t length) {
+  JNIEnv* env;
+  JavaVM* vm = sim::GetJVM();
+  bool didAttachThread = false;
+  int tryGetEnv = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+  if (tryGetEnv == JNI_EDETACHED) {
+    // Thread not attached
+    didAttachThread = true;
+    if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
+      // Failed to attach, log and return
+      wpi::outs() << "Failed to attach\n";
+      wpi::outs().flush();
+      return;
+    }
+  } else if (tryGetEnv == JNI_EVERSION) {
+    wpi::outs() << "Invalid JVM Version requested\n";
+    wpi::outs().flush();
+  }
+
+  auto toCallbackArr =
+      MakeJByteArray(env, wpi::StringRef{reinterpret_cast<const char*>(buffer),
+                                         static_cast<size_t>(length)});
+
+  env->CallVoidMethod(m_call, sim::GetBufferCallback(), MakeJString(env, name),
+                      toCallbackArr, (jint)length);
+
+  jbyte* fromCallbackArr = reinterpret_cast<jbyte*>(
+      env->GetPrimitiveArrayCritical(toCallbackArr, nullptr));
+
+  for (size_t i = 0; i < length; i++) {
+    buffer[i] = fromCallbackArr[i];
+  }
+
+  env->ReleasePrimitiveArrayCritical(toCallbackArr, fromCallbackArr, JNI_ABORT);
+
+  if (env->ExceptionCheck()) {
+    env->ExceptionDescribe();
+  }
+
+  if (didAttachThread) {
+    vm->DetachCurrentThread();
+  }
+}
+
+void BufferCallbackStore::free(JNIEnv* env) { m_call.free(env); }
+
+SIM_JniHandle sim::AllocateBufferCallback(
+    JNIEnv* env, jint index, jobject callback,
+    RegisterBufferCallbackFunc createCallback) {
+  auto callbackStore = std::make_shared<BufferCallbackStore>();
+
+  auto handle = callbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param, uint8_t* buffer,
+                         uint32_t length) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = callbackHandles->Get(handle);
+    if (!data) return;
+
+    data->performCallback(name, buffer, length);
+  };
+
+  auto id = createCallback(index, callbackFunc, handleAsVoidPtr);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
+}
+
+void sim::FreeBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                             FreeBufferCallbackFunc freeCallback) {
+  auto callback = callbackHandles->Free(handle);
+  freeCallback(index, callback->getCallbackId());
+  callback->free(env);
+}
diff --git a/hal/src/main/native/sim/jni/BufferCallbackStore.h b/hal/src/main/native/sim/jni/BufferCallbackStore.h
new file mode 100644
index 0000000..b9d49ac
--- /dev/null
+++ b/hal/src/main/native/sim/jni/BufferCallbackStore.h
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+
+namespace sim {
+class BufferCallbackStore {
+ public:
+  void create(JNIEnv* env, jobject obj);
+  void performCallback(const char* name, uint8_t* buffer, uint32_t length);
+  void free(JNIEnv* env);
+  void setCallbackId(int32_t id) { callbackId = id; }
+  int32_t getCallbackId() { return callbackId; }
+
+ private:
+  wpi::java::JGlobal<jobject> m_call;
+  int32_t callbackId;
+};
+
+void InitializeBufferStore();
+
+typedef int32_t (*RegisterBufferCallbackFunc)(int32_t index,
+                                              HAL_BufferCallback callback,
+                                              void* param);
+typedef void (*FreeBufferCallbackFunc)(int32_t index, int32_t uid);
+
+SIM_JniHandle AllocateBufferCallback(JNIEnv* env, jint index, jobject callback,
+                                     RegisterBufferCallbackFunc createCallback);
+void FreeBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                        FreeBufferCallbackFunc freeCallback);
+}  // namespace sim
diff --git a/hal/src/main/native/sim/jni/CallbackStore.cpp b/hal/src/main/native/sim/jni/CallbackStore.cpp
new file mode 100644
index 0000000..abef9b0
--- /dev/null
+++ b/hal/src/main/native/sim/jni/CallbackStore.cpp
@@ -0,0 +1,194 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "CallbackStore.h"
+
+#include <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+
+using namespace wpi::java;
+using namespace sim;
+
+static hal::UnlimitedHandleResource<SIM_JniHandle, CallbackStore,
+                                    hal::HAL_HandleEnum::SimulationJni>*
+    callbackHandles;
+
+namespace sim {
+void InitializeStore() {
+  static hal::UnlimitedHandleResource<SIM_JniHandle, CallbackStore,
+                                      hal::HAL_HandleEnum::SimulationJni>
+      cb;
+  callbackHandles = &cb;
+}
+}  // namespace sim
+
+void CallbackStore::create(JNIEnv* env, jobject obj) {
+  m_call = JGlobal<jobject>(env, obj);
+}
+
+void CallbackStore::performCallback(const char* name, const HAL_Value* value) {
+  JNIEnv* env;
+  JavaVM* vm = sim::GetJVM();
+  bool didAttachThread = false;
+  int tryGetEnv = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+  if (tryGetEnv == JNI_EDETACHED) {
+    // Thread not attached
+    didAttachThread = true;
+    if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
+      // Failed to attach, log and return
+      wpi::outs() << "Failed to attach\n";
+      wpi::outs().flush();
+      return;
+    }
+  } else if (tryGetEnv == JNI_EVERSION) {
+    wpi::outs() << "Invalid JVM Version requested\n";
+    wpi::outs().flush();
+  }
+
+  env->CallVoidMethod(m_call, sim::GetNotifyCallback(), MakeJString(env, name),
+                      (jint)value->type, (jlong)value->data.v_long,
+                      (jdouble)value->data.v_double);
+
+  if (env->ExceptionCheck()) {
+    env->ExceptionDescribe();
+  }
+
+  if (didAttachThread) {
+    vm->DetachCurrentThread();
+  }
+}
+
+void CallbackStore::free(JNIEnv* env) { m_call.free(env); }
+
+SIM_JniHandle sim::AllocateCallback(JNIEnv* env, jint index, jobject callback,
+                                    jboolean initialNotify,
+                                    RegisterCallbackFunc createCallback) {
+  auto callbackStore = std::make_shared<CallbackStore>();
+
+  auto handle = callbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param,
+                         const HAL_Value* value) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = callbackHandles->Get(handle);
+    if (!data) return;
+
+    data->performCallback(name, value);
+  };
+
+  auto id = createCallback(index, callbackFunc, handleAsVoidPtr, initialNotify);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
+}
+
+void sim::FreeCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                       FreeCallbackFunc freeCallback) {
+  auto callback = callbackHandles->Free(handle);
+  freeCallback(index, callback->getCallbackId());
+  callback->free(env);
+}
+
+SIM_JniHandle sim::AllocateChannelCallback(
+    JNIEnv* env, jint index, jint channel, jobject callback,
+    jboolean initialNotify, RegisterChannelCallbackFunc createCallback) {
+  auto callbackStore = std::make_shared<CallbackStore>();
+
+  auto handle = callbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param,
+                         const HAL_Value* value) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = callbackHandles->Get(handle);
+    if (!data) return;
+
+    data->performCallback(name, value);
+  };
+
+  auto id = createCallback(index, channel, callbackFunc, handleAsVoidPtr,
+                           initialNotify);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
+}
+
+void sim::FreeChannelCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                              jint channel,
+                              FreeChannelCallbackFunc freeCallback) {
+  auto callback = callbackHandles->Free(handle);
+  freeCallback(index, channel, callback->getCallbackId());
+  callback->free(env);
+}
+
+SIM_JniHandle sim::AllocateCallbackNoIndex(
+    JNIEnv* env, jobject callback, jboolean initialNotify,
+    RegisterCallbackNoIndexFunc createCallback) {
+  auto callbackStore = std::make_shared<CallbackStore>();
+
+  auto handle = callbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param,
+                         const HAL_Value* value) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = callbackHandles->Get(handle);
+    if (!data) return;
+
+    data->performCallback(name, value);
+  };
+
+  auto id = createCallback(callbackFunc, handleAsVoidPtr, initialNotify);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
+}
+
+void sim::FreeCallbackNoIndex(JNIEnv* env, SIM_JniHandle handle,
+                              FreeCallbackNoIndexFunc freeCallback) {
+  auto callback = callbackHandles->Free(handle);
+  freeCallback(callback->getCallbackId());
+  callback->free(env);
+}
diff --git a/hal/src/main/native/sim/jni/CallbackStore.h b/hal/src/main/native/sim/jni/CallbackStore.h
new file mode 100644
index 0000000..94454b0
--- /dev/null
+++ b/hal/src/main/native/sim/jni/CallbackStore.h
@@ -0,0 +1,66 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+
+namespace sim {
+class CallbackStore {
+ public:
+  void create(JNIEnv* env, jobject obj);
+  void performCallback(const char* name, const HAL_Value* value);
+  void free(JNIEnv* env);
+  void setCallbackId(int32_t id) { callbackId = id; }
+  int32_t getCallbackId() { return callbackId; }
+
+ private:
+  wpi::java::JGlobal<jobject> m_call;
+  int32_t callbackId;
+};
+
+void InitializeStore();
+
+typedef int32_t (*RegisterCallbackFunc)(int32_t index,
+                                        HAL_NotifyCallback callback,
+                                        void* param, HAL_Bool initialNotify);
+typedef void (*FreeCallbackFunc)(int32_t index, int32_t uid);
+typedef int32_t (*RegisterChannelCallbackFunc)(int32_t index, int32_t channel,
+                                               HAL_NotifyCallback callback,
+                                               void* param,
+                                               HAL_Bool initialNotify);
+typedef void (*FreeChannelCallbackFunc)(int32_t index, int32_t channel,
+                                        int32_t uid);
+typedef int32_t (*RegisterCallbackNoIndexFunc)(HAL_NotifyCallback callback,
+                                               void* param,
+                                               HAL_Bool initialNotify);
+typedef void (*FreeCallbackNoIndexFunc)(int32_t uid);
+
+SIM_JniHandle AllocateCallback(JNIEnv* env, jint index, jobject callback,
+                               jboolean initialNotify,
+                               RegisterCallbackFunc createCallback);
+SIM_JniHandle AllocateChannelCallback(
+    JNIEnv* env, jint index, jint channel, jobject callback,
+    jboolean initialNotify, RegisterChannelCallbackFunc createCallback);
+SIM_JniHandle AllocateCallbackNoIndex(
+    JNIEnv* env, jobject callback, jboolean initialNotify,
+    RegisterCallbackNoIndexFunc createCallback);
+void FreeCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                  FreeCallbackFunc freeCallback);
+void FreeChannelCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                         jint channel, FreeChannelCallbackFunc freeCallback);
+void FreeCallbackNoIndex(JNIEnv* env, SIM_JniHandle handle,
+                         FreeCallbackNoIndexFunc freeCallback);
+}  // namespace sim
diff --git a/hal/src/main/native/sim/jni/ConstBufferCallbackStore.cpp b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.cpp
new file mode 100644
index 0000000..781725b
--- /dev/null
+++ b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.cpp
@@ -0,0 +1,117 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "ConstBufferCallbackStore.h"
+
+#include <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+
+using namespace wpi::java;
+using namespace sim;
+
+static hal::UnlimitedHandleResource<SIM_JniHandle, ConstBufferCallbackStore,
+                                    hal::HAL_HandleEnum::SimulationJni>*
+    callbackHandles;
+
+namespace sim {
+void InitializeConstBufferStore() {
+  static hal::UnlimitedHandleResource<SIM_JniHandle, ConstBufferCallbackStore,
+                                      hal::HAL_HandleEnum::SimulationJni>
+      cb;
+  callbackHandles = &cb;
+}
+}  // namespace sim
+
+void ConstBufferCallbackStore::create(JNIEnv* env, jobject obj) {
+  m_call = JGlobal<jobject>(env, obj);
+}
+
+void ConstBufferCallbackStore::performCallback(const char* name,
+                                               const uint8_t* buffer,
+                                               uint32_t length) {
+  JNIEnv* env;
+  JavaVM* vm = sim::GetJVM();
+  bool didAttachThread = false;
+  int tryGetEnv = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+  if (tryGetEnv == JNI_EDETACHED) {
+    // Thread not attached
+    didAttachThread = true;
+    if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
+      // Failed to attach, log and return
+      wpi::outs() << "Failed to attach\n";
+      wpi::outs().flush();
+      return;
+    }
+  } else if (tryGetEnv == JNI_EVERSION) {
+    wpi::outs() << "Invalid JVM Version requested\n";
+    wpi::outs().flush();
+  }
+
+  auto toCallbackArr =
+      MakeJByteArray(env, wpi::StringRef{reinterpret_cast<const char*>(buffer),
+                                         static_cast<size_t>(length)});
+
+  env->CallVoidMethod(m_call, sim::GetConstBufferCallback(),
+                      MakeJString(env, name), toCallbackArr, (jint)length);
+
+  if (env->ExceptionCheck()) {
+    env->ExceptionDescribe();
+  }
+
+  if (didAttachThread) {
+    vm->DetachCurrentThread();
+  }
+}
+
+void ConstBufferCallbackStore::free(JNIEnv* env) { m_call.free(env); }
+
+SIM_JniHandle sim::AllocateConstBufferCallback(
+    JNIEnv* env, jint index, jobject callback,
+    RegisterConstBufferCallbackFunc createCallback) {
+  auto callbackStore = std::make_shared<ConstBufferCallbackStore>();
+
+  auto handle = callbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param, const uint8_t* buffer,
+                         uint32_t length) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = callbackHandles->Get(handle);
+    if (!data) return;
+
+    data->performCallback(name, buffer, length);
+  };
+
+  auto id = createCallback(index, callbackFunc, handleAsVoidPtr);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
+}
+
+void sim::FreeConstBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                                  FreeConstBufferCallbackFunc freeCallback) {
+  auto callback = callbackHandles->Free(handle);
+  freeCallback(index, callback->getCallbackId());
+  callback->free(env);
+}
diff --git a/hal/src/main/native/sim/jni/ConstBufferCallbackStore.h b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.h
new file mode 100644
index 0000000..1b0f54e
--- /dev/null
+++ b/hal/src/main/native/sim/jni/ConstBufferCallbackStore.h
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+
+namespace sim {
+class ConstBufferCallbackStore {
+ public:
+  void create(JNIEnv* env, jobject obj);
+  void performCallback(const char* name, const uint8_t* buffer,
+                       uint32_t length);
+  void free(JNIEnv* env);
+  void setCallbackId(int32_t id) { callbackId = id; }
+  int32_t getCallbackId() { return callbackId; }
+
+ private:
+  wpi::java::JGlobal<jobject> m_call;
+  int32_t callbackId;
+};
+
+void InitializeConstBufferStore();
+
+typedef int32_t (*RegisterConstBufferCallbackFunc)(
+    int32_t index, HAL_ConstBufferCallback callback, void* param);
+typedef void (*FreeConstBufferCallbackFunc)(int32_t index, int32_t uid);
+
+SIM_JniHandle AllocateConstBufferCallback(
+    JNIEnv* env, jint index, jobject callback,
+    RegisterConstBufferCallbackFunc createCallback);
+void FreeConstBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                             FreeConstBufferCallbackFunc freeCallback);
+}  // namespace sim
diff --git a/hal/src/main/native/sim/jni/DIODataJNI.cpp b/hal/src/main/native/sim/jni/DIODataJNI.cpp
new file mode 100644
index 0000000..2ad55f9
--- /dev/null
+++ b/hal/src/main/native/sim/jni/DIODataJNI.cpp
@@ -0,0 +1,277 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_DIODataJNI.h"
+#include "mockdata/DIOData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDIOInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelDIOInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDIOInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetDIOInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    registerValueCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_registerValueCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDIOValueCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    cancelValueCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_cancelValueCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index, &HALSIM_CancelDIOValueCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    getValue
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_getValue
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDIOValue(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    setValue
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_setValue
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetDIOValue(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    registerPulseLengthCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_registerPulseLengthCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDIOPulseLengthCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    cancelPulseLengthCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_cancelPulseLengthCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelDIOPulseLengthCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    getPulseLength
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_getPulseLength
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDIOPulseLength(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    setPulseLength
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_setPulseLength
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetDIOPulseLength(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    registerIsInputCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_registerIsInputCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDIOIsInputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    cancelIsInputCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_cancelIsInputCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelDIOIsInputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    getIsInput
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_getIsInput
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDIOIsInput(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    setIsInput
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_setIsInput
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetDIOIsInput(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    registerFilterIndexCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_registerFilterIndexCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDIOFilterIndexCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    cancelFilterIndexCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_cancelFilterIndexCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelDIOFilterIndexCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    getFilterIndex
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_getFilterIndex
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDIOFilterIndex(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    setFilterIndex
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_setFilterIndex
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetDIOFilterIndex(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DIODataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DIODataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetDIOData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/DigitalPWMDataJNI.cpp b/hal/src/main/native/sim/jni/DigitalPWMDataJNI.cpp
new file mode 100644
index 0000000..0800917
--- /dev/null
+++ b/hal/src/main/native/sim/jni/DigitalPWMDataJNI.cpp
@@ -0,0 +1,178 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI.h"
+#include "mockdata/DigitalPWMData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDigitalPWMInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelDigitalPWMInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDigitalPWMInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetDigitalPWMInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    registerDutyCycleCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_registerDutyCycleCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDigitalPWMDutyCycleCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    cancelDutyCycleCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_cancelDutyCycleCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelDigitalPWMDutyCycleCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    getDutyCycle
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_getDutyCycle
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDigitalPWMDutyCycle(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    setDutyCycle
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_setDutyCycle
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetDigitalPWMDutyCycle(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    registerPinCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_registerPinCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterDigitalPWMPinCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    cancelPinCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_cancelPinCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelDigitalPWMPinCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    getPin
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_getPin
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetDigitalPWMPin(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    setPin
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_setPin
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetDigitalPWMPin(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DigitalPWMDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetDigitalPWMData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/DriverStationDataJNI.cpp b/hal/src/main/native/sim/jni/DriverStationDataJNI.cpp
new file mode 100644
index 0000000..621650a
--- /dev/null
+++ b/hal/src/main/native/sim/jni/DriverStationDataJNI.cpp
@@ -0,0 +1,461 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include <cstring>
+
+#include <wpi/jni_util.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI.h"
+#include "mockdata/DriverStationData.h"
+
+using namespace wpi::java;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    registerEnabledCallback
+ * Signature: (Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_registerEnabledCallback
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify,
+      &HALSIM_RegisterDriverStationEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    cancelEnabledCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_cancelEnabledCallback
+  (JNIEnv* env, jclass, jint handle)
+{
+  return sim::FreeCallbackNoIndex(env, handle,
+                                  &HALSIM_CancelDriverStationEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    getEnabled
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_getEnabled
+  (JNIEnv*, jclass)
+{
+  return HALSIM_GetDriverStationEnabled();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setEnabled
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setEnabled
+  (JNIEnv*, jclass, jboolean value)
+{
+  HALSIM_SetDriverStationEnabled(value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    registerAutonomousCallback
+ * Signature: (Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_registerAutonomousCallback
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify,
+      &HALSIM_RegisterDriverStationAutonomousCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    cancelAutonomousCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_cancelAutonomousCallback
+  (JNIEnv* env, jclass, jint handle)
+{
+  return sim::FreeCallbackNoIndex(
+      env, handle, &HALSIM_CancelDriverStationAutonomousCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    getAutonomous
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_getAutonomous
+  (JNIEnv*, jclass)
+{
+  return HALSIM_GetDriverStationAutonomous();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setAutonomous
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setAutonomous
+  (JNIEnv*, jclass, jboolean value)
+{
+  HALSIM_SetDriverStationAutonomous(value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    registerTestCallback
+ * Signature: (Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_registerTestCallback
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify, &HALSIM_RegisterDriverStationTestCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    cancelTestCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_cancelTestCallback
+  (JNIEnv* env, jclass, jint handle)
+{
+  return sim::FreeCallbackNoIndex(env, handle,
+                                  &HALSIM_CancelDriverStationTestCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    getTest
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_getTest
+  (JNIEnv*, jclass)
+{
+  return HALSIM_GetDriverStationTest();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setTest
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setTest
+  (JNIEnv*, jclass, jboolean value)
+{
+  HALSIM_SetDriverStationTest(value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    registerEStopCallback
+ * Signature: (Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_registerEStopCallback
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify, &HALSIM_RegisterDriverStationEStopCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    cancelEStopCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_cancelEStopCallback
+  (JNIEnv* env, jclass, jint handle)
+{
+  return sim::FreeCallbackNoIndex(env, handle,
+                                  &HALSIM_CancelDriverStationEStopCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    getEStop
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_getEStop
+  (JNIEnv*, jclass)
+{
+  return HALSIM_GetDriverStationEStop();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setEStop
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setEStop
+  (JNIEnv*, jclass, jboolean value)
+{
+  HALSIM_SetDriverStationEStop(value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    registerFmsAttachedCallback
+ * Signature: (Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_registerFmsAttachedCallback
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify,
+      &HALSIM_RegisterDriverStationFmsAttachedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    cancelFmsAttachedCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_cancelFmsAttachedCallback
+  (JNIEnv* env, jclass, jint handle)
+{
+  return sim::FreeCallbackNoIndex(
+      env, handle, &HALSIM_CancelDriverStationFmsAttachedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    getFmsAttached
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_getFmsAttached
+  (JNIEnv*, jclass)
+{
+  return HALSIM_GetDriverStationFmsAttached();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setFmsAttached
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setFmsAttached
+  (JNIEnv*, jclass, jboolean value)
+{
+  HALSIM_SetDriverStationFmsAttached(value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    registerDsAttachedCallback
+ * Signature: (Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_registerDsAttachedCallback
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify,
+      &HALSIM_RegisterDriverStationDsAttachedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    cancelDsAttachedCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_cancelDsAttachedCallback
+  (JNIEnv* env, jclass, jint handle)
+{
+  return sim::FreeCallbackNoIndex(
+      env, handle, &HALSIM_CancelDriverStationDsAttachedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    getDsAttached
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_getDsAttached
+  (JNIEnv*, jclass)
+{
+  return HALSIM_GetDriverStationDsAttached();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setDsAttached
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setDsAttached
+  (JNIEnv*, jclass, jboolean value)
+{
+  HALSIM_SetDriverStationDsAttached(value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setJoystickAxes
+ * Signature: (B[F)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setJoystickAxes
+  (JNIEnv* env, jclass, jbyte joystickNum, jfloatArray axesArray)
+{
+  HAL_JoystickAxes axes;
+  {
+    wpi::java::JFloatArrayRef jArrayRef(env, axesArray);
+    auto arrayRef = jArrayRef.array();
+    auto arraySize = arrayRef.size();
+    int maxCount =
+        arraySize < HAL_kMaxJoystickAxes ? arraySize : HAL_kMaxJoystickAxes;
+    axes.count = maxCount;
+    for (int i = 0; i < maxCount; i++) {
+      axes.axes[i] = arrayRef[i];
+    }
+  }
+  HALSIM_SetJoystickAxes(joystickNum, &axes);
+  return;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setJoystickPOVs
+ * Signature: (B[S)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setJoystickPOVs
+  (JNIEnv* env, jclass, jbyte joystickNum, jshortArray povsArray)
+{
+  HAL_JoystickPOVs povs;
+  {
+    wpi::java::JShortArrayRef jArrayRef(env, povsArray);
+    auto arrayRef = jArrayRef.array();
+    auto arraySize = arrayRef.size();
+    int maxCount =
+        arraySize < HAL_kMaxJoystickPOVs ? arraySize : HAL_kMaxJoystickPOVs;
+    povs.count = maxCount;
+    for (int i = 0; i < maxCount; i++) {
+      povs.povs[i] = arrayRef[i];
+    }
+  }
+  HALSIM_SetJoystickPOVs(joystickNum, &povs);
+  return;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setJoystickButtons
+ * Signature: (BII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setJoystickButtons
+  (JNIEnv* env, jclass, jbyte joystickNum, jint buttons, jint count)
+{
+  if (count > 32) {
+    count = 32;
+  }
+  HAL_JoystickButtons joystickButtons;
+  joystickButtons.count = count;
+  joystickButtons.buttons = buttons;
+  HALSIM_SetJoystickButtons(joystickNum, &joystickButtons);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    setMatchInfo
+ * Signature: (Ljava/lang/String;Ljava/lang/String;III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setMatchInfo
+  (JNIEnv* env, jclass, jstring eventName, jstring gameSpecificMessage,
+   jint matchNumber, jint replayNumber, jint matchType)
+{
+  JStringRef eventNameRef{env, eventName};
+  JStringRef gameSpecificMessageRef{env, gameSpecificMessage};
+
+  HAL_MatchInfo halMatchInfo;
+  std::snprintf(halMatchInfo.eventName, sizeof(halMatchInfo.eventName), "%s",
+                eventNameRef.c_str());
+  std::snprintf(reinterpret_cast<char*>(halMatchInfo.gameSpecificMessage),
+                sizeof(halMatchInfo.gameSpecificMessage), "%s",
+                gameSpecificMessageRef.c_str());
+  halMatchInfo.gameSpecificMessageSize = gameSpecificMessageRef.size();
+  halMatchInfo.matchType = (HAL_MatchType)matchType;
+  halMatchInfo.matchNumber = matchNumber;
+  halMatchInfo.replayNumber = replayNumber;
+  HALSIM_SetMatchInfo(&halMatchInfo);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    registerAllCallbacks
+ * Signature: (Ljava/lang/Object;Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_registerAllCallbacks
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify,
+      [](HAL_NotifyCallback cb, void* param, HAL_Bool in) {
+        HALSIM_RegisterDriverStationAllCallbacks(cb, param, in);
+        return 0;
+      });
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    notifyNewData
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_notifyNewData
+  (JNIEnv*, jclass)
+{
+  HALSIM_NotifyDriverStationNewData();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
+ * Method:    resetData
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_resetData
+  (JNIEnv*, jclass)
+{
+  HALSIM_ResetDriverStationData();
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/EncoderDataJNI.cpp b/hal/src/main/native/sim/jni/EncoderDataJNI.cpp
new file mode 100644
index 0000000..8992b0c
--- /dev/null
+++ b/hal/src/main/native/sim/jni/EncoderDataJNI.cpp
@@ -0,0 +1,428 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_EncoderDataJNI.h"
+#include "mockdata/EncoderData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetEncoderInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerCountCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerCountCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderCountCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelCountCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelCountCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderCountCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getCount
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getCount
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderCount(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setCount
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setCount
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetEncoderCount(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerPeriodCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerPeriodCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderPeriodCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelPeriodCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelPeriodCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderPeriodCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getPeriod
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getPeriod
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderPeriod(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setPeriod
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setPeriod
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetEncoderPeriod(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerResetCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerResetCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderResetCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelResetCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelResetCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderResetCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getReset
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getReset
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderReset(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setReset
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setReset
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetEncoderReset(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerMaxPeriodCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerMaxPeriodCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderMaxPeriodCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelMaxPeriodCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelMaxPeriodCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderMaxPeriodCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getMaxPeriod
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getMaxPeriod
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderMaxPeriod(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setMaxPeriod
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setMaxPeriod
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetEncoderMaxPeriod(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerDirectionCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerDirectionCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderDirectionCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelDirectionCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelDirectionCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderDirectionCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getDirection
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getDirection
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderDirection(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setDirection
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setDirection
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetEncoderDirection(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerReverseDirectionCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerReverseDirectionCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderReverseDirectionCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelReverseDirectionCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelReverseDirectionCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderReverseDirectionCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getReverseDirection
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getReverseDirection
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderReverseDirection(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setReverseDirection
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setReverseDirection
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetEncoderReverseDirection(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    registerSamplesToAverageCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_registerSamplesToAverageCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterEncoderSamplesToAverageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    cancelSamplesToAverageCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_cancelSamplesToAverageCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelEncoderSamplesToAverageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    getSamplesToAverage
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_getSamplesToAverage
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetEncoderSamplesToAverage(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    setSamplesToAverage
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_setSamplesToAverage
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetEncoderSamplesToAverage(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_EncoderDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_EncoderDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetEncoderData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/I2CDataJNI.cpp b/hal/src/main/native/sim/jni/I2CDataJNI.cpp
new file mode 100644
index 0000000..14b3292
--- /dev/null
+++ b/hal/src/main/native/sim/jni/I2CDataJNI.cpp
@@ -0,0 +1,131 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "BufferCallbackStore.h"
+#include "CallbackStore.h"
+#include "ConstBufferCallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_I2CDataJNI.h"
+#include "mockdata/I2CData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterI2CInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelI2CInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetI2CInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetI2CInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    registerReadCallback
+ * Signature: (ILjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_registerReadCallback
+  (JNIEnv* env, jclass, jint index, jobject callback)
+{
+  return sim::AllocateBufferCallback(env, index, callback,
+                                     &HALSIM_RegisterI2CReadCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    cancelReadCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_cancelReadCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  sim::FreeBufferCallback(env, handle, index, &HALSIM_CancelI2CReadCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    registerWriteCallback
+ * Signature: (ILjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_registerWriteCallback
+  (JNIEnv* env, jclass, jint index, jobject callback)
+{
+  return sim::AllocateConstBufferCallback(env, index, callback,
+                                          &HALSIM_RegisterI2CWriteCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    cancelWriteCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_cancelWriteCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  sim::FreeConstBufferCallback(env, handle, index,
+                               &HALSIM_CancelI2CWriteCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_I2CDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_I2CDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetI2CData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/PCMDataJNI.cpp b/hal/src/main/native/sim/jni/PCMDataJNI.cpp
new file mode 100644
index 0000000..de6f738
--- /dev/null
+++ b/hal/src/main/native/sim/jni/PCMDataJNI.cpp
@@ -0,0 +1,419 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_PCMDataJNI.h"
+#include "mockdata/PCMData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerSolenoidInitializedCallback
+ * Signature: (IILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerSolenoidInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  return sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      &HALSIM_RegisterPCMSolenoidInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    cancelSolenoidInitializedCallback
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_cancelSolenoidInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
+{
+  return sim::FreeChannelCallback(env, handle, index, channel,
+                                  &HALSIM_CancelPCMSolenoidInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    getSolenoidInitialized
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_getSolenoidInitialized
+  (JNIEnv*, jclass, jint index, jint channel)
+{
+  return HALSIM_GetPCMSolenoidInitialized(index, channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    setSolenoidInitialized
+ * Signature: (IIZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_setSolenoidInitialized
+  (JNIEnv*, jclass, jint index, jint channel, jboolean value)
+{
+  HALSIM_SetPCMSolenoidInitialized(index, channel, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerSolenoidOutputCallback
+ * Signature: (IILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerSolenoidOutputCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  return sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      &HALSIM_RegisterPCMSolenoidOutputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    cancelSolenoidOutputCallback
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_cancelSolenoidOutputCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
+{
+  return sim::FreeChannelCallback(env, handle, index, channel,
+                                  &HALSIM_CancelPCMSolenoidOutputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    getSolenoidOutput
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_getSolenoidOutput
+  (JNIEnv*, jclass, jint index, jint channel)
+{
+  return HALSIM_GetPCMSolenoidOutput(index, channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    setSolenoidOutput
+ * Signature: (IIZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_setSolenoidOutput
+  (JNIEnv*, jclass, jint index, jint channel, jboolean value)
+{
+  HALSIM_SetPCMSolenoidOutput(index, channel, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerCompressorInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerCompressorInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterPCMCompressorInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    cancelCompressorInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_cancelCompressorInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPCMCompressorInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    getCompressorInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_getCompressorInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPCMCompressorInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    setCompressorInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_setCompressorInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPCMCompressorInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerCompressorOnCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerCompressorOnCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPCMCompressorOnCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    cancelCompressorOnCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_cancelCompressorOnCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPCMCompressorOnCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    getCompressorOn
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_getCompressorOn
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPCMCompressorOn(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    setCompressorOn
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_setCompressorOn
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPCMCompressorOn(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerClosedLoopEnabledCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerClosedLoopEnabledCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPCMClosedLoopEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    cancelClosedLoopEnabledCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_cancelClosedLoopEnabledCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPCMClosedLoopEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    getClosedLoopEnabled
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_getClosedLoopEnabled
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPCMClosedLoopEnabled(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    setClosedLoopEnabled
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_setClosedLoopEnabled
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPCMClosedLoopEnabled(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerPressureSwitchCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerPressureSwitchCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPCMPressureSwitchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    cancelPressureSwitchCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_cancelPressureSwitchCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPCMPressureSwitchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    getPressureSwitch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_getPressureSwitch
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPCMPressureSwitch(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    setPressureSwitch
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_setPressureSwitch
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPCMPressureSwitch(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerCompressorCurrentCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerCompressorCurrentCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPCMCompressorCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    cancelCompressorCurrentCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_cancelCompressorCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPCMCompressorCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    getCompressorCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_getCompressorCurrent
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPCMCompressorCurrent(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    setCompressorCurrent
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_setCompressorCurrent
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetPCMCompressorCurrent(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerAllNonSolenoidCallbacks
+ * Signature: (ILjava/lang/Object;Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerAllNonSolenoidCallbacks
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      [](int32_t index, HAL_NotifyCallback cb, void* param, HAL_Bool in) {
+        HALSIM_RegisterPCMAllNonSolenoidCallbacks(index, cb, param, in);
+        return 0;
+      });
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    registerAllSolenoidCallbacks
+ * Signature: (IILjava/lang/Object;Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_registerAllSolenoidCallbacks
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      [](int32_t index, int32_t channel, HAL_NotifyCallback cb, void* param,
+         HAL_Bool in) {
+        HALSIM_RegisterPCMAllSolenoidCallbacks(index, channel, cb, param, in);
+        return 0;
+      });
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PCMDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PCMDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetPCMData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/PDPDataJNI.cpp b/hal/src/main/native/sim/jni/PDPDataJNI.cpp
new file mode 100644
index 0000000..5d39e87
--- /dev/null
+++ b/hal/src/main/native/sim/jni/PDPDataJNI.cpp
@@ -0,0 +1,230 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_PDPDataJNI.h"
+#include "mockdata/PDPData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPDPInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPDPInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPDPInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPDPInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    registerTemperatureCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_registerTemperatureCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPDPTemperatureCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    cancelTemperatureCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_cancelTemperatureCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPDPTemperatureCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    getTemperature
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_getTemperature
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPDPTemperature(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    setTemperature
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_setTemperature
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetPDPTemperature(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    registerVoltageCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_registerVoltageCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPDPVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    cancelVoltageCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_cancelVoltageCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPDPVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    getVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_getVoltage
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPDPVoltage(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    setVoltage
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_setVoltage
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetPDPVoltage(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    registerCurrentCallback
+ * Signature: (IILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_registerCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  return sim::AllocateChannelCallback(env, index, channel, callback,
+                                      initialNotify,
+                                      &HALSIM_RegisterPDPCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    cancelCurrentCallback
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_cancelCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
+{
+  return sim::FreeChannelCallback(env, handle, index, channel,
+                                  &HALSIM_CancelPDPCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    getCurrent
+ * Signature: (II)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_getCurrent
+  (JNIEnv*, jclass, jint index, jint channel)
+{
+  return HALSIM_GetPDPCurrent(index, channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    setCurrent
+ * Signature: (IID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_setCurrent
+  (JNIEnv*, jclass, jint index, jint channel, jdouble value)
+{
+  HALSIM_SetPDPCurrent(index, channel, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PDPDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PDPDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetPDPData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/PWMDataJNI.cpp b/hal/src/main/native/sim/jni/PWMDataJNI.cpp
new file mode 100644
index 0000000..b8a7c41
--- /dev/null
+++ b/hal/src/main/native/sim/jni/PWMDataJNI.cpp
@@ -0,0 +1,327 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_PWMDataJNI.h"
+#include "mockdata/PWMData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPWMInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPWMInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPWMInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPWMInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    registerRawValueCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_registerRawValueCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPWMRawValueCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    cancelRawValueCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_cancelRawValueCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPWMRawValueCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    getRawValue
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_getRawValue
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPWMRawValue(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    setRawValue
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_setRawValue
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetPWMRawValue(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    registerSpeedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_registerSpeedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPWMSpeedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    cancelSpeedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_cancelSpeedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index, &HALSIM_CancelPWMSpeedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    getSpeed
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_getSpeed
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPWMSpeed(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    setSpeed
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_setSpeed
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetPWMSpeed(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    registerPositionCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_registerPositionCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPWMPositionCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    cancelPositionCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_cancelPositionCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPWMPositionCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    getPosition
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_getPosition
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPWMPosition(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    setPosition
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_setPosition
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetPWMPosition(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    registerPeriodScaleCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_registerPeriodScaleCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPWMPeriodScaleCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    cancelPeriodScaleCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_cancelPeriodScaleCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPWMPeriodScaleCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    getPeriodScale
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_getPeriodScale
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPWMPeriodScale(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    setPeriodScale
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_setPeriodScale
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetPWMPeriodScale(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    registerZeroLatchCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_registerZeroLatchCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterPWMZeroLatchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    cancelZeroLatchCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_cancelZeroLatchCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPWMZeroLatchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    getZeroLatch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_getZeroLatch
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPWMZeroLatch(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    setZeroLatch
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_setZeroLatch
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPWMZeroLatch(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_PWMDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_PWMDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetPWMData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/RelayDataJNI.cpp b/hal/src/main/native/sim/jni/RelayDataJNI.cpp
new file mode 100644
index 0000000..bf85407
--- /dev/null
+++ b/hal/src/main/native/sim/jni/RelayDataJNI.cpp
@@ -0,0 +1,228 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_RelayDataJNI.h"
+#include "mockdata/RelayData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    registerInitializedForwardCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_registerInitializedForwardCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRelayInitializedForwardCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    cancelInitializedForwardCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_cancelInitializedForwardCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRelayInitializedForwardCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    getInitializedForward
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_getInitializedForward
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRelayInitializedForward(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    setInitializedForward
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_setInitializedForward
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRelayInitializedForward(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    registerInitializedReverseCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_registerInitializedReverseCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRelayInitializedReverseCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    cancelInitializedReverseCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_cancelInitializedReverseCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRelayInitializedReverseCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    getInitializedReverse
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_getInitializedReverse
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRelayInitializedReverse(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    setInitializedReverse
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_setInitializedReverse
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRelayInitializedReverse(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    registerForwardCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_registerForwardCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRelayForwardCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    cancelForwardCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_cancelForwardCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRelayForwardCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    getForward
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_getForward
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRelayForward(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    setForward
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_setForward
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRelayForward(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    registerReverseCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_registerReverseCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRelayReverseCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    cancelReverseCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_cancelReverseCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRelayReverseCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    getReverse
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_getReverse
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRelayReverse(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    setReverse
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_setReverse
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRelayReverse(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RelayDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RelayDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetRelayData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/RoboRioDataJNI.cpp b/hal/src/main/native/sim/jni/RoboRioDataJNI.cpp
new file mode 100644
index 0000000..d69e895
--- /dev/null
+++ b/hal/src/main/native/sim/jni/RoboRioDataJNI.cpp
@@ -0,0 +1,778 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI.h"
+#include "mockdata/RoboRioData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerFPGAButtonCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerFPGAButtonCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioFPGAButtonCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelFPGAButtonCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelFPGAButtonCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioFPGAButtonCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getFPGAButton
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getFPGAButton
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioFPGAButton(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setFPGAButton
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setFPGAButton
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRoboRioFPGAButton(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerVInVoltageCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerVInVoltageCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioVInVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelVInVoltageCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelVInVoltageCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioVInVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getVInVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getVInVoltage
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioVInVoltage(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setVInVoltage
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setVInVoltage
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioVInVoltage(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerVInCurrentCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerVInCurrentCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioVInCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelVInCurrentCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelVInCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioVInCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getVInCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getVInCurrent
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioVInCurrent(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setVInCurrent
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setVInCurrent
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioVInCurrent(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserVoltage6VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserVoltage6VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserVoltage6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserVoltage6VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserVoltage6VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserVoltage6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserVoltage6V
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserVoltage6V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserVoltage6V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserVoltage6V
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserVoltage6V
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioUserVoltage6V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserCurrent6VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserCurrent6VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserCurrent6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserCurrent6VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserCurrent6VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserCurrent6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserCurrent6V
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserCurrent6V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserCurrent6V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserCurrent6V
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserCurrent6V
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioUserCurrent6V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserActive6VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserActive6VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserActive6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserActive6VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserActive6VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserActive6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserActive6V
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserActive6V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserActive6V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserActive6V
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserActive6V
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRoboRioUserActive6V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserVoltage5VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserVoltage5VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserVoltage5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserVoltage5VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserVoltage5VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserVoltage5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserVoltage5V
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserVoltage5V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserVoltage5V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserVoltage5V
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserVoltage5V
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioUserVoltage5V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserCurrent5VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserCurrent5VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserCurrent5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserCurrent5VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserCurrent5VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserCurrent5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserCurrent5V
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserCurrent5V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserCurrent5V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserCurrent5V
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserCurrent5V
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioUserCurrent5V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserActive5VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserActive5VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserActive5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserActive5VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserActive5VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserActive5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserActive5V
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserActive5V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserActive5V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserActive5V
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserActive5V
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRoboRioUserActive5V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserVoltage3V3Callback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserVoltage3V3Callback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserVoltage3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserVoltage3V3Callback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserVoltage3V3Callback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserVoltage3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserVoltage3V3
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserVoltage3V3
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserVoltage3V3(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserVoltage3V3
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserVoltage3V3
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioUserVoltage3V3(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserCurrent3V3Callback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserCurrent3V3Callback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserCurrent3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserCurrent3V3Callback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserCurrent3V3Callback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserCurrent3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserCurrent3V3
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserCurrent3V3
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserCurrent3V3(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserCurrent3V3
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserCurrent3V3
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetRoboRioUserCurrent3V3(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserActive3V3Callback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserActive3V3Callback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserActive3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserActive3V3Callback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserActive3V3Callback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserActive3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserActive3V3
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserActive3V3
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserActive3V3(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserActive3V3
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserActive3V3
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetRoboRioUserActive3V3(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserFaults6VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserFaults6VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserFaults6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserFaults6VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserFaults6VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserFaults6VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserFaults6V
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserFaults6V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserFaults6V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserFaults6V
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserFaults6V
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetRoboRioUserFaults6V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserFaults5VCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserFaults5VCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserFaults5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserFaults5VCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserFaults5VCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserFaults5VCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserFaults5V
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserFaults5V
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserFaults5V(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserFaults5V
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserFaults5V
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetRoboRioUserFaults5V(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    registerUserFaults3V3Callback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_registerUserFaults3V3Callback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterRoboRioUserFaults3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    cancelUserFaults3V3Callback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_cancelUserFaults3V3Callback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelRoboRioUserFaults3V3Callback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    getUserFaults3V3
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_getUserFaults3V3
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetRoboRioUserFaults3V3(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    setUserFaults3V3
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_setUserFaults3V3
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetRoboRioUserFaults3V3(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_RoboRioDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetRoboRioData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/SPIAccelerometerDataJNI.cpp b/hal/src/main/native/sim/jni/SPIAccelerometerDataJNI.cpp
new file mode 100644
index 0000000..ca12f79
--- /dev/null
+++ b/hal/src/main/native/sim/jni/SPIAccelerometerDataJNI.cpp
@@ -0,0 +1,278 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI.h"
+#include "mockdata/SPIAccelerometerData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    registerActiveCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_registerActiveCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterSPIAccelerometerActiveCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    cancelActiveCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_cancelActiveCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelSPIAccelerometerActiveCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    getActive
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_getActive
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetSPIAccelerometerActive(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    setActive
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_setActive
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetSPIAccelerometerActive(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    registerRangeCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_registerRangeCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterSPIAccelerometerRangeCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    cancelRangeCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_cancelRangeCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelSPIAccelerometerRangeCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    getRange
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_getRange
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetSPIAccelerometerRange(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    setRange
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_setRange
+  (JNIEnv*, jclass, jint index, jint value)
+{
+  HALSIM_SetSPIAccelerometerRange(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    registerXCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_registerXCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterSPIAccelerometerXCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    cancelXCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_cancelXCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelSPIAccelerometerXCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    getX
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_getX
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetSPIAccelerometerX(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    setX
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_setX
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetSPIAccelerometerX(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    registerYCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_registerYCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterSPIAccelerometerYCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    cancelYCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_cancelYCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelSPIAccelerometerYCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    getY
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_getY
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetSPIAccelerometerY(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    setY
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_setY
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetSPIAccelerometerY(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    registerZCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_registerZCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterSPIAccelerometerZCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    cancelZCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_cancelZCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelSPIAccelerometerZCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    getZ
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_getZ
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetSPIAccelerometerZ(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    setZ
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_setZ
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetSPIAccelerometerZ(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIAccelerometerDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetSPIAccelerometerData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/SPIDataJNI.cpp b/hal/src/main/native/sim/jni/SPIDataJNI.cpp
new file mode 100644
index 0000000..4eb342c
--- /dev/null
+++ b/hal/src/main/native/sim/jni/SPIDataJNI.cpp
@@ -0,0 +1,158 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "BufferCallbackStore.h"
+#include "CallbackStore.h"
+#include "ConstBufferCallbackStore.h"
+#include "SpiReadAutoReceiveBufferCallbackStore.h"
+#include "edu_wpi_first_hal_sim_mockdata_SPIDataJNI.h"
+#include "mockdata/SPIData.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterSPIInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelSPIInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetSPIInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetSPIInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    registerReadCallback
+ * Signature: (ILjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_registerReadCallback
+  (JNIEnv* env, jclass, jint index, jobject callback)
+{
+  return sim::AllocateBufferCallback(env, index, callback,
+                                     &HALSIM_RegisterSPIReadCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    cancelReadCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_cancelReadCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  sim::FreeBufferCallback(env, handle, index, &HALSIM_CancelSPIReadCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    registerWriteCallback
+ * Signature: (ILjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_registerWriteCallback
+  (JNIEnv* env, jclass, jint index, jobject callback)
+{
+  return sim::AllocateConstBufferCallback(env, index, callback,
+                                          &HALSIM_RegisterSPIWriteCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    cancelWriteCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_cancelWriteCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  sim::FreeConstBufferCallback(env, handle, index,
+                               &HALSIM_CancelSPIWriteCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    registerReadAutoReceiveBufferCallback
+ * Signature: (ILjava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_registerReadAutoReceiveBufferCallback
+  (JNIEnv* env, jclass, jint index, jobject callback)
+{
+  return sim::AllocateSpiBufferCallback(
+      env, index, callback, &HALSIM_RegisterSPIReadAutoReceivedDataCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    cancelReadAutoReceiveBufferCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_cancelReadAutoReceiveBufferCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  sim::FreeSpiBufferCallback(env, handle, index,
+                             &HALSIM_CancelSPIReadAutoReceivedDataCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SPIDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SPIDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetSPIData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/SimulatorJNI.cpp b/hal/src/main/native/sim/jni/SimulatorJNI.cpp
new file mode 100644
index 0000000..d1e0f7d
--- /dev/null
+++ b/hal/src/main/native/sim/jni/SimulatorJNI.cpp
@@ -0,0 +1,157 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "SimulatorJNI.h"
+
+#include "BufferCallbackStore.h"
+#include "CallbackStore.h"
+#include "ConstBufferCallbackStore.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;
+static JClass spiReadAutoReceiveBufferCallbackCls;
+static jmethodID notifyCallbackCallback;
+static jmethodID bufferCallbackCallback;
+static jmethodID constBufferCallbackCallback;
+static jmethodID spiReadAutoReceiveBufferCallbackCallback;
+
+namespace sim {
+jint SimOnLoad(JavaVM* vm, void* reserved) {
+  jvm = vm;
+
+  JNIEnv* env;
+  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;
+
+  notifyCallbackCallback = env->GetMethodID(notifyCallbackCls, "callbackNative",
+                                            "(Ljava/lang/String;IJD)V");
+  if (!notifyCallbackCallback) return JNI_ERR;
+
+  bufferCallbackCls = JClass(env, "edu/wpi/first/hal/sim/BufferCallback");
+  if (!bufferCallbackCls) return JNI_ERR;
+
+  bufferCallbackCallback = env->GetMethodID(bufferCallbackCls, "callback",
+                                            "(Ljava/lang/String;[BI)V");
+  if (!bufferCallbackCallback) return JNI_ERR;
+
+  constBufferCallbackCls =
+      JClass(env, "edu/wpi/first/hal/sim/ConstBufferCallback");
+  if (!constBufferCallbackCls) return JNI_ERR;
+
+  constBufferCallbackCallback = env->GetMethodID(
+      constBufferCallbackCls, "callback", "(Ljava/lang/String;[BI)V");
+  if (!constBufferCallbackCallback) return JNI_ERR;
+
+  spiReadAutoReceiveBufferCallbackCls =
+      JClass(env, "edu/wpi/first/hal/sim/SpiReadAutoReceiveBufferCallback");
+  if (!spiReadAutoReceiveBufferCallbackCls) return JNI_ERR;
+
+  spiReadAutoReceiveBufferCallbackCallback =
+      env->GetMethodID(spiReadAutoReceiveBufferCallbackCls, "callback",
+                       "(Ljava/lang/String;[II)I");
+  if (!spiReadAutoReceiveBufferCallbackCallback) return JNI_ERR;
+
+  InitializeStore();
+  InitializeBufferStore();
+  InitializeConstBufferStore();
+  InitializeSpiBufferStore();
+
+  return JNI_VERSION_1_6;
+}
+
+void SimOnUnload(JavaVM* vm, void* reserved) {
+  JNIEnv* env;
+  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);
+  jvm = nullptr;
+}
+
+JavaVM* GetJVM() { return jvm; }
+
+jmethodID GetNotifyCallback() { return notifyCallbackCallback; }
+
+jmethodID GetBufferCallback() { return bufferCallbackCallback; }
+
+jmethodID GetConstBufferCallback() { return constBufferCallbackCallback; }
+
+jmethodID GetSpiReadAutoReceiveBufferCallback() {
+  return spiReadAutoReceiveBufferCallbackCallback;
+}
+}  // namespace sim
+
+extern "C" {
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimulatorJNI
+ * Method:    waitForProgramStart
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimulatorJNI_waitForProgramStart
+  (JNIEnv*, jclass)
+{
+  HALSIM_WaitForProgramStart();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimulatorJNI
+ * Method:    setProgramStarted
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimulatorJNI_setProgramStarted
+  (JNIEnv*, jclass)
+{
+  HALSIM_SetProgramStarted();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimulatorJNI
+ * Method:    restartTiming
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimulatorJNI_restartTiming
+  (JNIEnv*, jclass)
+{
+  HALSIM_RestartTiming();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_sim_mockdata_SimulatorJNI
+ * Method:    resetHandles
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_sim_mockdata_SimulatorJNI_resetHandles
+  (JNIEnv*, jclass)
+{
+  hal::HandleBase::ResetGlobalHandles();
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/jni/SimulatorJNI.h b/hal/src/main/native/sim/jni/SimulatorJNI.h
new file mode 100644
index 0000000..60d0ca3
--- /dev/null
+++ b/hal/src/main/native/sim/jni/SimulatorJNI.h
@@ -0,0 +1,25 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <wpi/jni_util.h>
+
+#include "hal/Types.h"
+#include "jni.h"
+#include "mockdata/HAL_Value.h"
+
+typedef HAL_Handle SIM_JniHandle;
+
+namespace sim {
+JavaVM* GetJVM();
+
+jmethodID GetNotifyCallback();
+jmethodID GetBufferCallback();
+jmethodID GetConstBufferCallback();
+jmethodID GetSpiReadAutoReceiveBufferCallback();
+}  // namespace sim
diff --git a/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.cpp b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.cpp
new file mode 100644
index 0000000..935c8bf
--- /dev/null
+++ b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.cpp
@@ -0,0 +1,130 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "SpiReadAutoReceiveBufferCallbackStore.h"
+
+#include <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+
+using namespace wpi::java;
+using namespace sim;
+
+static hal::UnlimitedHandleResource<
+    SIM_JniHandle, SpiReadAutoReceiveBufferCallbackStore,
+    hal::HAL_HandleEnum::SimulationJni>* callbackHandles;
+
+namespace sim {
+void InitializeSpiBufferStore() {
+  static hal::UnlimitedHandleResource<SIM_JniHandle,
+                                      SpiReadAutoReceiveBufferCallbackStore,
+                                      hal::HAL_HandleEnum::SimulationJni>
+      cb;
+  callbackHandles = &cb;
+}
+}  // namespace sim
+
+void SpiReadAutoReceiveBufferCallbackStore::create(JNIEnv* env, jobject obj) {
+  m_call = JGlobal<jobject>(env, obj);
+}
+
+int32_t SpiReadAutoReceiveBufferCallbackStore::performCallback(
+    const char* name, uint32_t* buffer, int32_t numToRead) {
+  JNIEnv* env;
+  JavaVM* vm = sim::GetJVM();
+  bool didAttachThread = false;
+  int tryGetEnv = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+  if (tryGetEnv == JNI_EDETACHED) {
+    // Thread not attached
+    didAttachThread = true;
+    if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
+      // Failed to attach, log and return
+      wpi::outs() << "Failed to attach\n";
+      wpi::outs().flush();
+      return -1;
+    }
+  } else if (tryGetEnv == JNI_EVERSION) {
+    wpi::outs() << "Invalid JVM Version requested\n";
+    wpi::outs().flush();
+  }
+
+  auto toCallbackArr = MakeJIntArray(
+      env, wpi::ArrayRef<uint32_t>{buffer, static_cast<size_t>(numToRead)});
+
+  jint ret = env->CallIntMethod(m_call, sim::GetBufferCallback(),
+                                MakeJString(env, name), toCallbackArr,
+                                (jint)numToRead);
+
+  jint* fromCallbackArr = reinterpret_cast<jint*>(
+      env->GetPrimitiveArrayCritical(toCallbackArr, nullptr));
+
+  for (int i = 0; i < ret; i++) {
+    buffer[i] = fromCallbackArr[i];
+  }
+
+  env->ReleasePrimitiveArrayCritical(toCallbackArr, fromCallbackArr, JNI_ABORT);
+
+  if (env->ExceptionCheck()) {
+    env->ExceptionDescribe();
+  }
+
+  if (didAttachThread) {
+    vm->DetachCurrentThread();
+  }
+  return ret;
+}
+
+void SpiReadAutoReceiveBufferCallbackStore::free(JNIEnv* env) {
+  m_call.free(env);
+}
+
+SIM_JniHandle sim::AllocateSpiBufferCallback(
+    JNIEnv* env, jint index, jobject callback,
+    RegisterSpiBufferCallbackFunc createCallback) {
+  auto callbackStore =
+      std::make_shared<SpiReadAutoReceiveBufferCallbackStore>();
+
+  auto handle = callbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param, uint32_t* buffer,
+                         int32_t numToRead, int32_t* outputCount) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = callbackHandles->Get(handle);
+    if (!data) return;
+
+    *outputCount = data->performCallback(name, buffer, numToRead);
+  };
+
+  auto id = createCallback(index, callbackFunc, handleAsVoidPtr);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
+}
+
+void sim::FreeSpiBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                                FreeSpiBufferCallbackFunc freeCallback) {
+  auto callback = callbackHandles->Free(handle);
+  freeCallback(index, callback->getCallbackId());
+  callback->free(env);
+}
diff --git a/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.h b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.h
new file mode 100644
index 0000000..643a874
--- /dev/null
+++ b/hal/src/main/native/sim/jni/SpiReadAutoReceiveBufferCallbackStore.h
@@ -0,0 +1,47 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "SimulatorJNI.h"
+#include "hal/Types.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/HAL_Value.h"
+#include "mockdata/NotifyListener.h"
+#include "mockdata/SPIData.h"
+
+namespace sim {
+class SpiReadAutoReceiveBufferCallbackStore {
+ public:
+  void create(JNIEnv* env, jobject obj);
+  int32_t performCallback(const char* name, uint32_t* buffer,
+                          int32_t numToRead);
+  void free(JNIEnv* env);
+  void setCallbackId(int32_t id) { callbackId = id; }
+  int32_t getCallbackId() { return callbackId; }
+
+ private:
+  wpi::java::JGlobal<jobject> m_call;
+  int32_t callbackId;
+};
+
+void InitializeSpiBufferStore();
+
+typedef int32_t (*RegisterSpiBufferCallbackFunc)(
+    int32_t index, HAL_SpiReadAutoReceiveBufferCallback callback, void* param);
+typedef void (*FreeSpiBufferCallbackFunc)(int32_t index, int32_t uid);
+
+SIM_JniHandle AllocateSpiBufferCallback(
+    JNIEnv* env, jint index, jobject callback,
+    RegisterSpiBufferCallbackFunc createCallback);
+void FreeSpiBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
+                           FreeSpiBufferCallbackFunc freeCallback);
+}  // namespace sim
diff --git a/hal/src/main/native/sim/mockdata/AccelerometerData.cpp b/hal/src/main/native/sim/mockdata/AccelerometerData.cpp
new file mode 100644
index 0000000..66e129a
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AccelerometerData.cpp
@@ -0,0 +1,60 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "AccelerometerDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAccelerometerData() {
+  static AccelerometerData sad[1];
+  ::hal::SimAccelerometerData = sad;
+}
+}  // namespace init
+}  // namespace hal
+
+AccelerometerData* hal::SimAccelerometerData;
+void AccelerometerData::ResetData() {
+  active.Reset(false);
+  range.Reset(static_cast<HAL_AccelerometerRange>(0));
+  x.Reset(0.0);
+  y.Reset(0.0);
+  z.Reset(0.0);
+}
+
+extern "C" {
+void HALSIM_ResetAccelerometerData(int32_t index) {
+  SimAccelerometerData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                        \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, Accelerometer##CAPINAME, \
+                               SimAccelerometerData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Active, active)
+DEFINE_CAPI(HAL_AccelerometerRange, Range, range)
+DEFINE_CAPI(double, X, x)
+DEFINE_CAPI(double, Y, y)
+DEFINE_CAPI(double, Z, z)
+
+#define REGISTER(NAME)                                               \
+  SimAccelerometerData[index].NAME.RegisterCallback(callback, param, \
+                                                    initialNotify)
+
+void HALSIM_RegisterAccelerometerAllCallbacks(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify) {
+  REGISTER(active);
+  REGISTER(range);
+  REGISTER(x);
+  REGISTER(y);
+  REGISTER(z);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h b/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h
new file mode 100644
index 0000000..15e55ac
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/AccelerometerData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class AccelerometerData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Active)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Range)
+  HAL_SIMDATAVALUE_DEFINE_NAME(X)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Y)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Z)
+
+  static inline HAL_Value MakeRangeValue(HAL_AccelerometerRange value) {
+    return MakeEnum(value);
+  }
+
+ public:
+  SimDataValue<HAL_Bool, 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};
+
+  virtual void ResetData();
+};
+extern AccelerometerData* SimAccelerometerData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/AnalogGyroData.cpp b/hal/src/main/native/sim/mockdata/AnalogGyroData.cpp
new file mode 100644
index 0000000..2508d9b
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogGyroData.cpp
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "AnalogGyroDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAnalogGyroData() {
+  static AnalogGyroData agd[kNumAccumulators];
+  ::hal::SimAnalogGyroData = agd;
+}
+}  // namespace init
+}  // namespace hal
+
+AnalogGyroData* hal::SimAnalogGyroData;
+void AnalogGyroData::ResetData() {
+  angle.Reset(0.0);
+  rate.Reset(0.0);
+  initialized.Reset(false);
+}
+
+extern "C" {
+void HALSIM_ResetAnalogGyroData(int32_t index) {
+  SimAnalogGyroData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                     \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, AnalogGyro##CAPINAME, \
+                               SimAnalogGyroData, LOWERNAME)
+
+DEFINE_CAPI(double, Angle, angle)
+DEFINE_CAPI(double, Rate, rate)
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+
+#define REGISTER(NAME) \
+  SimAnalogGyroData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterAnalogGyroAllCallbacks(int32_t index,
+                                           HAL_NotifyCallback callback,
+                                           void* param,
+                                           HAL_Bool initialNotify) {
+  REGISTER(angle);
+  REGISTER(rate);
+  REGISTER(initialized);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h
new file mode 100644
index 0000000..8dfcb52
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h
@@ -0,0 +1,27 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/AnalogGyroData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class AnalogGyroData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Angle)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Rate)
+  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};
+
+  virtual void ResetData();
+};
+extern AnalogGyroData* SimAnalogGyroData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/AnalogInData.cpp b/hal/src/main/native/sim/mockdata/AnalogInData.cpp
new file mode 100644
index 0000000..1efdf50
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogInData.cpp
@@ -0,0 +1,70 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "AnalogInDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAnalogInData() {
+  static AnalogInData sind[kNumAnalogInputs];
+  ::hal::SimAnalogInData = sind;
+}
+}  // namespace init
+}  // namespace hal
+
+AnalogInData* hal::SimAnalogInData;
+void AnalogInData::ResetData() {
+  initialized.Reset(false);
+  averageBits.Reset(7);
+  oversampleBits.Reset(0);
+  voltage.Reset(0.0);
+  accumulatorInitialized.Reset(false);
+  accumulatorValue.Reset(0);
+  accumulatorCount.Reset(0);
+  accumulatorCenter.Reset(0);
+  accumulatorDeadband.Reset(0);
+}
+
+extern "C" {
+void HALSIM_ResetAnalogInData(int32_t index) {
+  SimAnalogInData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                   \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, AnalogIn##CAPINAME, \
+                               SimAnalogInData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(int32_t, AverageBits, averageBits)
+DEFINE_CAPI(int32_t, OversampleBits, oversampleBits)
+DEFINE_CAPI(double, Voltage, voltage)
+DEFINE_CAPI(HAL_Bool, AccumulatorInitialized, accumulatorInitialized)
+DEFINE_CAPI(int64_t, AccumulatorValue, accumulatorValue)
+DEFINE_CAPI(int64_t, AccumulatorCount, accumulatorCount)
+DEFINE_CAPI(int32_t, AccumulatorCenter, accumulatorCenter)
+DEFINE_CAPI(int32_t, AccumulatorDeadband, accumulatorDeadband)
+
+#define REGISTER(NAME) \
+  SimAnalogInData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterAnalogInAllCallbacks(int32_t index,
+                                         HAL_NotifyCallback callback,
+                                         void* param, HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(averageBits);
+  REGISTER(oversampleBits);
+  REGISTER(voltage);
+  REGISTER(accumulatorInitialized);
+  REGISTER(accumulatorValue);
+  REGISTER(accumulatorCount);
+  REGISTER(accumulatorCenter);
+  REGISTER(accumulatorDeadband);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h
new file mode 100644
index 0000000..94121ca
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/AnalogInData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class AnalogInData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(AverageBits)
+  HAL_SIMDATAVALUE_DEFINE_NAME(OversampleBits)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Voltage)
+  HAL_SIMDATAVALUE_DEFINE_NAME(AccumulatorInitialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(AccumulatorValue)
+  HAL_SIMDATAVALUE_DEFINE_NAME(AccumulatorCount)
+  HAL_SIMDATAVALUE_DEFINE_NAME(AccumulatorCenter)
+  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>
+      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>
+      accumulatorDeadband{0};
+
+  virtual void ResetData();
+};
+extern AnalogInData* SimAnalogInData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/AnalogOutData.cpp b/hal/src/main/native/sim/mockdata/AnalogOutData.cpp
new file mode 100644
index 0000000..d4b9116
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogOutData.cpp
@@ -0,0 +1,49 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "AnalogOutDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAnalogOutData() {
+  static AnalogOutData siod[kNumAnalogOutputs];
+  ::hal::SimAnalogOutData = siod;
+}
+}  // namespace init
+}  // namespace hal
+
+AnalogOutData* hal::SimAnalogOutData;
+void AnalogOutData::ResetData() {
+  voltage.Reset(0.0);
+  initialized.Reset(0);
+}
+
+extern "C" {
+void HALSIM_ResetAnalogOutData(int32_t index) {
+  SimAnalogOutData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                    \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, AnalogOut##CAPINAME, \
+                               SimAnalogOutData, LOWERNAME)
+
+DEFINE_CAPI(double, Voltage, voltage)
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+
+#define REGISTER(NAME) \
+  SimAnalogOutData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterAnalogOutAllCallbacks(int32_t index,
+                                          HAL_NotifyCallback callback,
+                                          void* param, HAL_Bool initialNotify) {
+  REGISTER(voltage);
+  REGISTER(initialized);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h
new file mode 100644
index 0000000..84af837
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h
@@ -0,0 +1,25 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/AnalogOutData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class AnalogOutData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Voltage)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+
+ public:
+  SimDataValue<double, MakeDouble, GetVoltageName> voltage{0.0};
+  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{0};
+
+  virtual void ResetData();
+};
+extern AnalogOutData* SimAnalogOutData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/AnalogTriggerData.cpp b/hal/src/main/native/sim/mockdata/AnalogTriggerData.cpp
new file mode 100644
index 0000000..64d1a97
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogTriggerData.cpp
@@ -0,0 +1,57 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "AnalogTriggerDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeAnalogTriggerData() {
+  static AnalogTriggerData satd[kNumAnalogTriggers];
+  ::hal::SimAnalogTriggerData = satd;
+}
+}  // namespace init
+}  // namespace hal
+
+AnalogTriggerData* hal::SimAnalogTriggerData;
+void AnalogTriggerData::ResetData() {
+  initialized.Reset(0);
+  triggerLowerBound.Reset(0);
+  triggerUpperBound.Reset(0);
+  triggerMode.Reset(static_cast<HALSIM_AnalogTriggerMode>(0));
+}
+
+extern "C" {
+void HALSIM_ResetAnalogTriggerData(int32_t index) {
+  SimAnalogTriggerData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                        \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, AnalogTrigger##CAPINAME, \
+                               SimAnalogTriggerData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(double, TriggerLowerBound, triggerLowerBound)
+DEFINE_CAPI(double, TriggerUpperBound, triggerUpperBound)
+DEFINE_CAPI(HALSIM_AnalogTriggerMode, TriggerMode, triggerMode)
+
+#define REGISTER(NAME)                                               \
+  SimAnalogTriggerData[index].NAME.RegisterCallback(callback, param, \
+                                                    initialNotify)
+
+void HALSIM_RegisterAnalogTriggerAllCallbacks(int32_t index,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(triggerLowerBound);
+  REGISTER(triggerUpperBound);
+  REGISTER(triggerMode);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h
new file mode 100644
index 0000000..131ba7a
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h
@@ -0,0 +1,38 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/AnalogTriggerData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class AnalogTriggerData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(TriggerLowerBound)
+  HAL_SIMDATAVALUE_DEFINE_NAME(TriggerUpperBound)
+  HAL_SIMDATAVALUE_DEFINE_NAME(TriggerMode)
+
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE HAL_Value
+  MakeTriggerModeValue(HALSIM_AnalogTriggerMode value) {
+    return MakeEnum(value);
+  }
+
+ public:
+  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{0};
+  SimDataValue<double, MakeDouble, GetTriggerLowerBoundName> triggerLowerBound{
+      0};
+  SimDataValue<double, MakeDouble, GetTriggerUpperBoundName> triggerUpperBound{
+      0};
+  SimDataValue<HALSIM_AnalogTriggerMode, MakeTriggerModeValue,
+               GetTriggerModeName>
+      triggerMode{static_cast<HALSIM_AnalogTriggerMode>(0)};
+
+  virtual void ResetData();
+};
+extern AnalogTriggerData* SimAnalogTriggerData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/CanDataInternal.cpp b/hal/src/main/native/sim/mockdata/CanDataInternal.cpp
new file mode 100644
index 0000000..e37d865
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/CanDataInternal.cpp
@@ -0,0 +1,47 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "CanDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeCanData() {
+  static CanData scd;
+  ::hal::SimCanData = &scd;
+}
+}  // namespace init
+}  // namespace hal
+
+CanData* hal::SimCanData;
+
+void CanData::ResetData() {
+  sendMessage.Reset();
+  receiveMessage.Reset();
+  openStreamSession.Reset();
+  closeStreamSession.Reset();
+  readStreamSession.Reset();
+  getCANStatus.Reset();
+}
+
+extern "C" {
+
+void HALSIM_ResetCanData(void) { SimCanData->ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                             \
+  HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI_NOINDEX(TYPE, HALSIM, Can##CAPINAME, \
+                                              SimCanData, LOWERNAME)
+
+DEFINE_CAPI(HAL_CAN_SendMessageCallback, SendMessage, sendMessage)
+DEFINE_CAPI(HAL_CAN_ReceiveMessageCallback, ReceiveMessage, receiveMessage)
+DEFINE_CAPI(HAL_CAN_OpenStreamSessionCallback, OpenStream, openStreamSession)
+DEFINE_CAPI(HAL_CAN_CloseStreamSessionCallback, CloseStream, closeStreamSession)
+DEFINE_CAPI(HAL_CAN_ReadStreamSessionCallback, ReadStream, readStreamSession)
+DEFINE_CAPI(HAL_CAN_GetCANStatusCallback, GetCANStatus, getCANStatus)
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/CanDataInternal.h b/hal/src/main/native/sim/mockdata/CanDataInternal.h
new file mode 100644
index 0000000..ffdd351
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/CanDataInternal.h
@@ -0,0 +1,42 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/CanData.h"
+#include "mockdata/SimCallbackRegistry.h"
+
+namespace hal {
+
+class CanData {
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(SendMessage)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(ReceiveMessage)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(OpenStream)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(CloseStream)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(ReadStream)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(GetCanStatus)
+
+ public:
+  SimCallbackRegistry<HAL_CAN_SendMessageCallback, GetSendMessageName>
+      sendMessage;
+  SimCallbackRegistry<HAL_CAN_ReceiveMessageCallback, GetReceiveMessageName>
+      receiveMessage;
+  SimCallbackRegistry<HAL_CAN_OpenStreamSessionCallback, GetOpenStreamName>
+      openStreamSession;
+  SimCallbackRegistry<HAL_CAN_CloseStreamSessionCallback, GetCloseStreamName>
+      closeStreamSession;
+  SimCallbackRegistry<HAL_CAN_ReadStreamSessionCallback, GetReadStreamName>
+      readStreamSession;
+  SimCallbackRegistry<HAL_CAN_GetCANStatusCallback, GetGetCanStatusName>
+      getCANStatus;
+
+  void ResetData();
+};
+
+extern CanData* SimCanData;
+
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/DIOData.cpp b/hal/src/main/native/sim/mockdata/DIOData.cpp
new file mode 100644
index 0000000..ea66de3
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/DIOData.cpp
@@ -0,0 +1,55 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "DIODataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeDIOData() {
+  static DIOData sdd[kNumDigitalChannels];
+  ::hal::SimDIOData = sdd;
+}
+}  // namespace init
+}  // namespace hal
+
+DIOData* hal::SimDIOData;
+void DIOData::ResetData() {
+  initialized.Reset(false);
+  value.Reset(true);
+  pulseLength.Reset(0.0);
+  isInput.Reset(true);
+  filterIndex.Reset(-1);
+}
+
+extern "C" {
+void HALSIM_ResetDIOData(int32_t index) { SimDIOData[index].ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, DIO##CAPINAME, SimDIOData, \
+                               LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(HAL_Bool, Value, value)
+DEFINE_CAPI(double, PulseLength, pulseLength)
+DEFINE_CAPI(HAL_Bool, IsInput, isInput)
+DEFINE_CAPI(int32_t, FilterIndex, filterIndex)
+
+#define REGISTER(NAME) \
+  SimDIOData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterDIOAllCallbacks(int32_t index, HAL_NotifyCallback callback,
+                                    void* param, HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(value);
+  REGISTER(pulseLength);
+  REGISTER(isInput);
+  REGISTER(filterIndex);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/DIODataInternal.h b/hal/src/main/native/sim/mockdata/DIODataInternal.h
new file mode 100644
index 0000000..0b022f9
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/DIODataInternal.h
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/DIOData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class DIOData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Value)
+  HAL_SIMDATAVALUE_DEFINE_NAME(PulseLength)
+  HAL_SIMDATAVALUE_DEFINE_NAME(IsInput)
+  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};
+
+  virtual void ResetData();
+};
+extern DIOData* SimDIOData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/DigitalPWMData.cpp b/hal/src/main/native/sim/mockdata/DigitalPWMData.cpp
new file mode 100644
index 0000000..78ee749
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/DigitalPWMData.cpp
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "DigitalPWMDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeDigitalPWMData() {
+  static DigitalPWMData sdpd[kNumDigitalPWMOutputs];
+  ::hal::SimDigitalPWMData = sdpd;
+}
+}  // namespace init
+}  // namespace hal
+
+DigitalPWMData* hal::SimDigitalPWMData;
+void DigitalPWMData::ResetData() {
+  initialized.Reset(false);
+  dutyCycle.Reset(0.0);
+  pin.Reset(0);
+}
+
+extern "C" {
+void HALSIM_ResetDigitalPWMData(int32_t index) {
+  SimDigitalPWMData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                     \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, DigitalPWM##CAPINAME, \
+                               SimDigitalPWMData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(double, DutyCycle, dutyCycle)
+DEFINE_CAPI(int32_t, Pin, pin)
+
+#define REGISTER(NAME) \
+  SimDigitalPWMData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterDigitalPWMAllCallbacks(int32_t index,
+                                           HAL_NotifyCallback callback,
+                                           void* param,
+                                           HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(dutyCycle);
+  REGISTER(pin);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h b/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h
new file mode 100644
index 0000000..00d8b4a
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h
@@ -0,0 +1,27 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/DigitalPWMData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class DigitalPWMData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(DutyCycle)
+  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};
+
+  virtual void ResetData();
+};
+extern DigitalPWMData* SimDigitalPWMData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/DriverStationData.cpp b/hal/src/main/native/sim/mockdata/DriverStationData.cpp
new file mode 100644
index 0000000..d72d6b3
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/DriverStationData.cpp
@@ -0,0 +1,209 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "DriverStationDataInternal.h"
+#include "hal/DriverStation.h"
+
+namespace hal {
+struct JoystickOutputStore {
+  int64_t outputs = 0;
+  int32_t leftRumble = 0;
+  int32_t rightRumble = 0;
+};
+}  // namespace hal
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeDriverStationData() {
+  static DriverStationData dsd;
+  ::hal::SimDriverStationData = &dsd;
+}
+}  // namespace init
+}  // namespace hal
+
+DriverStationData* hal::SimDriverStationData;
+
+DriverStationData::DriverStationData() { ResetData(); }
+
+void DriverStationData::ResetData() {
+  enabled.Reset(false);
+  autonomous.Reset(false);
+  test.Reset(false);
+  eStop.Reset(false);
+  fmsAttached.Reset(false);
+  dsAttached.Reset(true);
+  allianceStationId.Reset(static_cast<HAL_AllianceStationID>(0));
+  matchTime.Reset(0.0);
+
+  {
+    std::lock_guard<wpi::spinlock> 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);
+    m_joystickOutputs = std::make_unique<JoystickOutputStore[]>(6);
+    m_joystickDescriptor = std::make_unique<HAL_JoystickDescriptor[]>(6);
+
+    for (int i = 0; i < 6; 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';
+    }
+  }
+  {
+    std::lock_guard<wpi::spinlock> lock(m_matchInfoMutex);
+
+    m_matchInfo = std::make_unique<HAL_MatchInfo>();
+  }
+}
+
+void DriverStationData::GetJoystickAxes(int32_t joystickNum,
+                                        HAL_JoystickAxes* axes) {
+  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  *axes = m_joystickAxes[joystickNum];
+}
+void DriverStationData::GetJoystickPOVs(int32_t joystickNum,
+                                        HAL_JoystickPOVs* povs) {
+  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  *povs = m_joystickPOVs[joystickNum];
+}
+void DriverStationData::GetJoystickButtons(int32_t joystickNum,
+                                           HAL_JoystickButtons* buttons) {
+  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  *buttons = m_joystickButtons[joystickNum];
+}
+void DriverStationData::GetJoystickDescriptor(
+    int32_t joystickNum, HAL_JoystickDescriptor* descriptor) {
+  std::lock_guard<wpi::spinlock> lock(m_joystickDataMutex);
+  *descriptor = m_joystickDescriptor[joystickNum];
+  // Always ensure name is null terminated
+  descriptor->name[255] = '\0';
+}
+void DriverStationData::GetJoystickOutputs(int32_t joystickNum,
+                                           int64_t* outputs,
+                                           int32_t* leftRumble,
+                                           int32_t* rightRumble) {
+  std::lock_guard<wpi::spinlock> 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);
+  *info = *m_matchInfo;
+}
+
+void DriverStationData::SetJoystickAxes(int32_t joystickNum,
+                                        const HAL_JoystickAxes* axes) {
+  std::lock_guard<wpi::spinlock> 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);
+  m_joystickPOVs[joystickNum] = *povs;
+}
+void DriverStationData::SetJoystickButtons(int32_t joystickNum,
+                                           const HAL_JoystickButtons* buttons) {
+  std::lock_guard<wpi::spinlock> 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);
+  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);
+  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);
+  *m_matchInfo = *info;
+  *(std::end(m_matchInfo->eventName) - 1) = '\0';
+}
+
+void DriverStationData::NotifyNewData() { HAL_ReleaseDSMutex(); }
+
+extern "C" {
+void HALSIM_ResetDriverStationData(void) { SimDriverStationData->ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                                \
+  HAL_SIMDATAVALUE_DEFINE_CAPI_NOINDEX(TYPE, HALSIM, DriverStation##CAPINAME, \
+                                       SimDriverStationData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Enabled, enabled)
+DEFINE_CAPI(HAL_Bool, Autonomous, autonomous)
+DEFINE_CAPI(HAL_Bool, Test, test)
+DEFINE_CAPI(HAL_Bool, EStop, eStop)
+DEFINE_CAPI(HAL_Bool, FmsAttached, fmsAttached)
+DEFINE_CAPI(HAL_Bool, DsAttached, dsAttached)
+DEFINE_CAPI(HAL_AllianceStationID, AllianceStationId, allianceStationId)
+DEFINE_CAPI(double, MatchTime, matchTime)
+
+void HALSIM_SetJoystickAxes(int32_t joystickNum, const HAL_JoystickAxes* axes) {
+  SimDriverStationData->SetJoystickAxes(joystickNum, axes);
+}
+
+void HALSIM_SetJoystickPOVs(int32_t joystickNum, const HAL_JoystickPOVs* povs) {
+  SimDriverStationData->SetJoystickPOVs(joystickNum, povs);
+}
+
+void HALSIM_SetJoystickButtons(int32_t joystickNum,
+                               const HAL_JoystickButtons* buttons) {
+  SimDriverStationData->SetJoystickButtons(joystickNum, buttons);
+}
+void HALSIM_SetJoystickDescriptor(int32_t joystickNum,
+                                  const HAL_JoystickDescriptor* descriptor) {
+  SimDriverStationData->SetJoystickDescriptor(joystickNum, descriptor);
+}
+
+void HALSIM_GetJoystickOutputs(int32_t joystickNum, int64_t* outputs,
+                               int32_t* leftRumble, int32_t* rightRumble) {
+  SimDriverStationData->GetJoystickOutputs(joystickNum, outputs, leftRumble,
+                                           rightRumble);
+}
+
+void HALSIM_SetMatchInfo(const HAL_MatchInfo* info) {
+  SimDriverStationData->SetMatchInfo(info);
+}
+
+void HALSIM_NotifyDriverStationNewData(void) {
+  SimDriverStationData->NotifyNewData();
+}
+
+#define REGISTER(NAME) \
+  SimDriverStationData->NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterDriverStationAllCallbacks(HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify) {
+  REGISTER(enabled);
+  REGISTER(autonomous);
+  REGISTER(test);
+  REGISTER(eStop);
+  REGISTER(fmsAttached);
+  REGISTER(dsAttached);
+  REGISTER(allianceStationId);
+  REGISTER(matchTime);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h
new file mode 100644
index 0000000..f7eb132
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h
@@ -0,0 +1,85 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <wpi/spinlock.h>
+
+#include "mockdata/DriverStationData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+struct JoystickOutputStore;
+
+class DriverStationData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Enabled)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Autonomous)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Test)
+  HAL_SIMDATAVALUE_DEFINE_NAME(EStop)
+  HAL_SIMDATAVALUE_DEFINE_NAME(FmsAttached)
+  HAL_SIMDATAVALUE_DEFINE_NAME(DsAttached)
+  HAL_SIMDATAVALUE_DEFINE_NAME(AllianceStationId)
+  HAL_SIMDATAVALUE_DEFINE_NAME(MatchTime)
+
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE HAL_Value
+  MakeAllianceStationIdValue(HAL_AllianceStationID value) {
+    return MakeEnum(value);
+  }
+
+ public:
+  DriverStationData();
+  void ResetData();
+
+  void GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes);
+  void GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs);
+  void GetJoystickButtons(int32_t joystickNum, HAL_JoystickButtons* buttons);
+  void GetJoystickDescriptor(int32_t joystickNum,
+                             HAL_JoystickDescriptor* descriptor);
+  void GetJoystickOutputs(int32_t joystickNum, int64_t* outputs,
+                          int32_t* leftRumble, int32_t* rightRumble);
+  void GetMatchInfo(HAL_MatchInfo* info);
+  void FreeMatchInfo(const HAL_MatchInfo* info);
+
+  void SetJoystickAxes(int32_t joystickNum, const HAL_JoystickAxes* axes);
+  void SetJoystickPOVs(int32_t joystickNum, const HAL_JoystickPOVs* povs);
+  void SetJoystickButtons(int32_t joystickNum,
+                          const HAL_JoystickButtons* buttons);
+  void SetJoystickDescriptor(int32_t joystickNum,
+                             const HAL_JoystickDescriptor* descriptor);
+  void SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
+                          int32_t leftRumble, int32_t rightRumble);
+  void SetMatchInfo(const HAL_MatchInfo* info);
+
+  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_AllianceStationID, MakeAllianceStationIdValue,
+               GetAllianceStationIdName>
+      allianceStationId{static_cast<HAL_AllianceStationID>(0)};
+  SimDataValue<double, MakeDouble, GetMatchTimeName> matchTime{0.0};
+
+ private:
+  wpi::spinlock m_joystickDataMutex;
+  wpi::spinlock m_matchInfoMutex;
+
+  std::unique_ptr<HAL_JoystickAxes[]> m_joystickAxes;
+  std::unique_ptr<HAL_JoystickPOVs[]> m_joystickPOVs;
+  std::unique_ptr<HAL_JoystickButtons[]> m_joystickButtons;
+
+  std::unique_ptr<JoystickOutputStore[]> m_joystickOutputs;
+  std::unique_ptr<HAL_JoystickDescriptor[]> m_joystickDescriptor;
+  std::unique_ptr<HAL_MatchInfo> m_matchInfo;
+};
+extern DriverStationData* SimDriverStationData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/EncoderData.cpp b/hal/src/main/native/sim/mockdata/EncoderData.cpp
new file mode 100644
index 0000000..59ba48f
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/EncoderData.cpp
@@ -0,0 +1,75 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "EncoderDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeEncoderData() {
+  static EncoderData sed[kNumEncoders];
+  ::hal::SimEncoderData = sed;
+}
+}  // namespace init
+}  // namespace hal
+
+EncoderData* hal::SimEncoderData;
+void EncoderData::ResetData() {
+  digitalChannelA = 0;
+  initialized.Reset(false);
+  count.Reset(0);
+  period.Reset(std::numeric_limits<double>::max());
+  reset.Reset(false);
+  maxPeriod.Reset(0);
+  direction.Reset(false);
+  reverseDirection.Reset(false);
+  samplesToAverage.Reset(0);
+  distancePerPulse.Reset(1);
+}
+
+extern "C" {
+void HALSIM_ResetEncoderData(int32_t index) {
+  SimEncoderData[index].ResetData();
+}
+
+int16_t HALSIM_GetDigitalChannelA(int32_t index) {
+  return SimEncoderData[index].digitalChannelA;
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                  \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, Encoder##CAPINAME, \
+                               SimEncoderData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(int32_t, Count, count)
+DEFINE_CAPI(double, Period, period)
+DEFINE_CAPI(HAL_Bool, Reset, reset)
+DEFINE_CAPI(double, MaxPeriod, maxPeriod)
+DEFINE_CAPI(HAL_Bool, Direction, direction)
+DEFINE_CAPI(HAL_Bool, ReverseDirection, reverseDirection)
+DEFINE_CAPI(int32_t, SamplesToAverage, samplesToAverage)
+DEFINE_CAPI(double, DistancePerPulse, distancePerPulse)
+
+#define REGISTER(NAME) \
+  SimEncoderData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterEncoderAllCallbacks(int32_t index,
+                                        HAL_NotifyCallback callback,
+                                        void* param, HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(count);
+  REGISTER(period);
+  REGISTER(reset);
+  REGISTER(maxPeriod);
+  REGISTER(direction);
+  REGISTER(reverseDirection);
+  REGISTER(samplesToAverage);
+  REGISTER(distancePerPulse);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/EncoderDataInternal.h b/hal/src/main/native/sim/mockdata/EncoderDataInternal.h
new file mode 100644
index 0000000..657d977
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/EncoderDataInternal.h
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------*/
+/* 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 <atomic>
+#include <limits>
+
+#include "mockdata/EncoderData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class EncoderData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Count)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Period)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Reset)
+  HAL_SIMDATAVALUE_DEFINE_NAME(MaxPeriod)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Direction)
+  HAL_SIMDATAVALUE_DEFINE_NAME(ReverseDirection)
+  HAL_SIMDATAVALUE_DEFINE_NAME(SamplesToAverage)
+  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{
+      false};
+  SimDataValue<int32_t, MakeInt, GetSamplesToAverageName> samplesToAverage{0};
+  SimDataValue<double, MakeDouble, GetDistancePerPulseName> distancePerPulse{1};
+
+  virtual void ResetData();
+};
+extern EncoderData* SimEncoderData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/HALValueInternal.h b/hal/src/main/native/sim/mockdata/HALValueInternal.h
new file mode 100644
index 0000000..f659403
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/HALValueInternal.h
@@ -0,0 +1,27 @@
+/*----------------------------------------------------------------------------*/
+/* 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/I2CData.cpp b/hal/src/main/native/sim/mockdata/I2CData.cpp
new file mode 100644
index 0000000..b228c3b
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/I2CData.cpp
@@ -0,0 +1,58 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <iostream>
+
+#include "../PortsInternal.h"
+#include "I2CDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeI2CData() {
+  static I2CData sid[2];
+  ::hal::SimI2CData = sid;
+}
+}  // namespace init
+}  // namespace hal
+
+I2CData* hal::SimI2CData;
+
+void I2CData::ResetData() {
+  initialized.Reset(false);
+  read.Reset();
+  write.Reset();
+}
+
+void I2CData::Write(int32_t deviceAddress, const uint8_t* dataToSend,
+                    int32_t sendSize) {
+  write(dataToSend, sendSize);
+}
+
+void I2CData::Read(int32_t deviceAddress, uint8_t* buffer, int32_t count) {
+  read(buffer, count);
+}
+
+extern "C" {
+void HALSIM_ResetI2CData(int32_t index) { SimI2CData[index].ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, I2C##CAPINAME, SimI2CData, \
+                               LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+
+#undef DEFINE_CAPI
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                                 \
+  HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI(TYPE, HALSIM, I2C##CAPINAME, SimI2CData, \
+                                      LOWERNAME)
+
+DEFINE_CAPI(HAL_BufferCallback, Read, read)
+DEFINE_CAPI(HAL_ConstBufferCallback, Write, write)
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/I2CDataInternal.h b/hal/src/main/native/sim/mockdata/I2CDataInternal.h
new file mode 100644
index 0000000..1c2df0e
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/I2CDataInternal.h
@@ -0,0 +1,32 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/I2CData.h"
+#include "mockdata/SimCallbackRegistry.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class I2CData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(Read)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(Write)
+
+ public:
+  void Write(int32_t deviceAddress, const uint8_t* dataToSend,
+             int32_t sendSize);
+  void Read(int32_t deviceAddress, uint8_t* buffer, int32_t count);
+
+  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
+  SimCallbackRegistry<HAL_BufferCallback, GetReadName> read;
+  SimCallbackRegistry<HAL_ConstBufferCallback, GetWriteName> write;
+
+  void ResetData();
+};
+extern I2CData* SimI2CData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/PCMData.cpp b/hal/src/main/native/sim/mockdata/PCMData.cpp
new file mode 100644
index 0000000..df68e04
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PCMData.cpp
@@ -0,0 +1,73 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "PCMDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializePCMData() {
+  static PCMData spd[kNumPCMModules];
+  ::hal::SimPCMData = spd;
+}
+}  // namespace init
+}  // namespace hal
+
+PCMData* hal::SimPCMData;
+void PCMData::ResetData() {
+  for (int i = 0; i < kNumSolenoidChannels; i++) {
+    solenoidInitialized[i].Reset(false);
+    solenoidOutput[i].Reset(false);
+  }
+  compressorInitialized.Reset(false);
+  compressorOn.Reset(false);
+  closedLoopEnabled.Reset(true);
+  pressureSwitch.Reset(false);
+  compressorCurrent.Reset(0.0);
+}
+
+extern "C" {
+void HALSIM_ResetPCMData(int32_t index) { SimPCMData[index].ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PCM##CAPINAME, SimPCMData, \
+                               LOWERNAME)
+
+HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(HAL_Bool, HALSIM, PCMSolenoidInitialized,
+                                     SimPCMData, solenoidInitialized)
+HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(HAL_Bool, HALSIM, PCMSolenoidOutput,
+                                     SimPCMData, solenoidOutput)
+DEFINE_CAPI(HAL_Bool, CompressorInitialized, compressorInitialized)
+DEFINE_CAPI(HAL_Bool, CompressorOn, compressorOn)
+DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, closedLoopEnabled)
+DEFINE_CAPI(HAL_Bool, PressureSwitch, pressureSwitch)
+DEFINE_CAPI(double, CompressorCurrent, compressorCurrent)
+
+#define REGISTER(NAME) \
+  SimPCMData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterPCMAllNonSolenoidCallbacks(int32_t index,
+                                               HAL_NotifyCallback callback,
+                                               void* param,
+                                               HAL_Bool initialNotify) {
+  REGISTER(compressorInitialized);
+  REGISTER(compressorOn);
+  REGISTER(closedLoopEnabled);
+  REGISTER(pressureSwitch);
+  REGISTER(compressorCurrent);
+}
+
+void HALSIM_RegisterPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                            HAL_NotifyCallback callback,
+                                            void* param,
+                                            HAL_Bool initialNotify) {
+  REGISTER(solenoidInitialized[channel]);
+  REGISTER(solenoidOutput[channel]);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/PCMDataInternal.h b/hal/src/main/native/sim/mockdata/PCMDataInternal.h
new file mode 100644
index 0000000..4144987
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PCMDataInternal.h
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "../PortsInternal.h"
+#include "mockdata/PCMData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class PCMData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(SolenoidInitialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(SolenoidOutput)
+  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorInitialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorOn)
+  HAL_SIMDATAVALUE_DEFINE_NAME(ClosedLoopEnabled)
+  HAL_SIMDATAVALUE_DEFINE_NAME(PressureSwitch)
+  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorCurrent)
+
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr HAL_Bool
+  GetSolenoidInitializedDefault() {
+    return false;
+  }
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr HAL_Bool
+  GetSolenoidOutputDefault() {
+    return false;
+  }
+
+ public:
+  SimDataValue<HAL_Bool, MakeBoolean, GetSolenoidInitializedName,
+               GetSolenoidInitializedDefault>
+      solenoidInitialized[kNumSolenoidChannels];
+  SimDataValue<HAL_Bool, MakeBoolean, GetSolenoidOutputName,
+               GetSolenoidOutputDefault>
+      solenoidOutput[kNumSolenoidChannels];
+  SimDataValue<HAL_Bool, MakeBoolean, GetCompressorInitializedName>
+      compressorInitialized{false};
+  SimDataValue<HAL_Bool, MakeBoolean, GetCompressorOnName> compressorOn{false};
+  SimDataValue<HAL_Bool, MakeBoolean, GetClosedLoopEnabledName>
+      closedLoopEnabled{true};
+  SimDataValue<HAL_Bool, MakeBoolean, GetPressureSwitchName> pressureSwitch{
+      false};
+  SimDataValue<double, MakeDouble, GetCompressorCurrentName> compressorCurrent{
+      0.0};
+
+  virtual void ResetData();
+};
+extern PCMData* SimPCMData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/PDPData.cpp b/hal/src/main/native/sim/mockdata/PDPData.cpp
new file mode 100644
index 0000000..9c6143e
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PDPData.cpp
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "PDPDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializePDPData() {
+  static PDPData spd[kNumPDPModules];
+  ::hal::SimPDPData = spd;
+}
+}  // namespace init
+}  // namespace hal
+
+PDPData* hal::SimPDPData;
+void PDPData::ResetData() {
+  initialized.Reset(false);
+  temperature.Reset(0.0);
+  voltage.Reset(12.0);
+  for (int i = 0; i < kNumPDPChannels; i++) {
+    current[i].Reset(0.0);
+  }
+}
+
+extern "C" {
+void HALSIM_ResetPDPData(int32_t index) { SimPDPData[index].ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PDP##CAPINAME, SimPDPData, \
+                               LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(double, Temperature, temperature)
+DEFINE_CAPI(double, Voltage, voltage)
+HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(double, HALSIM, PDPCurrent, SimPDPData,
+                                     current)
+
+#define REGISTER(NAME) \
+  SimPDPData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterPDPAllNonCurrentCallbacks(int32_t index, int32_t channel,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(temperature);
+  REGISTER(voltage);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/PDPDataInternal.h b/hal/src/main/native/sim/mockdata/PDPDataInternal.h
new file mode 100644
index 0000000..a7170c7
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PDPDataInternal.h
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "../PortsInternal.h"
+#include "mockdata/PDPData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class PDPData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Temperature)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Voltage)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Current)
+
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr double GetCurrentDefault() {
+    return 0.0;
+  }
+
+ 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>
+      current[kNumPDPChannels];
+
+  virtual void ResetData();
+};
+extern PDPData* SimPDPData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/PWMData.cpp b/hal/src/main/native/sim/mockdata/PWMData.cpp
new file mode 100644
index 0000000..4d2121d
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PWMData.cpp
@@ -0,0 +1,58 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "PWMDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializePWMData() {
+  static PWMData spd[kNumPWMChannels];
+  ::hal::SimPWMData = spd;
+}
+}  // namespace init
+}  // namespace hal
+
+PWMData* hal::SimPWMData;
+void PWMData::ResetData() {
+  initialized.Reset(false);
+  rawValue.Reset(0);
+  speed.Reset(0);
+  position.Reset(0);
+  periodScale.Reset(0);
+  zeroLatch.Reset(false);
+}
+
+extern "C" {
+void HALSIM_ResetPWMData(int32_t index) { SimPWMData[index].ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PWM##CAPINAME, SimPWMData, \
+                               LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(int32_t, RawValue, rawValue)
+DEFINE_CAPI(double, Speed, speed)
+DEFINE_CAPI(double, Position, position)
+DEFINE_CAPI(int32_t, PeriodScale, periodScale)
+DEFINE_CAPI(HAL_Bool, ZeroLatch, zeroLatch)
+
+#define REGISTER(NAME) \
+  SimPWMData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterPWMAllCallbacks(int32_t index, HAL_NotifyCallback callback,
+                                    void* param, HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(rawValue);
+  REGISTER(speed);
+  REGISTER(position);
+  REGISTER(periodScale);
+  REGISTER(zeroLatch);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/PWMDataInternal.h b/hal/src/main/native/sim/mockdata/PWMDataInternal.h
new file mode 100644
index 0000000..85eae44
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PWMDataInternal.h
@@ -0,0 +1,33 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/PWMData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class PWMData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(RawValue)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Speed)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Position)
+  HAL_SIMDATAVALUE_DEFINE_NAME(PeriodScale)
+  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};
+
+  virtual void ResetData();
+};
+extern PWMData* SimPWMData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/RelayData.cpp b/hal/src/main/native/sim/mockdata/RelayData.cpp
new file mode 100644
index 0000000..4623203
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/RelayData.cpp
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "RelayDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeRelayData() {
+  static RelayData srd[kNumRelayHeaders];
+  ::hal::SimRelayData = srd;
+}
+}  // namespace init
+}  // namespace hal
+
+RelayData* hal::SimRelayData;
+void RelayData::ResetData() {
+  initializedForward.Reset(false);
+  initializedReverse.Reset(false);
+  forward.Reset(false);
+  reverse.Reset(false);
+}
+
+extern "C" {
+void HALSIM_ResetRelayData(int32_t index) { SimRelayData[index].ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                              \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, Relay##CAPINAME, SimRelayData, \
+                               LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, InitializedForward, initializedForward)
+DEFINE_CAPI(HAL_Bool, InitializedReverse, initializedReverse)
+DEFINE_CAPI(HAL_Bool, Forward, forward)
+DEFINE_CAPI(HAL_Bool, Reverse, reverse)
+
+#define REGISTER(NAME) \
+  SimRelayData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterRelayAllCallbacks(int32_t index,
+                                      HAL_NotifyCallback callback, void* param,
+                                      HAL_Bool initialNotify) {
+  REGISTER(initializedForward);
+  REGISTER(initializedReverse);
+  REGISTER(forward);
+  REGISTER(reverse);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/RelayDataInternal.h b/hal/src/main/native/sim/mockdata/RelayDataInternal.h
new file mode 100644
index 0000000..88e79ff
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/RelayDataInternal.h
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/RelayData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class RelayData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(InitializedForward)
+  HAL_SIMDATAVALUE_DEFINE_NAME(InitializedReverse)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Forward)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Reverse)
+
+ public:
+  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedForwardName>
+      initializedForward{false};
+  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedReverseName>
+      initializedReverse{false};
+  SimDataValue<HAL_Bool, MakeBoolean, GetForwardName> forward{false};
+  SimDataValue<HAL_Bool, MakeBoolean, GetReverseName> reverse{false};
+
+  virtual void ResetData();
+};
+extern RelayData* SimRelayData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/RoboRioData.cpp b/hal/src/main/native/sim/mockdata/RoboRioData.cpp
new file mode 100644
index 0000000..5cff1d9
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/RoboRioData.cpp
@@ -0,0 +1,88 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "RoboRioDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeRoboRioData() {
+  static RoboRioData srrd[1];
+  ::hal::SimRoboRioData = srrd;
+}
+}  // namespace init
+}  // namespace hal
+
+RoboRioData* hal::SimRoboRioData;
+void RoboRioData::ResetData() {
+  fpgaButton.Reset(false);
+  vInVoltage.Reset(0.0);
+  vInCurrent.Reset(0.0);
+  userVoltage6V.Reset(6.0);
+  userCurrent6V.Reset(0.0);
+  userActive6V.Reset(false);
+  userVoltage5V.Reset(5.0);
+  userCurrent5V.Reset(0.0);
+  userActive5V.Reset(false);
+  userVoltage3V3.Reset(3.3);
+  userCurrent3V3.Reset(0.0);
+  userActive3V3.Reset(false);
+  userFaults6V.Reset(0);
+  userFaults5V.Reset(0);
+  userFaults3V3.Reset(0);
+}
+
+extern "C" {
+void HALSIM_ResetRoboRioData(int32_t index) {
+  SimRoboRioData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                  \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, RoboRio##CAPINAME, \
+                               SimRoboRioData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, FPGAButton, fpgaButton)
+DEFINE_CAPI(double, VInVoltage, vInVoltage)
+DEFINE_CAPI(double, VInCurrent, vInCurrent)
+DEFINE_CAPI(double, UserVoltage6V, userVoltage6V)
+DEFINE_CAPI(double, UserCurrent6V, userCurrent6V)
+DEFINE_CAPI(HAL_Bool, UserActive6V, userActive6V)
+DEFINE_CAPI(double, UserVoltage5V, userVoltage5V)
+DEFINE_CAPI(double, UserCurrent5V, userCurrent5V)
+DEFINE_CAPI(HAL_Bool, UserActive5V, userActive5V)
+DEFINE_CAPI(double, UserVoltage3V3, userVoltage3V3)
+DEFINE_CAPI(double, UserCurrent3V3, userCurrent3V3)
+DEFINE_CAPI(HAL_Bool, UserActive3V3, userActive3V3)
+DEFINE_CAPI(int32_t, UserFaults6V, userFaults6V)
+DEFINE_CAPI(int32_t, UserFaults5V, userFaults5V)
+DEFINE_CAPI(int32_t, UserFaults3V3, userFaults3V3)
+
+#define REGISTER(NAME) \
+  SimRoboRioData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterRoboRioAllCallbacks(int32_t index,
+                                        HAL_NotifyCallback callback,
+                                        void* param, HAL_Bool initialNotify) {
+  REGISTER(fpgaButton);
+  REGISTER(vInVoltage);
+  REGISTER(vInCurrent);
+  REGISTER(userVoltage6V);
+  REGISTER(userCurrent6V);
+  REGISTER(userActive6V);
+  REGISTER(userVoltage5V);
+  REGISTER(userCurrent5V);
+  REGISTER(userActive5V);
+  REGISTER(userVoltage3V3);
+  REGISTER(userCurrent3V3);
+  REGISTER(userActive3V3);
+  REGISTER(userFaults6V);
+  REGISTER(userFaults5V);
+  REGISTER(userFaults3V3);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h
new file mode 100644
index 0000000..92aa0c8
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h
@@ -0,0 +1,52 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/RoboRioData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class RoboRioData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(FPGAButton)
+  HAL_SIMDATAVALUE_DEFINE_NAME(VInVoltage)
+  HAL_SIMDATAVALUE_DEFINE_NAME(VInCurrent)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserVoltage6V)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserCurrent6V)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserActive6V)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserVoltage5V)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserCurrent5V)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserActive5V)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserVoltage3V3)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserCurrent3V3)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserActive3V3)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserFaults6V)
+  HAL_SIMDATAVALUE_DEFINE_NAME(UserFaults5V)
+  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{
+      false};
+  SimDataValue<int32_t, MakeInt, GetUserFaults6VName> userFaults6V{0};
+  SimDataValue<int32_t, MakeInt, GetUserFaults5VName> userFaults5V{0};
+  SimDataValue<int32_t, MakeInt, GetUserFaults3V3Name> userFaults3V3{0};
+
+  virtual void ResetData();
+};
+extern RoboRioData* SimRoboRioData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/SPIAccelerometerData.cpp b/hal/src/main/native/sim/mockdata/SPIAccelerometerData.cpp
new file mode 100644
index 0000000..db7dc1d
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/SPIAccelerometerData.cpp
@@ -0,0 +1,60 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "../PortsInternal.h"
+#include "SPIAccelerometerDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeSPIAccelerometerData() {
+  static SPIAccelerometerData ssad[5];
+  ::hal::SimSPIAccelerometerData = ssad;
+}
+}  // namespace init
+}  // namespace hal
+
+SPIAccelerometerData* hal::SimSPIAccelerometerData;
+void SPIAccelerometerData::ResetData() {
+  active.Reset(false);
+  range.Reset(0);
+  x.Reset(0.0);
+  y.Reset(0.0);
+  z.Reset(0.0);
+}
+
+extern "C" {
+void HALSIM_ResetSPIAccelerometerData(int32_t index) {
+  SimSPIAccelerometerData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                           \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, SPIAccelerometer##CAPINAME, \
+                               SimSPIAccelerometerData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Active, active)
+DEFINE_CAPI(int32_t, Range, range)
+DEFINE_CAPI(double, X, x)
+DEFINE_CAPI(double, Y, y)
+DEFINE_CAPI(double, Z, z)
+
+#define REGISTER(NAME)                                                  \
+  SimSPIAccelerometerData[index].NAME.RegisterCallback(callback, param, \
+                                                       initialNotify)
+
+void HALSIM_RegisterSPIAccelerometerAllCallbcaks(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify) {
+  REGISTER(active);
+  REGISTER(range);
+  REGISTER(x);
+  REGISTER(y);
+  REGISTER(z);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h b/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h
new file mode 100644
index 0000000..ee9f79d
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/SPIAccelerometerData.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+class SPIAccelerometerData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Active)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Range)
+  HAL_SIMDATAVALUE_DEFINE_NAME(X)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Y)
+  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};
+
+  virtual void ResetData();
+};
+extern SPIAccelerometerData* SimSPIAccelerometerData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/SPIData.cpp b/hal/src/main/native/sim/mockdata/SPIData.cpp
new file mode 100644
index 0000000..3afc606
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/SPIData.cpp
@@ -0,0 +1,75 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <iostream>
+
+#include "../PortsInternal.h"
+#include "SPIDataInternal.h"
+
+using namespace hal;
+
+namespace hal {
+namespace init {
+void InitializeSPIData() {
+  static SPIData ssd[5];
+  ::hal::SimSPIData = ssd;
+}
+}  // namespace init
+}  // namespace hal
+
+SPIData* hal::SimSPIData;
+void SPIData::ResetData() {
+  initialized.Reset(false);
+  read.Reset();
+  write.Reset();
+  autoReceivedData.Reset();
+}
+
+int32_t SPIData::Read(uint8_t* buffer, int32_t count) {
+  read(buffer, count);
+  return count;
+}
+
+int32_t SPIData::Write(const uint8_t* dataToSend, int32_t sendSize) {
+  write(dataToSend, sendSize);
+  return sendSize;
+}
+
+int32_t SPIData::Transaction(const uint8_t* dataToSend, uint8_t* dataReceived,
+                             int32_t size) {
+  write(dataToSend, size);
+  read(dataReceived, size);
+  return size;
+}
+
+int32_t SPIData::ReadAutoReceivedData(uint32_t* buffer, int32_t numToRead,
+                                      double timeout, int32_t* status) {
+  int32_t outputCount = 0;
+  autoReceivedData(buffer, numToRead, &outputCount);
+  return outputCount;
+}
+
+extern "C" {
+void HALSIM_ResetSPIData(int32_t index) { SimSPIData[index].ResetData(); }
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, SPI##CAPINAME, SimSPIData, \
+                               LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+
+#undef DEFINE_CAPI
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                                 \
+  HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI(TYPE, HALSIM, SPI##CAPINAME, SimSPIData, \
+                                      LOWERNAME)
+
+DEFINE_CAPI(HAL_BufferCallback, Read, read)
+DEFINE_CAPI(HAL_ConstBufferCallback, Write, write)
+DEFINE_CAPI(HAL_SpiReadAutoReceiveBufferCallback, ReadAutoReceivedData,
+            autoReceivedData)
+
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/SPIDataInternal.h b/hal/src/main/native/sim/mockdata/SPIDataInternal.h
new file mode 100644
index 0000000..b10e741
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/SPIDataInternal.h
@@ -0,0 +1,39 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "mockdata/SPIData.h"
+#include "mockdata/SimCallbackRegistry.h"
+#include "mockdata/SimDataValue.h"
+
+namespace hal {
+
+class SPIData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(Read)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(Write)
+  HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(AutoReceive)
+
+ public:
+  int32_t Read(uint8_t* buffer, int32_t count);
+  int32_t Write(const uint8_t* dataToSend, int32_t sendSize);
+  int32_t Transaction(const uint8_t* dataToSend, uint8_t* dataReceived,
+                      int32_t size);
+  int32_t ReadAutoReceivedData(uint32_t* buffer, int32_t numToRead,
+                               double timeout, int32_t* status);
+
+  SimDataValue<HAL_Bool, MakeBoolean, GetInitializedName> initialized{false};
+  SimCallbackRegistry<HAL_BufferCallback, GetReadName> read;
+  SimCallbackRegistry<HAL_ConstBufferCallback, GetWriteName> write;
+  SimCallbackRegistry<HAL_SpiReadAutoReceiveBufferCallback, GetAutoReceiveName>
+      autoReceivedData;
+
+  void ResetData();
+};
+extern SPIData* SimSPIData;
+}  // namespace hal
diff --git a/hal/src/test/java/edu/wpi/first/hal/sim/AccelerometerSimTest.java b/hal/src/test/java/edu/wpi/first/hal/sim/AccelerometerSimTest.java
new file mode 100644
index 0000000..383165c
--- /dev/null
+++ b/hal/src/test/java/edu/wpi/first/hal/sim/AccelerometerSimTest.java
@@ -0,0 +1,42 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.hal.sim;
+
+import org.junit.jupiter.api.Test;
+
+import edu.wpi.first.hal.AccelerometerJNI;
+import edu.wpi.first.hal.HAL;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class AccelerometerSimTest {
+  static class TriggeredStore {
+    public boolean m_wasTriggered;
+    public boolean m_setValue = true;
+  }
+
+  @Test
+  void testCallbacks() {
+    HAL.initialize(500, 0);
+    AccelerometerSim sim = new AccelerometerSim();
+    sim.resetData();
+
+    TriggeredStore store = new TriggeredStore();
+
+    try (CallbackStore cb = sim.registerActiveCallback((s, v) -> {
+      store.m_wasTriggered = true;
+      store.m_setValue = v.getBoolean();
+    }, false)) {
+      assertFalse(store.m_wasTriggered);
+      AccelerometerJNI.setAccelerometerActive(true);
+      assertTrue(store.m_wasTriggered);
+      assertTrue(store.m_setValue);
+    }
+  }
+}
diff --git a/hal/src/test/native/cpp/HALTests.cpp b/hal/src/test/native/cpp/HALTests.cpp
new file mode 100644
index 0000000..b387c14
--- /dev/null
+++ b/hal/src/test/native/cpp/HALTests.cpp
@@ -0,0 +1,22 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/Solenoid.h"
+
+namespace hal {
+TEST(HALTests, RuntimeType) {
+  EXPECT_EQ(HAL_RuntimeType::HAL_Mock, HAL_GetRuntimeType());
+}
+
+TEST(HALSOLENOID, SolenoidTest) {
+  int32_t status = 0;
+  HAL_InitializeSolenoidPort(0, &status);
+  EXPECT_NE(status, 0);
+}
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/can/CANTest.cpp b/hal/src/test/native/cpp/can/CANTest.cpp
new file mode 100644
index 0000000..6f5549c
--- /dev/null
+++ b/hal/src/test/native/cpp/can/CANTest.cpp
@@ -0,0 +1,83 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/CANAPI.h"
+#include "hal/HAL.h"
+#include "mockdata/CanData.h"
+
+namespace hal {
+struct CANTestStore {
+  CANTestStore(int32_t deviceId, int32_t* status) {
+    this->deviceId = deviceId;
+    handle = HAL_InitializeCAN(
+        HAL_CANManufacturer::HAL_CAN_Man_kTeamUse, deviceId,
+        HAL_CANDeviceType::HAL_CAN_Dev_kMiscellaneous, status);
+  }
+
+  ~CANTestStore() {
+    if (handle != HAL_kInvalidHandle) {
+      HAL_CleanCAN(handle);
+    }
+  }
+
+  int32_t deviceId;
+  HAL_CANHandle handle;
+};
+
+struct CANReceiveCallbackStore {
+  explicit CANReceiveCallbackStore(int32_t handle) { this->handle = handle; }
+  ~CANReceiveCallbackStore() { HALSIM_CancelCanReceiveMessageCallback(handle); }
+  int32_t handle;
+};
+
+struct CANSendCallbackStore {
+  explicit CANSendCallbackStore(int32_t handle) { this->handle = handle; }
+  ~CANSendCallbackStore() { HALSIM_CancelCanSendMessageCallback(handle); }
+  int32_t handle;
+};
+
+TEST(HALCanTests, CanIdPackingTest) {
+  int32_t status = 0;
+  int32_t deviceId = 12;
+  CANTestStore testStore(deviceId, &status);
+  ASSERT_EQ(0, status);
+
+  std::pair<int32_t, bool> storePair;
+  storePair.second = false;
+
+  auto cbHandle = HALSIM_RegisterCanSendMessageCallback(
+      [](const char* name, void* param, uint32_t messageID, const uint8_t* data,
+         uint8_t dataSize, int32_t periodMs, int32_t* status) {
+        std::pair<int32_t, bool>* paramI =
+            reinterpret_cast<std::pair<int32_t, bool>*>(param);
+        paramI->first = messageID;
+        paramI->second = true;
+      },
+      &storePair);
+
+  CANSendCallbackStore cbStore(cbHandle);
+  uint8_t data[8];
+
+  int32_t apiId = 42;
+
+  HAL_WriteCANPacket(testStore.handle, data, 8, 42, &status);
+
+  ASSERT_EQ(0, status);
+
+  ASSERT_TRUE(storePair.second);
+
+  ASSERT_NE(0, storePair.first);
+
+  ASSERT_EQ(deviceId, storePair.first & 0x3F);
+  ASSERT_EQ(apiId, (storePair.first & 0x0000FFC0) >> 6);
+  ASSERT_EQ(static_cast<int32_t>(HAL_CANManufacturer::HAL_CAN_Man_kTeamUse),
+            (storePair.first & 0x00FF0000) >> 16);
+  ASSERT_EQ(static_cast<int32_t>(HAL_CANDeviceType::HAL_CAN_Dev_kMiscellaneous),
+            (storePair.first & 0x1F000000) >> 24);
+}
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/handles/HandleTests.cpp b/hal/src/test/native/cpp/handles/HandleTests.cpp
new file mode 100644
index 0000000..e893c78
--- /dev/null
+++ b/hal/src/test/native/cpp/handles/HandleTests.cpp
@@ -0,0 +1,28 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/handles/IndexedClassedHandleResource.h"
+
+#define HAL_TestHandle HAL_Handle
+
+namespace {
+class MyTestClass {};
+}  // namespace
+
+namespace hal {
+TEST(HandleTests, ClassedHandleTest) {
+  hal::IndexedClassedHandleResource<HAL_TestHandle, MyTestClass, 8,
+                                    HAL_HandleEnum::Vendor>
+      testClass;
+  int32_t status = 0;
+  testClass.Allocate(0, std::make_unique<MyTestClass>(), &status);
+  EXPECT_EQ(0, status);
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/main.cpp b/hal/src/test/native/cpp/main.cpp
new file mode 100644
index 0000000..33990f0
--- /dev/null
+++ b/hal/src/test/native/cpp/main.cpp
@@ -0,0 +1,16 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+
+int main(int argc, char** argv) {
+  HAL_Initialize(500, 0);
+  ::testing::InitGoogleTest(&argc, argv);
+  int ret = RUN_ALL_TESTS();
+  return ret;
+}
diff --git a/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp b/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp
new file mode 100644
index 0000000..791be79
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp
@@ -0,0 +1,80 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/AnalogInput.h"
+#include "hal/HAL.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/AnalogInData.h"
+
+namespace hal {
+
+std::string gTestAnalogInCallbackName;
+HAL_Value gTestAnalogInCallbackValue;
+
+void TestAnalogInInitializationCallback(const char* name, void* param,
+                                        const struct HAL_Value* value) {
+  gTestAnalogInCallbackName = name;
+  gTestAnalogInCallbackValue = *value;
+}
+
+TEST(AnalogInSimTests, TestAnalogInInitialization) {
+  const int INDEX_TO_TEST = 1;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterAnalogInInitializedCallback(
+      INDEX_TO_TEST, &TestAnalogInInitializationCallback, &callbackParam,
+      false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status;
+  HAL_PortHandle portHandle;
+  HAL_DigitalHandle analogInHandle;
+
+  // Use out of range index
+  status = 0;
+  portHandle = 8000;
+  gTestAnalogInCallbackName = "Unset";
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, analogInHandle);
+  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_STREQ("Unset", gTestAnalogInCallbackName.c_str());
+
+  // Successful setup
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestAnalogInCallbackName = "Unset";
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != analogInHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestAnalogInCallbackName.c_str());
+
+  // Double initialize... should fail
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestAnalogInCallbackName = "Unset";
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, analogInHandle);
+  EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
+  EXPECT_STREQ("Unset", gTestAnalogInCallbackName.c_str());
+
+  // Reset, should allow you to re-register
+  hal::HandleBase::ResetGlobalHandles();
+  HALSIM_ResetAnalogInData(INDEX_TO_TEST);
+  callbackId = HALSIM_RegisterAnalogInInitializedCallback(
+      INDEX_TO_TEST, &TestAnalogInInitializationCallback, &callbackParam,
+      false);
+
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestAnalogInCallbackName = "Unset";
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != analogInHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestAnalogInCallbackName.c_str());
+}
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp b/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp
new file mode 100644
index 0000000..8f6d6f0
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp
@@ -0,0 +1,80 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/AnalogOutput.h"
+#include "hal/HAL.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/AnalogOutData.h"
+
+namespace hal {
+
+std::string gTestAnalogOutCallbackName;
+HAL_Value gTestAnalogOutCallbackValue;
+
+void TestAnalogOutInitializationCallback(const char* name, void* param,
+                                         const struct HAL_Value* value) {
+  gTestAnalogOutCallbackName = name;
+  gTestAnalogOutCallbackValue = *value;
+}
+
+TEST(AnalogOutSimTests, TestAnalogOutInitialization) {
+  const int INDEX_TO_TEST = 1;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterAnalogOutInitializedCallback(
+      INDEX_TO_TEST, &TestAnalogOutInitializationCallback, &callbackParam,
+      false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status;
+  HAL_PortHandle portHandle;
+  HAL_DigitalHandle analogOutHandle;
+
+  // Use out of range index
+  status = 0;
+  portHandle = 8000;
+  gTestAnalogOutCallbackName = "Unset";
+  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, analogOutHandle);
+  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_STREQ("Unset", gTestAnalogOutCallbackName.c_str());
+
+  // Successful setup
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestAnalogOutCallbackName = "Unset";
+  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != analogOutHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestAnalogOutCallbackName.c_str());
+
+  // Double initialize... should fail
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestAnalogOutCallbackName = "Unset";
+  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, analogOutHandle);
+  EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
+  EXPECT_STREQ("Unset", gTestAnalogOutCallbackName.c_str());
+
+  // Reset, should allow you to re-register
+  hal::HandleBase::ResetGlobalHandles();
+  HALSIM_ResetAnalogOutData(INDEX_TO_TEST);
+  callbackId = HALSIM_RegisterAnalogOutInitializedCallback(
+      INDEX_TO_TEST, &TestAnalogOutInitializationCallback, &callbackParam,
+      false);
+
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestAnalogOutCallbackName = "Unset";
+  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != analogOutHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestAnalogOutCallbackName.c_str());
+}
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/DIODataTests.cpp b/hal/src/test/native/cpp/mockdata/DIODataTests.cpp
new file mode 100644
index 0000000..19fe994
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/DIODataTests.cpp
@@ -0,0 +1,81 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/DIO.h"
+#include "hal/HAL.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/DIOData.h"
+
+namespace hal {
+
+std::string gTestDigitalIoCallbackName;
+HAL_Value gTestDigitalIoCallbackValue;
+
+void TestDigitalIoInitializationCallback(const char* name, void* param,
+                                         const struct HAL_Value* value) {
+  gTestDigitalIoCallbackName = name;
+  gTestDigitalIoCallbackValue = *value;
+}
+
+TEST(DigitalIoSimTests, TestDigitalIoInitialization) {
+  const int INDEX_TO_TEST = 3;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterDIOInitializedCallback(
+      INDEX_TO_TEST, &TestDigitalIoInitializationCallback, &callbackParam,
+      false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status;
+  HAL_PortHandle portHandle;
+  HAL_DigitalHandle digitalIoHandle;
+
+  // Use out of range index
+  status = 0;
+  portHandle = 8000;
+  gTestDigitalIoCallbackName = "Unset";
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, digitalIoHandle);
+  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_STREQ("Unset", gTestDigitalIoCallbackName.c_str());
+
+  // Successful setup
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestDigitalIoCallbackName = "Unset";
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != digitalIoHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestDigitalIoCallbackName.c_str());
+
+  // Double initialize... should fail
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestDigitalIoCallbackName = "Unset";
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, digitalIoHandle);
+  EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
+  EXPECT_STREQ("Unset", gTestDigitalIoCallbackName.c_str());
+
+  // Reset, should allow you to re-register
+  hal::HandleBase::ResetGlobalHandles();
+  HALSIM_ResetDIOData(INDEX_TO_TEST);
+  callbackId = HALSIM_RegisterDIOInitializedCallback(
+      INDEX_TO_TEST, &TestDigitalIoInitializationCallback, &callbackParam,
+      false);
+
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestDigitalIoCallbackName = "Unset";
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != digitalIoHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestDigitalIoCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/DriverStationDataTests.cpp b/hal/src/test/native/cpp/mockdata/DriverStationDataTests.cpp
new file mode 100644
index 0000000..35c0d54
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/DriverStationDataTests.cpp
@@ -0,0 +1,143 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <cstring>
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/Solenoid.h"
+#include "mockdata/DriverStationData.h"
+
+namespace hal {
+
+TEST(DriverStationTests, JoystickTests) {
+  HAL_JoystickAxes axes;
+  HAL_JoystickPOVs povs;
+  HAL_JoystickButtons buttons;
+
+  // Check default values before anything has been set
+  for (int joystickNum = 0; joystickNum < 6; ++joystickNum) {
+    HAL_GetJoystickAxes(joystickNum, &axes);
+    HAL_GetJoystickPOVs(joystickNum, &povs);
+    HAL_GetJoystickButtons(joystickNum, &buttons);
+
+    EXPECT_EQ(0, axes.count);
+    for (int i = 0; i < HAL_kMaxJoystickAxes; ++i) {
+      EXPECT_EQ(0, axes.axes[i]);
+    }
+
+    EXPECT_EQ(0, povs.count);
+    for (int i = 0; i < HAL_kMaxJoystickPOVs; ++i) {
+      EXPECT_EQ(0, povs.povs[i]);
+    }
+
+    EXPECT_EQ(0, buttons.count);
+    EXPECT_EQ(0u, buttons.buttons);
+  }
+
+  HAL_JoystickAxes set_axes;
+  std::memset(&set_axes, 0, sizeof(HAL_JoystickAxes));
+  HAL_JoystickPOVs set_povs;
+  std::memset(&set_povs, 0, sizeof(HAL_JoystickPOVs));
+  HAL_JoystickButtons set_buttons;
+  std::memset(&set_buttons, 0, sizeof(HAL_JoystickButtons));
+
+  // Set values
+  int joystickUnderTest = 4;
+  set_axes.count = 5;
+  for (int i = 0; i < set_axes.count; ++i) {
+    set_axes.axes[i] = i * .125;
+  }
+
+  set_povs.count = 3;
+  for (int i = 0; i < set_povs.count; ++i) {
+    set_povs.povs[i] = i * 15 + 12;
+  }
+
+  set_buttons.count = 8;
+  set_buttons.buttons = 0xDEADBEEF;
+
+  HALSIM_SetJoystickAxes(joystickUnderTest, &set_axes);
+  HALSIM_SetJoystickPOVs(joystickUnderTest, &set_povs);
+  HALSIM_SetJoystickButtons(joystickUnderTest, &set_buttons);
+
+  // Check the set values
+  HAL_GetJoystickAxes(joystickUnderTest, &axes);
+  HAL_GetJoystickPOVs(joystickUnderTest, &povs);
+  HAL_GetJoystickButtons(joystickUnderTest, &buttons);
+
+  EXPECT_EQ(5, axes.count);
+  EXPECT_NEAR(0.000, axes.axes[0], 0.000001);
+  EXPECT_NEAR(0.125, axes.axes[1], 0.000001);
+  EXPECT_NEAR(0.250, axes.axes[2], 0.000001);
+  EXPECT_NEAR(0.375, axes.axes[3], 0.000001);
+  EXPECT_NEAR(0.500, axes.axes[4], 0.000001);
+  EXPECT_NEAR(0, axes.axes[5], 0.000001);  // Should not have been set, still 0
+  EXPECT_NEAR(0, axes.axes[6], 0.000001);  // Should not have been set, still 0
+
+  EXPECT_EQ(3, povs.count);
+  EXPECT_EQ(12, povs.povs[0]);
+  EXPECT_EQ(27, povs.povs[1]);
+  EXPECT_EQ(42, povs.povs[2]);
+  EXPECT_EQ(0, povs.povs[3]);  // Should not have been set, still 0
+  EXPECT_EQ(0, povs.povs[4]);  // Should not have been set, still 0
+  EXPECT_EQ(0, povs.povs[5]);  // Should not have been set, still 0
+  EXPECT_EQ(0, povs.povs[6]);  // Should not have been set, still 0
+
+  EXPECT_EQ(8, buttons.count);
+  EXPECT_EQ(0xDEADBEEFu, buttons.buttons);
+
+  // Reset
+  HALSIM_ResetDriverStationData();
+  for (int joystickNum = 0; joystickNum < 6; ++joystickNum) {
+    HAL_GetJoystickAxes(joystickNum, &axes);
+    HAL_GetJoystickPOVs(joystickNum, &povs);
+    HAL_GetJoystickButtons(joystickNum, &buttons);
+
+    EXPECT_EQ(0, axes.count);
+    for (int i = 0; i < HAL_kMaxJoystickAxes; ++i) {
+      EXPECT_EQ(0, axes.axes[i]);
+    }
+
+    EXPECT_EQ(0, povs.count);
+    for (int i = 0; i < HAL_kMaxJoystickPOVs; ++i) {
+      EXPECT_EQ(0, povs.povs[i]);
+    }
+
+    EXPECT_EQ(0, buttons.count);
+    EXPECT_EQ(0u, buttons.buttons);
+  }
+}
+
+TEST(DriverStationTests, EventInfoTest) {
+  std::string eventName = "UnitTest";
+  std::string gameData = "Insert game specific info here :D";
+  HAL_MatchInfo info;
+  std::snprintf(info.eventName, sizeof(info.eventName), "%s",
+                eventName.c_str());
+  std::snprintf(reinterpret_cast<char*>(info.gameSpecificMessage),
+                sizeof(info.gameSpecificMessage), "%s", gameData.c_str());
+  info.gameSpecificMessageSize = gameData.size();
+  info.matchNumber = 5;
+  info.matchType = HAL_MatchType::HAL_kMatchType_qualification;
+  info.replayNumber = 42;
+  HALSIM_SetMatchInfo(&info);
+
+  HAL_MatchInfo dataBack;
+  HAL_GetMatchInfo(&dataBack);
+
+  std::string gsm{reinterpret_cast<char*>(dataBack.gameSpecificMessage),
+                  dataBack.gameSpecificMessageSize};
+
+  EXPECT_STREQ(eventName.c_str(), dataBack.eventName);
+  EXPECT_EQ(gameData, gsm);
+  EXPECT_EQ(5, dataBack.matchNumber);
+  EXPECT_EQ(HAL_MatchType::HAL_kMatchType_qualification, dataBack.matchType);
+  EXPECT_EQ(42, dataBack.replayNumber);
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/I2CDataTests.cpp b/hal/src/test/native/cpp/mockdata/I2CDataTests.cpp
new file mode 100644
index 0000000..3a8e01c
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/I2CDataTests.cpp
@@ -0,0 +1,43 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/I2C.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/I2CData.h"
+
+namespace hal {
+
+std::string gTestI2CCallbackName;
+HAL_Value gTestI2CCallbackValue;
+
+void TestI2CInitializationCallback(const char* name, void* param,
+                                   const struct HAL_Value* value) {
+  gTestI2CCallbackName = name;
+  gTestI2CCallbackValue = *value;
+}
+
+TEST(I2CSimTests, TestI2CInitialization) {
+  const int INDEX_TO_TEST = 1;
+
+  int32_t status;
+  HAL_I2CPort port;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterI2CInitializedCallback(
+      INDEX_TO_TEST, &TestI2CInitializationCallback, &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  status = 0;
+  port = HAL_I2C_kMXP;
+  gTestI2CCallbackName = "Unset";
+  HAL_InitializeI2C(port, &status);
+  EXPECT_STREQ("Initialized", gTestI2CCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/PCMDataTests.cpp b/hal/src/test/native/cpp/mockdata/PCMDataTests.cpp
new file mode 100644
index 0000000..50a8ae3
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/PCMDataTests.cpp
@@ -0,0 +1,83 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/Solenoid.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/PCMData.h"
+
+namespace hal {
+
+std::string gTestSolenoidCallbackName;
+HAL_Value gTestSolenoidCallbackValue;
+
+void TestSolenoidInitializationCallback(const char* name, void* param,
+                                        const struct HAL_Value* value) {
+  gTestSolenoidCallbackName = name;
+  gTestSolenoidCallbackValue = *value;
+}
+
+TEST(SolenoidSimTests, TestSolenoidInitialization) {
+  const int MODULE_TO_TEST = 2;
+  const int CHANNEL_TO_TEST = 3;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterPCMSolenoidInitializedCallback(
+      MODULE_TO_TEST, CHANNEL_TO_TEST, &TestSolenoidInitializationCallback,
+      &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status;
+  HAL_PortHandle portHandle;
+  HAL_DigitalHandle solenoidHandle;
+
+  // Use out of range index
+  status = 0;
+  portHandle = 8000;
+  gTestSolenoidCallbackName = "Unset";
+  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, solenoidHandle);
+  EXPECT_EQ(HAL_HANDLE_ERROR, status);
+  EXPECT_STREQ("Unset", gTestSolenoidCallbackName.c_str());
+
+  // Successful setup
+  status = 0;
+  portHandle = HAL_GetPortWithModule(MODULE_TO_TEST, CHANNEL_TO_TEST);
+  gTestSolenoidCallbackName = "Unset";
+  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != solenoidHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("SolenoidInitialized", gTestSolenoidCallbackName.c_str());
+
+  // Double initialize... should fail
+  status = 0;
+  portHandle = HAL_GetPortWithModule(MODULE_TO_TEST, CHANNEL_TO_TEST);
+  gTestSolenoidCallbackName = "Unset";
+  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, solenoidHandle);
+  EXPECT_EQ(NO_AVAILABLE_RESOURCES, status);
+  EXPECT_STREQ("Unset", gTestSolenoidCallbackName.c_str());
+
+  // Reset, should allow you to re-register
+  hal::HandleBase::ResetGlobalHandles();
+  HALSIM_ResetPCMData(MODULE_TO_TEST);
+  callbackId = HALSIM_RegisterPCMSolenoidInitializedCallback(
+      MODULE_TO_TEST, CHANNEL_TO_TEST, &TestSolenoidInitializationCallback,
+      &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  status = 0;
+  portHandle = HAL_GetPortWithModule(MODULE_TO_TEST, CHANNEL_TO_TEST);
+  gTestSolenoidCallbackName = "Unset";
+  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != solenoidHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("SolenoidInitialized", gTestSolenoidCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/PDPDataTests.cpp b/hal/src/test/native/cpp/mockdata/PDPDataTests.cpp
new file mode 100644
index 0000000..a46454f
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/PDPDataTests.cpp
@@ -0,0 +1,43 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/PDP.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/PDPData.h"
+
+namespace hal {
+
+std::string gTestPdpCallbackName;
+HAL_Value gTestPdpCallbackValue;
+
+void TestPdpInitializationCallback(const char* name, void* param,
+                                   const struct HAL_Value* value) {
+  gTestPdpCallbackName = name;
+  gTestPdpCallbackValue = *value;
+}
+
+TEST(PdpSimTests, TestPdpInitialization) {
+  const int INDEX_TO_TEST = 1;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterPDPInitializedCallback(
+      INDEX_TO_TEST, &TestPdpInitializationCallback, &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status;
+
+  // Use out of range index
+  status = 0;
+  gTestPdpCallbackName = "Unset";
+  HAL_InitializePDP(INDEX_TO_TEST, &status);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestPdpCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp b/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp
new file mode 100644
index 0000000..447a510
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp
@@ -0,0 +1,78 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/PWM.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/PWMData.h"
+
+namespace hal {
+
+std::string gTestPwmCallbackName;
+HAL_Value gTestPwmCallbackValue;
+
+void TestPwmInitializationCallback(const char* name, void* param,
+                                   const struct HAL_Value* value) {
+  gTestPwmCallbackName = name;
+  gTestPwmCallbackValue = *value;
+}
+
+TEST(PWMSimTests, TestPwmInitialization) {
+  const int INDEX_TO_TEST = 7;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterPWMInitializedCallback(
+      INDEX_TO_TEST, &TestPwmInitializationCallback, &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status;
+  HAL_PortHandle portHandle;
+  HAL_DigitalHandle pwmHandle;
+
+  // Use out of range index
+  status = 0;
+  portHandle = 8000;
+  gTestPwmCallbackName = "Unset";
+  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, pwmHandle);
+  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_STREQ("Unset", gTestPwmCallbackName.c_str());
+
+  // Successful setup
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestPwmCallbackName = "Unset";
+  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != pwmHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestPwmCallbackName.c_str());
+
+  // Double initialize... should fail
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestPwmCallbackName = "Unset";
+  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, pwmHandle);
+  EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
+  EXPECT_STREQ("Unset", gTestPwmCallbackName.c_str());
+
+  // Reset, should allow you to re-register
+  hal::HandleBase::ResetGlobalHandles();
+  HALSIM_ResetPWMData(INDEX_TO_TEST);
+  callbackId = HALSIM_RegisterPWMInitializedCallback(
+      INDEX_TO_TEST, &TestPwmInitializationCallback, &callbackParam, false);
+
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestPwmCallbackName = "Unset";
+  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != pwmHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestPwmCallbackName.c_str());
+}
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp b/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp
new file mode 100644
index 0000000..408657a
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp
@@ -0,0 +1,79 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/Relay.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/RelayData.h"
+
+namespace hal {
+
+std::string gTestRelayCallbackName;
+HAL_Value gTestRelayCallbackValue;
+
+void TestRelayInitializationCallback(const char* name, void* param,
+                                     const struct HAL_Value* value) {
+  gTestRelayCallbackName = name;
+  gTestRelayCallbackValue = *value;
+}
+
+TEST(RelaySimTests, TestRelayInitialization) {
+  const int INDEX_TO_TEST = 3;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterRelayInitializedForwardCallback(
+      INDEX_TO_TEST, &TestRelayInitializationCallback, &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status;
+  HAL_PortHandle portHandle;
+  HAL_DigitalHandle pdpHandle;
+
+  // Use out of range index
+  status = 0;
+  portHandle = 8000;
+  gTestRelayCallbackName = "Unset";
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, pdpHandle);
+  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_STREQ("Unset", gTestRelayCallbackName.c_str());
+
+  // Successful setup
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestRelayCallbackName = "Unset";
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != pdpHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("InitializedForward", gTestRelayCallbackName.c_str());
+
+  // Double initialize... should fail
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestRelayCallbackName = "Unset";
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, pdpHandle);
+  EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
+  EXPECT_STREQ("Unset", gTestRelayCallbackName.c_str());
+
+  // Reset, should allow you to re-register
+  hal::HandleBase::ResetGlobalHandles();
+  HALSIM_ResetRelayData(INDEX_TO_TEST);
+  callbackId = HALSIM_RegisterRelayInitializedForwardCallback(
+      INDEX_TO_TEST, &TestRelayInitializationCallback, &callbackParam, false);
+
+  status = 0;
+  portHandle = HAL_GetPort(INDEX_TO_TEST);
+  gTestRelayCallbackName = "Unset";
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != pdpHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("InitializedForward", gTestRelayCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/SPIDataTests.cpp b/hal/src/test/native/cpp/mockdata/SPIDataTests.cpp
new file mode 100644
index 0000000..64c8555
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/SPIDataTests.cpp
@@ -0,0 +1,43 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/SPI.h"
+#include "hal/handles/HandlesInternal.h"
+#include "mockdata/SPIData.h"
+
+namespace hal {
+
+std::string gTestSpiCallbackName;
+HAL_Value gTestSpiCallbackValue;
+
+void TestSpiInitializationCallback(const char* name, void* param,
+                                   const struct HAL_Value* value) {
+  gTestSpiCallbackName = name;
+  gTestSpiCallbackValue = *value;
+}
+
+TEST(SpiSimTests, TestSpiInitialization) {
+  const int INDEX_TO_TEST = 2;
+
+  int32_t status;
+  HAL_SPIPort port;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterSPIInitializedCallback(
+      INDEX_TO_TEST, &TestSpiInitializationCallback, &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  status = 0;
+  port = HAL_SPI_kOnboardCS2;
+  gTestSpiCallbackName = "Unset";
+  HAL_InitializeSPI(port, &status);
+  EXPECT_STREQ("Initialized", gTestSpiCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/sim/AccelerometerSimTest.cpp b/hal/src/test/native/cpp/sim/AccelerometerSimTest.cpp
new file mode 100644
index 0000000..54be6e3
--- /dev/null
+++ b/hal/src/test/native/cpp/sim/AccelerometerSimTest.cpp
@@ -0,0 +1,42 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/Accelerometer.h"
+#include "hal/HAL.h"
+#include "simulation/AccelerometerSim.h"
+
+using namespace frc::sim;
+
+namespace hal {
+
+TEST(AcclerometerSimTests, TestActiveCallback) {
+  HAL_Initialize(500, 0);
+
+  AccelerometerSim sim{0};
+
+  sim.ResetData();
+
+  bool wasTriggered = false;
+  bool lastValue = false;
+
+  auto cb = sim.RegisterActiveCallback(
+      [&](wpi::StringRef name, const HAL_Value* value) {
+        wasTriggered = true;
+        lastValue = value->data.v_boolean;
+      },
+      false);
+
+  EXPECT_FALSE(wasTriggered);
+
+  HAL_SetAccelerometerActive(true);
+
+  EXPECT_TRUE(wasTriggered);
+  EXPECT_TRUE(lastValue);
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/sim/SimInitializationTest.cpp b/hal/src/test/native/cpp/sim/SimInitializationTest.cpp
new file mode 100644
index 0000000..fdd34cd
--- /dev/null
+++ b/hal/src/test/native/cpp/sim/SimInitializationTest.cpp
@@ -0,0 +1,49 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "simulation/AccelerometerSim.h"
+#include "simulation/AnalogGyroSim.h"
+#include "simulation/AnalogInSim.h"
+#include "simulation/AnalogOutSim.h"
+#include "simulation/AnalogTriggerSim.h"
+#include "simulation/DIOSim.h"
+#include "simulation/DigitalPWMSim.h"
+#include "simulation/DriverStationSim.h"
+#include "simulation/EncoderSim.h"
+#include "simulation/PCMSim.h"
+#include "simulation/PDPSim.h"
+#include "simulation/PWMSim.h"
+#include "simulation/RelaySim.h"
+#include "simulation/RoboRioSim.h"
+#include "simulation/SPIAccelerometerSim.h"
+
+using namespace frc::sim;
+
+namespace hal {
+
+TEST(SimInitializationTests, TestAllInitialize) {
+  HAL_Initialize(500, 0);
+  AccelerometerSim acsim{0};
+  AnalogGyroSim agsim{0};
+  AnalogInSim aisim{0};
+  AnalogOutSim aosim{0};
+  AnalogTriggerSim atsim{0};
+  DigitalPWMSim dpsim{0};
+  DIOSim diosim{0};
+  DriverStationSim dssim;
+  (void)dssim;
+  EncoderSim esim{0};
+  PCMSim pcmsim{0};
+  PDPSim pdpsim{0};
+  PWMSim pwmsim{0};
+  RelaySim rsim{0};
+  RoboRioSim rrsim{0};
+  SPIAccelerometerSim sasim{0};
+}
+}  // namespace hal