Put in new allwiplib-2018 and packaged the large files

added new allwpilib

added ntcore

Added new wpiutil

Change-Id: I5bbb966a69ac2fbdce056e4c092a13f246dbaa6a
diff --git a/third_party/allwpilib_2018/wpilibj/build.gradle b/third_party/allwpilib_2018/wpilibj/build.gradle
new file mode 100644
index 0000000..080eb92
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/build.gradle
@@ -0,0 +1,320 @@
+import edu.wpi.first.nativeutils.NativeUtils
+import org.gradle.api.file.FileCollection
+import org.gradle.internal.os.OperatingSystem
+
+repositories {
+    mavenCentral()
+}
+
+apply plugin: 'cpp'
+apply plugin: 'visual-studio'
+apply plugin: 'edu.wpi.first.NativeUtils'
+apply plugin: 'java'
+apply plugin: 'net.ltgt.errorprone'
+apply plugin: 'pmd'
+apply plugin: TestingModelBasePlugin
+
+configurations.errorprone {
+    resolutionStrategy.force 'com.google.errorprone:error_prone_core:2.0.9'
+}
+
+apply from: '../config.gradle'
+
+sourceSets {
+    dev
+}
+
+task nativeTestFilesJar(type: Jar) {
+    destinationDir = project.buildDir
+    classifier = "nativeTestFiles"
+
+    project.model {
+        binaries {
+            withType(SharedLibraryBinarySpec) { binary ->
+                if (binary.component.name == 'wpilibJNIStatic') {
+                    from(binary.sharedLibraryFile) {
+                        into NativeUtils.getPlatformPath(binary)
+                    }
+                    dependsOn binary.buildTask
+                }
+            }
+        }
+    }
+}
+
+task run(type: JavaExec) {
+    classpath = sourceSets.dev.runtimeClasspath
+
+    main = 'edu.wpi.first.wpilibj.DevMain'
+}
+
+test.dependsOn nativeTestFilesJar
+run.dependsOn nativeTestFilesJar
+
+def versionClass = """
+package edu.wpi.first.wpilibj.util;
+
+/*
+ * Autogenerated file! Do not manually edit this file. This version is regenerated
+ * any time the publish task is run, or when this file is deleted.
+ */
+
+public final class WPILibVersion {
+  public static final String Version = "${WPILibVersion.version}";
+}
+""".trim()
+
+def wpilibVersionFile = file('src/main/java/edu/wpi/first/wpilibj/util/WPILibVersion.java')
+
+def willPublish = false
+gradle.taskGraph.addTaskExecutionGraphListener { graph ->
+    willPublish = graph.hasTask(publish)
+}
+
+task generateJavaVersion() {
+    description = 'Generates the wpilib version class.'
+    group = 'WPILib'
+
+    // We follow a simple set of checks to determine whether we should generate a new version file:
+    // 1. If the release type is not development, we generate a new verison file
+    // 2. If there is no generated version number, we generate a new version file
+    // 3. If there is a generated build number, and the release type is development, then we will
+    //    only generate if the publish task is run.
+    doLast {
+        if (!WPILibVersion.releaseType.toString().equalsIgnoreCase('official') && !willPublish && wpilibVersionFile.exists()) {
+            return
+        }
+        println "Writing version ${WPILibVersion.version} to $wpilibVersionFile"
+
+        if (wpilibVersionFile.exists()) {
+            wpilibVersionFile.delete()
+        }
+        wpilibVersionFile.write(versionClass)
+    }
+}
+
+clean {
+    delete wpilibVersionFile
+}
+
+compileJava.dependsOn generateJavaVersion
+
+pmd {
+    sourceSets = [sourceSets.main]
+    consoleOutput = true
+    reportsDir = file("$project.buildDir/reports/pmd")
+    ruleSetFiles = files(new File(rootDir, "styleguide/pmd-ruleset.xml"))
+    ruleSets = []
+}
+
+dependencies {
+    compile 'edu.wpi.first.wpiutil:wpiutil-java:3.+'
+    compile 'edu.wpi.first.ntcore:ntcore-java:4.+'
+    compile 'org.opencv:opencv-java:3.2.0'
+    compile 'edu.wpi.first.cscore:cscore-java:1.+'
+    testCompile 'org.hamcrest:hamcrest-all:1.3'
+    testCompile 'junit:junit:4.12'
+    testCompile 'com.google.guava:guava:19.0'
+    testRuntime files(project.nativeTestFilesJar.archivePath)
+    testRuntime 'edu.wpi.first.ntcore:ntcore-jni:4.+:all'
+    testRuntime 'org.opencv:opencv-jni:3.2.0:all'
+    testRuntime 'edu.wpi.first.cscore:cscore-jni:1.+:all'
+    devCompile 'edu.wpi.first.wpiutil:wpiutil-java:3.+'
+    devCompile 'edu.wpi.first.ntcore:ntcore-java:4.+'
+    devCompile 'org.opencv:opencv-java:3.2.0'
+    devCompile 'edu.wpi.first.cscore:cscore-java:1.+'
+    devCompile sourceSets.main.output
+    devRuntime files(project.nativeTestFilesJar.archivePath)
+    devRuntime 'edu.wpi.first.ntcore:ntcore-jni:4.+:all'
+    devRuntime 'org.opencv:opencv-jni:3.2.0:all'
+    devRuntime 'edu.wpi.first.cscore:cscore-jni:1.+:all'
+}
+
+def jniClasses = [
+    'edu.wpi.first.wpilibj.can.CANJNI',
+    'edu.wpi.first.wpilibj.hal.FRCNetComm',
+    'edu.wpi.first.wpilibj.hal.HAL',
+    'edu.wpi.first.wpilibj.hal.HALUtil',
+    'edu.wpi.first.wpilibj.hal.JNIWrapper',
+    'edu.wpi.first.wpilibj.hal.AccelerometerJNI',
+    'edu.wpi.first.wpilibj.hal.AnalogJNI',
+    'edu.wpi.first.wpilibj.hal.AnalogGyroJNI',
+    'edu.wpi.first.wpilibj.hal.ConstantsJNI',
+    'edu.wpi.first.wpilibj.hal.CounterJNI',
+    'edu.wpi.first.wpilibj.hal.DigitalGlitchFilterJNI',
+    'edu.wpi.first.wpilibj.hal.DIOJNI',
+    'edu.wpi.first.wpilibj.hal.EncoderJNI',
+    'edu.wpi.first.wpilibj.hal.I2CJNI',
+    'edu.wpi.first.wpilibj.hal.InterruptJNI',
+    'edu.wpi.first.wpilibj.hal.NotifierJNI',
+    'edu.wpi.first.wpilibj.hal.PortsJNI',
+    'edu.wpi.first.wpilibj.hal.PWMJNI',
+    'edu.wpi.first.wpilibj.hal.RelayJNI',
+    'edu.wpi.first.wpilibj.hal.SPIJNI',
+    'edu.wpi.first.wpilibj.hal.SolenoidJNI',
+    'edu.wpi.first.wpilibj.hal.CompressorJNI',
+    'edu.wpi.first.wpilibj.hal.PDPJNI',
+    'edu.wpi.first.wpilibj.hal.PowerJNI',
+    'edu.wpi.first.wpilibj.hal.SerialPortJNI',
+    'edu.wpi.first.wpilibj.hal.OSSerialPortJNI',
+    'edu.wpi.first.wpilibj.hal.ThreadsJNI',
+]
+
+model {
+    jniConfigs {
+        wpilibJNIShared(JNIConfig) {
+            jniDefinitionClasses = jniClasses
+            jniArmHeaderLocations = [ all: file("${projectDir}/src/arm-linux-jni") ]
+            sourceSets = [ project.sourceSets.main ]
+        }
+        wpilibJNIStatic(JNIConfig) {
+            jniDefinitionClasses = jniClasses
+            jniArmHeaderLocations = [ all: file("${projectDir}/src/arm-linux-jni") ]
+            sourceSets = [ project.sourceSets.main ]
+        }
+    }
+    exportsConfigs {
+        wpilibJNIShared(ExportsConfig) {
+            x86SymbolFilter = { symbols->
+                def retList = []
+                symbols.each { symbol->
+                    if (symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
+                        retList << symbol
+                    }
+                }
+                return retList
+            }
+            x64SymbolFilter = { symbols->
+                def retList = []
+                symbols.each { symbol->
+                    if (symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
+                        retList << symbol
+                    }
+                }
+                return retList
+            }
+        }
+        wpilibJNIStatic(ExportsConfig) {
+            x86SymbolFilter = { symbols->
+                def retList = []
+                symbols.each { symbol->
+                    if (symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
+                        retList << symbol
+                    }
+                }
+                return retList
+            }
+            x64SymbolFilter = { symbols->
+                def retList = []
+                symbols.each { symbol->
+                    if (symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
+                        retList << symbol
+                    }
+                }
+                return retList
+            }
+        }
+    }
+    dependencyConfigs {
+        wpiutil(DependencyConfig) {
+            groupId = 'edu.wpi.first.wpiutil'
+            artifactId = 'wpiutil-cpp'
+            headerClassifier = 'headers'
+            ext = 'zip'
+            version = '3.+'
+            sharedConfigs = [ wpilibJNIShared: [] ]
+            staticConfigs = [ wpilibJNIStatic: [] ]
+        }
+    }
+    components {
+        wpilibJNIStatic(NativeLibrarySpec) {
+            baseName = 'wpilibJNI'
+            binaries.withType(NativeBinarySpec) { binary ->
+                if (binary.targetPlatform.architecture.name == 'athena') {
+                    binary.lib project: ':hal', library: 'halAthena', linkage: 'static'
+                } else {
+                    binary.lib project: ':hal', library: 'halSim', linkage: 'static'
+                }
+            }
+            sources {
+                cpp {
+                    source {
+                        srcDirs = ['src/main/native/cpp']
+                        includes = ['**/*.cpp']
+                    }
+                }
+            }
+        }
+        wpilibJNIShared(NativeLibrarySpec) {
+            baseName = 'wpilibJNI'
+            binaries.withType(NativeBinarySpec) { binary ->
+                if (binary.targetPlatform.architecture.name == 'athena') {
+                    binary.lib project: ':hal', library: 'halAthena', linkage: 'shared'
+                } else {
+                    binary.lib project: ':hal', library: 'halSim', linkage: 'shared'
+                }
+            }
+            sources {
+                cpp {
+                    source {
+                        srcDirs = ['src/main/native/cpp']
+                        includes = ['**/*.cpp']
+                    }
+                }
+            }
+        }
+
+    }
+    binaries {
+        withType(NativeBinarySpec) {
+            project(':ni-libraries').addNiLibrariesToLinker(it)
+        }
+        withType(StaticLibraryBinarySpec) {
+            it.buildable = false
+        }
+    }
+    tasks {
+        getHeaders(Task) {
+            def list = []
+            $.components.each {
+                if (it in NativeLibrarySpec && it.name == 'wpilibJNIStatic') {
+                    it.sources.each {
+                        it.exportedHeaders.srcDirs.each {
+                            list.add(it)
+                        }
+                    }
+                    it.binaries.each {
+                        it.libs.each {
+                            it.includeRoots.each {
+                                list.add(it)
+                            }
+                        }
+                    }
+                }
+            }
+            // use file to normalize this dir
+            list.add(file("$buildDir/wpilibJNIStatic/jniinclude"))
+            list = list.unique(false)
+            doLast {
+                list.each {
+                    print "WPIHEADER: "
+                    println it
+                }
+            }
+        }
+    }
+}
+
+apply from: 'publish.gradle'
+apply from: 'integrationTestingFiles.gradle'
+
+test {
+    testLogging {
+        events "failed"
+        exceptionFormat "full"
+    }
+}
+
+if (project.hasProperty('onlyAthena')) {
+    test.enabled = false
+}
diff --git a/third_party/allwpilib_2018/wpilibj/integrationTestingFiles.gradle b/third_party/allwpilib_2018/wpilibj/integrationTestingFiles.gradle
new file mode 100644
index 0000000..175c7c9
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/integrationTestingFiles.gradle
@@ -0,0 +1,21 @@
+def testOutputFolder = file("${project(':').buildDir}/integrationTestFiles")
+
+model {
+    tasks {
+        copyWpilibJTestLibrariesToOutput(Copy) {
+            destinationDir testOutputFolder
+            $.binaries.each {
+                if (it in SharedLibraryBinarySpec && it.targetPlatform.architecture.name == 'athena') {
+                    def spec = it
+                    dependsOn spec.buildTask
+                    from(spec.sharedLibraryFile) {
+                            into '/libs'
+                    }
+                }
+            }
+            outputs.file testOutputFolder
+            outputs.upToDateWhen { false }
+        }
+        build.dependsOn copyWpilibJTestLibrariesToOutput
+    }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/publish.gradle b/third_party/allwpilib_2018/wpilibj/publish.gradle
new file mode 100644
index 0000000..aab1243
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/publish.gradle
@@ -0,0 +1,170 @@
+apply plugin: 'maven-publish'
+apply plugin: 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin'
+
+if (!hasProperty('releaseType')) {
+    WPILibVersion {
+        releaseType = 'dev'
+    }
+}
+
+def pubVersion
+if (project.hasProperty("publishVersion")) {
+    pubVersion = project.publishVersion
+} else {
+    pubVersion = WPILibVersion.version
+}
+
+def baseArtifactId = 'wpilibj'
+def artifactGroupId = 'edu.wpi.first.wpilibj'
+
+def outputsFolder = file("$project.buildDir/outputs")
+
+task cppSourcesZip(type: Zip) {
+    destinationDir = outputsFolder
+    baseName = 'wpilibJNI'
+    classifier = "sources"
+
+    from(licenseFile) {
+        into '/'
+    }
+
+    from('src/main/native/cpp') {
+        into '/'
+    }
+
+    model {
+        tasks {
+            it.each {
+                if (it in getJNIHeadersClass()) {
+                    from (it.outputs.files) {
+                        into '/'
+                    }
+                    dependsOn it
+                }
+            }
+        }
+    }
+}
+
+task sourcesJar(type: Jar, dependsOn: classes) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+}
+
+task javadoc(type: Javadoc, overwrite: true) {
+    javadoc.options.links("http://docs.oracle.com/javase/8/docs/api/")
+    options.addStringOption "tag", "pre:a:Pre-Condition"
+    options.addStringOption('Xdoclint:accessibility,syntax,html', '-quiet')
+    source = sourceSets.main.allJava
+    failOnError = true
+}
+
+task javadocJar(type: Jar, dependsOn: javadoc) {
+    classifier = 'javadoc'
+    from javadoc.destinationDir
+}
+
+if (project.hasProperty('jenkinsBuild')) {
+    jar {
+        classifier = 'javaArtifact'
+    }
+}
+
+artifacts {
+    archives sourcesJar
+    archives javadocJar
+    archives cppSourcesZip
+}
+
+model {
+    publishing {
+        def wpilibJNIStaticTaskList = createComponentZipTasks($.components, 'wpilibJNIStatic', 'jni', Jar, project, { task, value ->
+            value.each { binary->
+                if (binary.buildable) {
+                    if (binary instanceof SharedLibraryBinarySpec) {
+                        task.dependsOn binary.buildTask
+                        task.from (binary.sharedLibraryFile) {
+                            into getPlatformPath(binary)
+                        }
+                    }
+                }
+            }
+        })
+
+        def wpilibJNISharedTaskList = createComponentZipTasks($.components, 'wpilibJNIShared', 'jni', Jar, project, { task, value ->
+            value.each { binary->
+                if (binary.buildable) {
+                    if (binary instanceof SharedLibraryBinarySpec) {
+                        task.dependsOn binary.buildTask
+                        task.from (binary.sharedLibraryFile) {
+                            into getPlatformPath(binary) + '/shared'
+                        }
+                        task.from(new File(binary.sharedLibraryFile.absolutePath + ".debug")) {
+                            into getPlatformPath(binary) + '/shared'
+                        }
+                    }
+                }
+            }
+        })
+
+        def allSharedTask
+        if (!project.hasProperty('jenkinsBuild')) {
+            allSharedTask = createAllCombined(wpilibJNISharedTaskList, 'wpilibJNIShared', 'jni', Jar, project)
+        }
+
+        def allStaticTask
+        if (!project.hasProperty('jenkinsBuild')) {
+            allStaticTask = createAllCombined(wpilibJNIStaticTaskList, 'wpilibJNIStatic', 'jni', Jar, project)
+        }
+
+        publications {
+            jniShared(MavenPublication) {
+                wpilibJNISharedTaskList.each {
+                    artifact it
+                }
+
+                 if (!project.hasProperty('jenkinsBuild')) {
+                    artifact allSharedTask
+                }
+
+                artifact cppSourcesZip
+
+                artifactId = "${baseArtifactId}-jniShared"
+                groupId artifactGroupId
+                version pubVersion
+            }
+
+            jni(MavenPublication) {
+                wpilibJNIStaticTaskList.each {
+                    artifact it
+                }
+
+                 if (!project.hasProperty('jenkinsBuild')) {
+                    artifact allStaticTask
+                }
+
+                artifact cppSourcesZip
+
+                artifactId = "${baseArtifactId}-jni"
+                groupId artifactGroupId
+                version pubVersion
+            }
+        }
+    }
+}
+
+
+publishing {
+  publications {
+
+    java(MavenPublication) {
+      artifact jar
+      artifact sourcesJar
+      artifact javadocJar
+
+      artifactId = "${baseArtifactId}-java"
+      groupId artifactGroupId
+      version pubVersion
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/LICENSE b/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/LICENSE
new file mode 100644
index 0000000..b40a0f4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/LICENSE
@@ -0,0 +1,347 @@
+The GNU General Public License (GPL)
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share
+and change it.  By contrast, the GNU General Public License is intended to
+guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.  This General Public License applies to
+most of the Free Software Foundation's software and to any other program whose
+authors commit to using it.  (Some other Free Software Foundation software is
+covered by the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.  Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for this service if you wish),
+that you receive source code or can get it if you want it, that you can change
+the software or use pieces of it in new free programs; and that you know you
+can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny
+you these rights or to ask you to surrender the rights.  These restrictions
+translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must give the recipients all the rights that you have.  You must
+make sure that they, too, receive or can get the source code.  And you must
+show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software.  If the
+software is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original, so that any problems introduced
+by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents.  We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program proprietary.
+To prevent this, we have made it clear that any patent must be licensed for
+everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms of
+this General Public License.  The "Program", below, refers to any such program
+or work, and a "work based on the Program" means either the Program or any
+derivative work under copyright law: that is to say, a work containing the
+Program or a portion of it, either verbatim or with modifications and/or
+translated into another language.  (Hereinafter, translation is included
+without limitation in the term "modification".) Each licensee is addressed as
+"you".
+
+Activities other than copying, distribution and modification are not covered by
+this License; they are outside its scope.  The act of running the Program is
+not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made by
+running the Program).  Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as
+you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may
+at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus
+forming a work based on the Program, and copy and distribute such modifications
+or work under the terms of Section 1 above, provided that you also meet all of
+these conditions:
+
+    a) You must cause the modified files to carry prominent notices stating
+    that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in whole or
+    in part contains or is derived from the Program or any part thereof, to be
+    licensed as a whole at no charge to all third parties under the terms of
+    this License.
+
+    c) If the modified program normally reads commands interactively when run,
+    you must cause it, when started running for such interactive use in the
+    most ordinary way, to print or display an announcement including an
+    appropriate copyright notice and a notice that there is no warranty (or
+    else, saying that you provide a warranty) and that users may redistribute
+    the program under these conditions, and telling the user how to view a copy
+    of this License.  (Exception: if the Program itself is interactive but does
+    not normally print such an announcement, your work based on the Program is
+    not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If identifiable
+sections of that work are not derived from the Program, and can be reasonably
+considered independent and separate works in themselves, then this License, and
+its terms, do not apply to those sections when you distribute them as separate
+works.  But when you distribute the same sections as part of a whole which is a
+work based on the Program, the distribution of the whole must be on the terms
+of this License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Program.
+
+In addition, mere aggregation of another work not based on the Program with the
+Program (or with a work based on the Program) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1 and
+2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable source
+    code, which must be distributed under the terms of Sections 1 and 2 above
+    on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three years, to
+    give any third party, for a charge no more than your cost of physically
+    performing source distribution, a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of Sections 1
+    and 2 above on a medium customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer to
+    distribute corresponding source code.  (This alternative is allowed only
+    for noncommercial distribution and only if you received the program in
+    object code or executable form with such an offer, in accord with
+    Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it.  For an executable work, complete source code means all
+the source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and installation
+of the executable.  However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the source
+code from the same place counts as distribution of the source code, even though
+third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License.  Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will automatically terminate
+your rights under this License.  However, parties who have received copies, or
+rights, from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the Program
+or its derivative works.  These actions are prohibited by law if you do not
+accept this License.  Therefore, by modifying or distributing the Program (or
+any work based on the Program), you indicate your acceptance of this License to
+do so, and all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program),
+the recipient automatically receives a license from the original licensor to
+copy, distribute or modify the Program subject to these terms and conditions.
+You may not impose any further restrictions on the recipients' exercise of the
+rights granted herein.  You are not responsible for enforcing compliance by
+third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues), conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from the
+conditions of this License.  If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices.  Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded.  In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the
+General Public License from time to time.  Such new versions will be similar in
+spirit to the present version, but may differ in detail to address new problems
+or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software Foundation.
+If the Program does not specify a version number of this License, you may
+choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission.  For software which is copyrighted by the Free Software Foundation,
+write to the Free Software Foundation; we sometimes make exceptions for this.
+Our decision will be guided by the two goals of preserving the free status of
+all derivatives of our free software and of promoting the sharing and reuse of
+software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
+ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
+PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
+OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program.  It is safest to attach
+them to the start of each source file to most effectively convey the exclusion
+of warranty; and each file should have at least the "copyright" line and a
+pointer to where the full notice is found.
+
+    One line to give the program's name and a brief idea of what it does.
+
+    Copyright (C) <year> <name of author>
+
+    This program is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the Free
+    Software Foundation; either version 2 of the License, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+    more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc., 59
+    Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it
+starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
+    with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free
+    software, and you are welcome to redistribute it under certain conditions;
+    type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may be
+called something other than 'show w' and 'show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.  Here
+is a sample; alter the names:
+
+    Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+    'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+    signature of Ty Coon, 1 April 1989
+
+    Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General Public
+License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL
+
+Certain source files distributed by Oracle America and/or its affiliates are
+subject to the following clarification and special exception to the GPL, but
+only where Oracle has expressly included in the particular source file's header
+the words "Oracle designates this particular file as subject to the "Classpath"
+exception as provided by Oracle in the LICENSE file that accompanied this code."
+
+    Linking this library statically or dynamically with other modules is making
+    a combined work based on this library.  Thus, the terms and conditions of
+    the GNU General Public License cover the whole combination.
+
+    As a special exception, the copyright holders of this library give you
+    permission to link this library with independent modules to produce an
+    executable, regardless of the license terms of these independent modules,
+    and to copy and distribute the resulting executable under terms of your
+    choice, provided that you also meet, for each linked independent module,
+    the terms and conditions of the license of that module.  An independent
+    module is a module which is not derived from or based on this library.  If
+    you modify this library, you may extend this exception to your version of
+    the library, but you are not obligated to do so.  If you do not wish to do
+    so, delete this exception statement from your version.
diff --git a/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/jni.h b/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/jni.h
new file mode 100644
index 0000000..2e83cb7
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/jni.h
@@ -0,0 +1,1960 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * We used part of Netscape's Java Runtime Interface (JRI) as the starting
+ * point of our design and implementation.
+ */
+
+/******************************************************************************
+ * Java Runtime Interface
+ * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved.
+ *****************************************************************************/
+
+#ifndef _JAVASOFT_JNI_H_
+#define _JAVASOFT_JNI_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* jni_md.h contains the machine-dependent typedefs for jbyte, jint
+   and jlong */
+
+#include "jni_md.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * JNI Types
+ */
+
+#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H
+
+typedef unsigned char   jboolean;
+typedef unsigned short  jchar;
+typedef short           jshort;
+typedef float           jfloat;
+typedef double          jdouble;
+
+typedef jint            jsize;
+
+#ifdef __cplusplus
+
+class _jobject {};
+class _jclass : public _jobject {};
+class _jthrowable : public _jobject {};
+class _jstring : public _jobject {};
+class _jarray : public _jobject {};
+class _jbooleanArray : public _jarray {};
+class _jbyteArray : public _jarray {};
+class _jcharArray : public _jarray {};
+class _jshortArray : public _jarray {};
+class _jintArray : public _jarray {};
+class _jlongArray : public _jarray {};
+class _jfloatArray : public _jarray {};
+class _jdoubleArray : public _jarray {};
+class _jobjectArray : public _jarray {};
+
+typedef _jobject *jobject;
+typedef _jclass *jclass;
+typedef _jthrowable *jthrowable;
+typedef _jstring *jstring;
+typedef _jarray *jarray;
+typedef _jbooleanArray *jbooleanArray;
+typedef _jbyteArray *jbyteArray;
+typedef _jcharArray *jcharArray;
+typedef _jshortArray *jshortArray;
+typedef _jintArray *jintArray;
+typedef _jlongArray *jlongArray;
+typedef _jfloatArray *jfloatArray;
+typedef _jdoubleArray *jdoubleArray;
+typedef _jobjectArray *jobjectArray;
+
+#else
+
+struct _jobject;
+
+typedef struct _jobject *jobject;
+typedef jobject jclass;
+typedef jobject jthrowable;
+typedef jobject jstring;
+typedef jobject jarray;
+typedef jarray jbooleanArray;
+typedef jarray jbyteArray;
+typedef jarray jcharArray;
+typedef jarray jshortArray;
+typedef jarray jintArray;
+typedef jarray jlongArray;
+typedef jarray jfloatArray;
+typedef jarray jdoubleArray;
+typedef jarray jobjectArray;
+
+#endif
+
+typedef jobject jweak;
+
+typedef union jvalue {
+    jboolean z;
+    jbyte    b;
+    jchar    c;
+    jshort   s;
+    jint     i;
+    jlong    j;
+    jfloat   f;
+    jdouble  d;
+    jobject  l;
+} jvalue;
+
+struct _jfieldID;
+typedef struct _jfieldID *jfieldID;
+
+struct _jmethodID;
+typedef struct _jmethodID *jmethodID;
+
+/* Return values from jobjectRefType */
+typedef enum _jobjectType {
+     JNIInvalidRefType    = 0,
+     JNILocalRefType      = 1,
+     JNIGlobalRefType     = 2,
+     JNIWeakGlobalRefType = 3
+} jobjectRefType;
+
+
+#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */
+
+/*
+ * jboolean constants
+ */
+
+#define JNI_FALSE 0
+#define JNI_TRUE 1
+
+/*
+ * possible return values for JNI functions.
+ */
+
+#define JNI_OK           0                 /* success */
+#define JNI_ERR          (-1)              /* unknown error */
+#define JNI_EDETACHED    (-2)              /* thread detached from the VM */
+#define JNI_EVERSION     (-3)              /* JNI version error */
+#define JNI_ENOMEM       (-4)              /* not enough memory */
+#define JNI_EEXIST       (-5)              /* VM already created */
+#define JNI_EINVAL       (-6)              /* invalid arguments */
+
+/*
+ * used in ReleaseScalarArrayElements
+ */
+
+#define JNI_COMMIT 1
+#define JNI_ABORT 2
+
+/*
+ * used in RegisterNatives to describe native method name, signature,
+ * and function pointer.
+ */
+
+typedef struct {
+    char *name;
+    char *signature;
+    void *fnPtr;
+} JNINativeMethod;
+
+/*
+ * JNI Native Method Interface.
+ */
+
+struct JNINativeInterface_;
+
+struct JNIEnv_;
+
+#ifdef __cplusplus
+typedef JNIEnv_ JNIEnv;
+#else
+typedef const struct JNINativeInterface_ *JNIEnv;
+#endif
+
+/*
+ * JNI Invocation Interface.
+ */
+
+struct JNIInvokeInterface_;
+
+struct JavaVM_;
+
+#ifdef __cplusplus
+typedef JavaVM_ JavaVM;
+#else
+typedef const struct JNIInvokeInterface_ *JavaVM;
+#endif
+
+struct JNINativeInterface_ {
+    void *reserved0;
+    void *reserved1;
+    void *reserved2;
+
+    void *reserved3;
+    jint (JNICALL *GetVersion)(JNIEnv *env);
+
+    jclass (JNICALL *DefineClass)
+      (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,
+       jsize len);
+    jclass (JNICALL *FindClass)
+      (JNIEnv *env, const char *name);
+
+    jmethodID (JNICALL *FromReflectedMethod)
+      (JNIEnv *env, jobject method);
+    jfieldID (JNICALL *FromReflectedField)
+      (JNIEnv *env, jobject field);
+
+    jobject (JNICALL *ToReflectedMethod)
+      (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);
+
+    jclass (JNICALL *GetSuperclass)
+      (JNIEnv *env, jclass sub);
+    jboolean (JNICALL *IsAssignableFrom)
+      (JNIEnv *env, jclass sub, jclass sup);
+
+    jobject (JNICALL *ToReflectedField)
+      (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);
+
+    jint (JNICALL *Throw)
+      (JNIEnv *env, jthrowable obj);
+    jint (JNICALL *ThrowNew)
+      (JNIEnv *env, jclass clazz, const char *msg);
+    jthrowable (JNICALL *ExceptionOccurred)
+      (JNIEnv *env);
+    void (JNICALL *ExceptionDescribe)
+      (JNIEnv *env);
+    void (JNICALL *ExceptionClear)
+      (JNIEnv *env);
+    void (JNICALL *FatalError)
+      (JNIEnv *env, const char *msg);
+
+    jint (JNICALL *PushLocalFrame)
+      (JNIEnv *env, jint capacity);
+    jobject (JNICALL *PopLocalFrame)
+      (JNIEnv *env, jobject result);
+
+    jobject (JNICALL *NewGlobalRef)
+      (JNIEnv *env, jobject lobj);
+    void (JNICALL *DeleteGlobalRef)
+      (JNIEnv *env, jobject gref);
+    void (JNICALL *DeleteLocalRef)
+      (JNIEnv *env, jobject obj);
+    jboolean (JNICALL *IsSameObject)
+      (JNIEnv *env, jobject obj1, jobject obj2);
+    jobject (JNICALL *NewLocalRef)
+      (JNIEnv *env, jobject ref);
+    jint (JNICALL *EnsureLocalCapacity)
+      (JNIEnv *env, jint capacity);
+
+    jobject (JNICALL *AllocObject)
+      (JNIEnv *env, jclass clazz);
+    jobject (JNICALL *NewObject)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *NewObjectV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jobject (JNICALL *NewObjectA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jclass (JNICALL *GetObjectClass)
+      (JNIEnv *env, jobject obj);
+    jboolean (JNICALL *IsInstanceOf)
+      (JNIEnv *env, jobject obj, jclass clazz);
+
+    jmethodID (JNICALL *GetMethodID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *CallObjectMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jobject (JNICALL *CallObjectMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jobject (JNICALL *CallObjectMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+    jboolean (JNICALL *CallBooleanMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jboolean (JNICALL *CallBooleanMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jboolean (JNICALL *CallBooleanMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+    jbyte (JNICALL *CallByteMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jbyte (JNICALL *CallByteMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jbyte (JNICALL *CallByteMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jchar (JNICALL *CallCharMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jchar (JNICALL *CallCharMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jchar (JNICALL *CallCharMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jshort (JNICALL *CallShortMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jshort (JNICALL *CallShortMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jshort (JNICALL *CallShortMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jint (JNICALL *CallIntMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jint (JNICALL *CallIntMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jint (JNICALL *CallIntMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jlong (JNICALL *CallLongMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jlong (JNICALL *CallLongMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jlong (JNICALL *CallLongMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jfloat (JNICALL *CallFloatMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jfloat (JNICALL *CallFloatMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jfloat (JNICALL *CallFloatMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jdouble (JNICALL *CallDoubleMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jdouble (JNICALL *CallDoubleMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jdouble (JNICALL *CallDoubleMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    void (JNICALL *CallVoidMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    void (JNICALL *CallVoidMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    void (JNICALL *CallVoidMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+    jobject (JNICALL *CallNonvirtualObjectMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *CallNonvirtualObjectMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jobject (JNICALL *CallNonvirtualObjectMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue * args);
+
+    jboolean (JNICALL *CallNonvirtualBooleanMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jboolean (JNICALL *CallNonvirtualBooleanMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jboolean (JNICALL *CallNonvirtualBooleanMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue * args);
+
+    jbyte (JNICALL *CallNonvirtualByteMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jbyte (JNICALL *CallNonvirtualByteMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jbyte (JNICALL *CallNonvirtualByteMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jchar (JNICALL *CallNonvirtualCharMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jchar (JNICALL *CallNonvirtualCharMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jchar (JNICALL *CallNonvirtualCharMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jshort (JNICALL *CallNonvirtualShortMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jshort (JNICALL *CallNonvirtualShortMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jshort (JNICALL *CallNonvirtualShortMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jint (JNICALL *CallNonvirtualIntMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jint (JNICALL *CallNonvirtualIntMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jint (JNICALL *CallNonvirtualIntMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jlong (JNICALL *CallNonvirtualLongMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jlong (JNICALL *CallNonvirtualLongMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jlong (JNICALL *CallNonvirtualLongMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jfloat (JNICALL *CallNonvirtualFloatMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jfloat (JNICALL *CallNonvirtualFloatMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jfloat (JNICALL *CallNonvirtualFloatMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jdouble (JNICALL *CallNonvirtualDoubleMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jdouble (JNICALL *CallNonvirtualDoubleMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jdouble (JNICALL *CallNonvirtualDoubleMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    void (JNICALL *CallNonvirtualVoidMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    void (JNICALL *CallNonvirtualVoidMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    void (JNICALL *CallNonvirtualVoidMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue * args);
+
+    jfieldID (JNICALL *GetFieldID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *GetObjectField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jboolean (JNICALL *GetBooleanField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jbyte (JNICALL *GetByteField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jchar (JNICALL *GetCharField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jshort (JNICALL *GetShortField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jint (JNICALL *GetIntField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jlong (JNICALL *GetLongField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jfloat (JNICALL *GetFloatField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jdouble (JNICALL *GetDoubleField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+
+    void (JNICALL *SetObjectField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);
+    void (JNICALL *SetBooleanField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);
+    void (JNICALL *SetByteField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);
+    void (JNICALL *SetCharField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);
+    void (JNICALL *SetShortField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);
+    void (JNICALL *SetIntField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jint val);
+    void (JNICALL *SetLongField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);
+    void (JNICALL *SetFloatField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);
+    void (JNICALL *SetDoubleField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);
+
+    jmethodID (JNICALL *GetStaticMethodID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *CallStaticObjectMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *CallStaticObjectMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jobject (JNICALL *CallStaticObjectMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jboolean (JNICALL *CallStaticBooleanMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jboolean (JNICALL *CallStaticBooleanMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jboolean (JNICALL *CallStaticBooleanMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jbyte (JNICALL *CallStaticByteMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jbyte (JNICALL *CallStaticByteMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jbyte (JNICALL *CallStaticByteMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jchar (JNICALL *CallStaticCharMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jchar (JNICALL *CallStaticCharMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jchar (JNICALL *CallStaticCharMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jshort (JNICALL *CallStaticShortMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jshort (JNICALL *CallStaticShortMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jshort (JNICALL *CallStaticShortMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jint (JNICALL *CallStaticIntMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jint (JNICALL *CallStaticIntMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jint (JNICALL *CallStaticIntMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jlong (JNICALL *CallStaticLongMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jlong (JNICALL *CallStaticLongMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jlong (JNICALL *CallStaticLongMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jfloat (JNICALL *CallStaticFloatMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jfloat (JNICALL *CallStaticFloatMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jfloat (JNICALL *CallStaticFloatMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jdouble (JNICALL *CallStaticDoubleMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jdouble (JNICALL *CallStaticDoubleMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jdouble (JNICALL *CallStaticDoubleMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    void (JNICALL *CallStaticVoidMethod)
+      (JNIEnv *env, jclass cls, jmethodID methodID, ...);
+    void (JNICALL *CallStaticVoidMethodV)
+      (JNIEnv *env, jclass cls, jmethodID methodID, va_list args);
+    void (JNICALL *CallStaticVoidMethodA)
+      (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args);
+
+    jfieldID (JNICALL *GetStaticFieldID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+    jobject (JNICALL *GetStaticObjectField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jboolean (JNICALL *GetStaticBooleanField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jbyte (JNICALL *GetStaticByteField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jchar (JNICALL *GetStaticCharField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jshort (JNICALL *GetStaticShortField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jint (JNICALL *GetStaticIntField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jlong (JNICALL *GetStaticLongField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jfloat (JNICALL *GetStaticFloatField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jdouble (JNICALL *GetStaticDoubleField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+
+    void (JNICALL *SetStaticObjectField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
+    void (JNICALL *SetStaticBooleanField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
+    void (JNICALL *SetStaticByteField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
+    void (JNICALL *SetStaticCharField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
+    void (JNICALL *SetStaticShortField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
+    void (JNICALL *SetStaticIntField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
+    void (JNICALL *SetStaticLongField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
+    void (JNICALL *SetStaticFloatField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
+    void (JNICALL *SetStaticDoubleField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);
+
+    jstring (JNICALL *NewString)
+      (JNIEnv *env, const jchar *unicode, jsize len);
+    jsize (JNICALL *GetStringLength)
+      (JNIEnv *env, jstring str);
+    const jchar *(JNICALL *GetStringChars)
+      (JNIEnv *env, jstring str, jboolean *isCopy);
+    void (JNICALL *ReleaseStringChars)
+      (JNIEnv *env, jstring str, const jchar *chars);
+
+    jstring (JNICALL *NewStringUTF)
+      (JNIEnv *env, const char *utf);
+    jsize (JNICALL *GetStringUTFLength)
+      (JNIEnv *env, jstring str);
+    const char* (JNICALL *GetStringUTFChars)
+      (JNIEnv *env, jstring str, jboolean *isCopy);
+    void (JNICALL *ReleaseStringUTFChars)
+      (JNIEnv *env, jstring str, const char* chars);
+
+
+    jsize (JNICALL *GetArrayLength)
+      (JNIEnv *env, jarray array);
+
+    jobjectArray (JNICALL *NewObjectArray)
+      (JNIEnv *env, jsize len, jclass clazz, jobject init);
+    jobject (JNICALL *GetObjectArrayElement)
+      (JNIEnv *env, jobjectArray array, jsize index);
+    void (JNICALL *SetObjectArrayElement)
+      (JNIEnv *env, jobjectArray array, jsize index, jobject val);
+
+    jbooleanArray (JNICALL *NewBooleanArray)
+      (JNIEnv *env, jsize len);
+    jbyteArray (JNICALL *NewByteArray)
+      (JNIEnv *env, jsize len);
+    jcharArray (JNICALL *NewCharArray)
+      (JNIEnv *env, jsize len);
+    jshortArray (JNICALL *NewShortArray)
+      (JNIEnv *env, jsize len);
+    jintArray (JNICALL *NewIntArray)
+      (JNIEnv *env, jsize len);
+    jlongArray (JNICALL *NewLongArray)
+      (JNIEnv *env, jsize len);
+    jfloatArray (JNICALL *NewFloatArray)
+      (JNIEnv *env, jsize len);
+    jdoubleArray (JNICALL *NewDoubleArray)
+      (JNIEnv *env, jsize len);
+
+    jboolean * (JNICALL *GetBooleanArrayElements)
+      (JNIEnv *env, jbooleanArray array, jboolean *isCopy);
+    jbyte * (JNICALL *GetByteArrayElements)
+      (JNIEnv *env, jbyteArray array, jboolean *isCopy);
+    jchar * (JNICALL *GetCharArrayElements)
+      (JNIEnv *env, jcharArray array, jboolean *isCopy);
+    jshort * (JNICALL *GetShortArrayElements)
+      (JNIEnv *env, jshortArray array, jboolean *isCopy);
+    jint * (JNICALL *GetIntArrayElements)
+      (JNIEnv *env, jintArray array, jboolean *isCopy);
+    jlong * (JNICALL *GetLongArrayElements)
+      (JNIEnv *env, jlongArray array, jboolean *isCopy);
+    jfloat * (JNICALL *GetFloatArrayElements)
+      (JNIEnv *env, jfloatArray array, jboolean *isCopy);
+    jdouble * (JNICALL *GetDoubleArrayElements)
+      (JNIEnv *env, jdoubleArray array, jboolean *isCopy);
+
+    void (JNICALL *ReleaseBooleanArrayElements)
+      (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);
+    void (JNICALL *ReleaseByteArrayElements)
+      (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);
+    void (JNICALL *ReleaseCharArrayElements)
+      (JNIEnv *env, jcharArray array, jchar *elems, jint mode);
+    void (JNICALL *ReleaseShortArrayElements)
+      (JNIEnv *env, jshortArray array, jshort *elems, jint mode);
+    void (JNICALL *ReleaseIntArrayElements)
+      (JNIEnv *env, jintArray array, jint *elems, jint mode);
+    void (JNICALL *ReleaseLongArrayElements)
+      (JNIEnv *env, jlongArray array, jlong *elems, jint mode);
+    void (JNICALL *ReleaseFloatArrayElements)
+      (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);
+    void (JNICALL *ReleaseDoubleArrayElements)
+      (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);
+
+    void (JNICALL *GetBooleanArrayRegion)
+      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);
+    void (JNICALL *GetByteArrayRegion)
+      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
+    void (JNICALL *GetCharArrayRegion)
+      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);
+    void (JNICALL *GetShortArrayRegion)
+      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);
+    void (JNICALL *GetIntArrayRegion)
+      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);
+    void (JNICALL *GetLongArrayRegion)
+      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);
+    void (JNICALL *GetFloatArrayRegion)
+      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);
+    void (JNICALL *GetDoubleArrayRegion)
+      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);
+
+    void (JNICALL *SetBooleanArrayRegion)
+      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf);
+    void (JNICALL *SetByteArrayRegion)
+      (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf);
+    void (JNICALL *SetCharArrayRegion)
+      (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf);
+    void (JNICALL *SetShortArrayRegion)
+      (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf);
+    void (JNICALL *SetIntArrayRegion)
+      (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf);
+    void (JNICALL *SetLongArrayRegion)
+      (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf);
+    void (JNICALL *SetFloatArrayRegion)
+      (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf);
+    void (JNICALL *SetDoubleArrayRegion)
+      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf);
+
+    jint (JNICALL *RegisterNatives)
+      (JNIEnv *env, jclass clazz, const JNINativeMethod *methods,
+       jint nMethods);
+    jint (JNICALL *UnregisterNatives)
+      (JNIEnv *env, jclass clazz);
+
+    jint (JNICALL *MonitorEnter)
+      (JNIEnv *env, jobject obj);
+    jint (JNICALL *MonitorExit)
+      (JNIEnv *env, jobject obj);
+
+    jint (JNICALL *GetJavaVM)
+      (JNIEnv *env, JavaVM **vm);
+
+    void (JNICALL *GetStringRegion)
+      (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
+    void (JNICALL *GetStringUTFRegion)
+      (JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
+
+    void * (JNICALL *GetPrimitiveArrayCritical)
+      (JNIEnv *env, jarray array, jboolean *isCopy);
+    void (JNICALL *ReleasePrimitiveArrayCritical)
+      (JNIEnv *env, jarray array, void *carray, jint mode);
+
+    const jchar * (JNICALL *GetStringCritical)
+      (JNIEnv *env, jstring string, jboolean *isCopy);
+    void (JNICALL *ReleaseStringCritical)
+      (JNIEnv *env, jstring string, const jchar *cstring);
+
+    jweak (JNICALL *NewWeakGlobalRef)
+       (JNIEnv *env, jobject obj);
+    void (JNICALL *DeleteWeakGlobalRef)
+       (JNIEnv *env, jweak ref);
+
+    jboolean (JNICALL *ExceptionCheck)
+       (JNIEnv *env);
+
+    jobject (JNICALL *NewDirectByteBuffer)
+       (JNIEnv* env, void* address, jlong capacity);
+    void* (JNICALL *GetDirectBufferAddress)
+       (JNIEnv* env, jobject buf);
+    jlong (JNICALL *GetDirectBufferCapacity)
+       (JNIEnv* env, jobject buf);
+
+    /* New JNI 1.6 Features */
+
+    jobjectRefType (JNICALL *GetObjectRefType)
+        (JNIEnv* env, jobject obj);
+};
+
+/*
+ * We use inlined functions for C++ so that programmers can write:
+ *
+ *    env->FindClass("java/lang/String")
+ *
+ * in C++ rather than:
+ *
+ *    (*env)->FindClass(env, "java/lang/String")
+ *
+ * in C.
+ */
+
+struct JNIEnv_ {
+    const struct JNINativeInterface_ *functions;
+#ifdef __cplusplus
+
+    jint GetVersion() {
+        return functions->GetVersion(this);
+    }
+    jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
+                       jsize len) {
+        return functions->DefineClass(this, name, loader, buf, len);
+    }
+    jclass FindClass(const char *name) {
+        return functions->FindClass(this, name);
+    }
+    jmethodID FromReflectedMethod(jobject method) {
+        return functions->FromReflectedMethod(this,method);
+    }
+    jfieldID FromReflectedField(jobject field) {
+        return functions->FromReflectedField(this,field);
+    }
+
+    jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) {
+        return functions->ToReflectedMethod(this, cls, methodID, isStatic);
+    }
+
+    jclass GetSuperclass(jclass sub) {
+        return functions->GetSuperclass(this, sub);
+    }
+    jboolean IsAssignableFrom(jclass sub, jclass sup) {
+        return functions->IsAssignableFrom(this, sub, sup);
+    }
+
+    jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) {
+        return functions->ToReflectedField(this,cls,fieldID,isStatic);
+    }
+
+    jint Throw(jthrowable obj) {
+        return functions->Throw(this, obj);
+    }
+    jint ThrowNew(jclass clazz, const char *msg) {
+        return functions->ThrowNew(this, clazz, msg);
+    }
+    jthrowable ExceptionOccurred() {
+        return functions->ExceptionOccurred(this);
+    }
+    void ExceptionDescribe() {
+        functions->ExceptionDescribe(this);
+    }
+    void ExceptionClear() {
+        functions->ExceptionClear(this);
+    }
+    void FatalError(const char *msg) {
+        functions->FatalError(this, msg);
+    }
+
+    jint PushLocalFrame(jint capacity) {
+        return functions->PushLocalFrame(this,capacity);
+    }
+    jobject PopLocalFrame(jobject result) {
+        return functions->PopLocalFrame(this,result);
+    }
+
+    jobject NewGlobalRef(jobject lobj) {
+        return functions->NewGlobalRef(this,lobj);
+    }
+    void DeleteGlobalRef(jobject gref) {
+        functions->DeleteGlobalRef(this,gref);
+    }
+    void DeleteLocalRef(jobject obj) {
+        functions->DeleteLocalRef(this, obj);
+    }
+
+    jboolean IsSameObject(jobject obj1, jobject obj2) {
+        return functions->IsSameObject(this,obj1,obj2);
+    }
+
+    jobject NewLocalRef(jobject ref) {
+        return functions->NewLocalRef(this,ref);
+    }
+    jint EnsureLocalCapacity(jint capacity) {
+        return functions->EnsureLocalCapacity(this,capacity);
+    }
+
+    jobject AllocObject(jclass clazz) {
+        return functions->AllocObject(this,clazz);
+    }
+    jobject NewObject(jclass clazz, jmethodID methodID, ...) {
+        va_list args;
+        jobject result;
+        va_start(args, methodID);
+        result = functions->NewObjectV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jobject NewObjectV(jclass clazz, jmethodID methodID,
+                       va_list args) {
+        return functions->NewObjectV(this,clazz,methodID,args);
+    }
+    jobject NewObjectA(jclass clazz, jmethodID methodID,
+                       const jvalue *args) {
+        return functions->NewObjectA(this,clazz,methodID,args);
+    }
+
+    jclass GetObjectClass(jobject obj) {
+        return functions->GetObjectClass(this,obj);
+    }
+    jboolean IsInstanceOf(jobject obj, jclass clazz) {
+        return functions->IsInstanceOf(this,obj,clazz);
+    }
+
+    jmethodID GetMethodID(jclass clazz, const char *name,
+                          const char *sig) {
+        return functions->GetMethodID(this,clazz,name,sig);
+    }
+
+    jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jobject result;
+        va_start(args,methodID);
+        result = functions->CallObjectMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jobject CallObjectMethodV(jobject obj, jmethodID methodID,
+                        va_list args) {
+        return functions->CallObjectMethodV(this,obj,methodID,args);
+    }
+    jobject CallObjectMethodA(jobject obj, jmethodID methodID,
+                        const jvalue * args) {
+        return functions->CallObjectMethodA(this,obj,methodID,args);
+    }
+
+    jboolean CallBooleanMethod(jobject obj,
+                               jmethodID methodID, ...) {
+        va_list args;
+        jboolean result;
+        va_start(args,methodID);
+        result = functions->CallBooleanMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jboolean CallBooleanMethodV(jobject obj, jmethodID methodID,
+                                va_list args) {
+        return functions->CallBooleanMethodV(this,obj,methodID,args);
+    }
+    jboolean CallBooleanMethodA(jobject obj, jmethodID methodID,
+                                const jvalue * args) {
+        return functions->CallBooleanMethodA(this,obj,methodID, args);
+    }
+
+    jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jbyte result;
+        va_start(args,methodID);
+        result = functions->CallByteMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jbyte CallByteMethodV(jobject obj, jmethodID methodID,
+                          va_list args) {
+        return functions->CallByteMethodV(this,obj,methodID,args);
+    }
+    jbyte CallByteMethodA(jobject obj, jmethodID methodID,
+                          const jvalue * args) {
+        return functions->CallByteMethodA(this,obj,methodID,args);
+    }
+
+    jchar CallCharMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jchar result;
+        va_start(args,methodID);
+        result = functions->CallCharMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jchar CallCharMethodV(jobject obj, jmethodID methodID,
+                          va_list args) {
+        return functions->CallCharMethodV(this,obj,methodID,args);
+    }
+    jchar CallCharMethodA(jobject obj, jmethodID methodID,
+                          const jvalue * args) {
+        return functions->CallCharMethodA(this,obj,methodID,args);
+    }
+
+    jshort CallShortMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jshort result;
+        va_start(args,methodID);
+        result = functions->CallShortMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jshort CallShortMethodV(jobject obj, jmethodID methodID,
+                            va_list args) {
+        return functions->CallShortMethodV(this,obj,methodID,args);
+    }
+    jshort CallShortMethodA(jobject obj, jmethodID methodID,
+                            const jvalue * args) {
+        return functions->CallShortMethodA(this,obj,methodID,args);
+    }
+
+    jint CallIntMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jint result;
+        va_start(args,methodID);
+        result = functions->CallIntMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jint CallIntMethodV(jobject obj, jmethodID methodID,
+                        va_list args) {
+        return functions->CallIntMethodV(this,obj,methodID,args);
+    }
+    jint CallIntMethodA(jobject obj, jmethodID methodID,
+                        const jvalue * args) {
+        return functions->CallIntMethodA(this,obj,methodID,args);
+    }
+
+    jlong CallLongMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jlong result;
+        va_start(args,methodID);
+        result = functions->CallLongMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jlong CallLongMethodV(jobject obj, jmethodID methodID,
+                          va_list args) {
+        return functions->CallLongMethodV(this,obj,methodID,args);
+    }
+    jlong CallLongMethodA(jobject obj, jmethodID methodID,
+                          const jvalue * args) {
+        return functions->CallLongMethodA(this,obj,methodID,args);
+    }
+
+    jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jfloat result;
+        va_start(args,methodID);
+        result = functions->CallFloatMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jfloat CallFloatMethodV(jobject obj, jmethodID methodID,
+                            va_list args) {
+        return functions->CallFloatMethodV(this,obj,methodID,args);
+    }
+    jfloat CallFloatMethodA(jobject obj, jmethodID methodID,
+                            const jvalue * args) {
+        return functions->CallFloatMethodA(this,obj,methodID,args);
+    }
+
+    jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        jdouble result;
+        va_start(args,methodID);
+        result = functions->CallDoubleMethodV(this,obj,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jdouble CallDoubleMethodV(jobject obj, jmethodID methodID,
+                        va_list args) {
+        return functions->CallDoubleMethodV(this,obj,methodID,args);
+    }
+    jdouble CallDoubleMethodA(jobject obj, jmethodID methodID,
+                        const jvalue * args) {
+        return functions->CallDoubleMethodA(this,obj,methodID,args);
+    }
+
+    void CallVoidMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+        va_start(args,methodID);
+        functions->CallVoidMethodV(this,obj,methodID,args);
+        va_end(args);
+    }
+    void CallVoidMethodV(jobject obj, jmethodID methodID,
+                         va_list args) {
+        functions->CallVoidMethodV(this,obj,methodID,args);
+    }
+    void CallVoidMethodA(jobject obj, jmethodID methodID,
+                         const jvalue * args) {
+        functions->CallVoidMethodA(this,obj,methodID,args);
+    }
+
+    jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz,
+                                       jmethodID methodID, ...) {
+        va_list args;
+        jobject result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+                                                        methodID,args);
+        va_end(args);
+        return result;
+    }
+    jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz,
+                                        jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+                                                      methodID,args);
+    }
+    jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz,
+                                        jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualObjectMethodA(this,obj,clazz,
+                                                      methodID,args);
+    }
+
+    jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz,
+                                         jmethodID methodID, ...) {
+        va_list args;
+        jboolean result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+                                                         methodID,args);
+        va_end(args);
+        return result;
+    }
+    jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz,
+                                          jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+                                                       methodID,args);
+    }
+    jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz,
+                                          jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualBooleanMethodA(this,obj,clazz,
+                                                       methodID, args);
+    }
+
+    jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz,
+                                   jmethodID methodID, ...) {
+        va_list args;
+        jbyte result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualByteMethodV(this,obj,clazz,
+                                                      methodID,args);
+        va_end(args);
+        return result;
+    }
+    jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz,
+                                    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualByteMethodV(this,obj,clazz,
+                                                    methodID,args);
+    }
+    jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz,
+                                    jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualByteMethodA(this,obj,clazz,
+                                                    methodID,args);
+    }
+
+    jchar CallNonvirtualCharMethod(jobject obj, jclass clazz,
+                                   jmethodID methodID, ...) {
+        va_list args;
+        jchar result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualCharMethodV(this,obj,clazz,
+                                                      methodID,args);
+        va_end(args);
+        return result;
+    }
+    jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz,
+                                    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualCharMethodV(this,obj,clazz,
+                                                    methodID,args);
+    }
+    jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz,
+                                    jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualCharMethodA(this,obj,clazz,
+                                                    methodID,args);
+    }
+
+    jshort CallNonvirtualShortMethod(jobject obj, jclass clazz,
+                                     jmethodID methodID, ...) {
+        va_list args;
+        jshort result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualShortMethodV(this,obj,clazz,
+                                                       methodID,args);
+        va_end(args);
+        return result;
+    }
+    jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz,
+                                      jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualShortMethodV(this,obj,clazz,
+                                                     methodID,args);
+    }
+    jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz,
+                                      jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualShortMethodA(this,obj,clazz,
+                                                     methodID,args);
+    }
+
+    jint CallNonvirtualIntMethod(jobject obj, jclass clazz,
+                                 jmethodID methodID, ...) {
+        va_list args;
+        jint result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualIntMethodV(this,obj,clazz,
+                                                     methodID,args);
+        va_end(args);
+        return result;
+    }
+    jint CallNonvirtualIntMethodV(jobject obj, jclass clazz,
+                                  jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualIntMethodV(this,obj,clazz,
+                                                   methodID,args);
+    }
+    jint CallNonvirtualIntMethodA(jobject obj, jclass clazz,
+                                  jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualIntMethodA(this,obj,clazz,
+                                                   methodID,args);
+    }
+
+    jlong CallNonvirtualLongMethod(jobject obj, jclass clazz,
+                                   jmethodID methodID, ...) {
+        va_list args;
+        jlong result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualLongMethodV(this,obj,clazz,
+                                                      methodID,args);
+        va_end(args);
+        return result;
+    }
+    jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz,
+                                    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualLongMethodV(this,obj,clazz,
+                                                    methodID,args);
+    }
+    jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz,
+                                    jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualLongMethodA(this,obj,clazz,
+                                                    methodID,args);
+    }
+
+    jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz,
+                                     jmethodID methodID, ...) {
+        va_list args;
+        jfloat result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+                                                       methodID,args);
+        va_end(args);
+        return result;
+    }
+    jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz,
+                                      jmethodID methodID,
+                                      va_list args) {
+        return functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+                                                     methodID,args);
+    }
+    jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz,
+                                      jmethodID methodID,
+                                      const jvalue * args) {
+        return functions->CallNonvirtualFloatMethodA(this,obj,clazz,
+                                                     methodID,args);
+    }
+
+    jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz,
+                                       jmethodID methodID, ...) {
+        va_list args;
+        jdouble result;
+        va_start(args,methodID);
+        result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+                                                        methodID,args);
+        va_end(args);
+        return result;
+    }
+    jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz,
+                                        jmethodID methodID,
+                                        va_list args) {
+        return functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+                                                      methodID,args);
+    }
+    jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz,
+                                        jmethodID methodID,
+                                        const jvalue * args) {
+        return functions->CallNonvirtualDoubleMethodA(this,obj,clazz,
+                                                      methodID,args);
+    }
+
+    void CallNonvirtualVoidMethod(jobject obj, jclass clazz,
+                                  jmethodID methodID, ...) {
+        va_list args;
+        va_start(args,methodID);
+        functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+        va_end(args);
+    }
+    void CallNonvirtualVoidMethodV(jobject obj, jclass clazz,
+                                   jmethodID methodID,
+                                   va_list args) {
+        functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+    }
+    void CallNonvirtualVoidMethodA(jobject obj, jclass clazz,
+                                   jmethodID methodID,
+                                   const jvalue * args) {
+        functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args);
+    }
+
+    jfieldID GetFieldID(jclass clazz, const char *name,
+                        const char *sig) {
+        return functions->GetFieldID(this,clazz,name,sig);
+    }
+
+    jobject GetObjectField(jobject obj, jfieldID fieldID) {
+        return functions->GetObjectField(this,obj,fieldID);
+    }
+    jboolean GetBooleanField(jobject obj, jfieldID fieldID) {
+        return functions->GetBooleanField(this,obj,fieldID);
+    }
+    jbyte GetByteField(jobject obj, jfieldID fieldID) {
+        return functions->GetByteField(this,obj,fieldID);
+    }
+    jchar GetCharField(jobject obj, jfieldID fieldID) {
+        return functions->GetCharField(this,obj,fieldID);
+    }
+    jshort GetShortField(jobject obj, jfieldID fieldID) {
+        return functions->GetShortField(this,obj,fieldID);
+    }
+    jint GetIntField(jobject obj, jfieldID fieldID) {
+        return functions->GetIntField(this,obj,fieldID);
+    }
+    jlong GetLongField(jobject obj, jfieldID fieldID) {
+        return functions->GetLongField(this,obj,fieldID);
+    }
+    jfloat GetFloatField(jobject obj, jfieldID fieldID) {
+        return functions->GetFloatField(this,obj,fieldID);
+    }
+    jdouble GetDoubleField(jobject obj, jfieldID fieldID) {
+        return functions->GetDoubleField(this,obj,fieldID);
+    }
+
+    void SetObjectField(jobject obj, jfieldID fieldID, jobject val) {
+        functions->SetObjectField(this,obj,fieldID,val);
+    }
+    void SetBooleanField(jobject obj, jfieldID fieldID,
+                         jboolean val) {
+        functions->SetBooleanField(this,obj,fieldID,val);
+    }
+    void SetByteField(jobject obj, jfieldID fieldID,
+                      jbyte val) {
+        functions->SetByteField(this,obj,fieldID,val);
+    }
+    void SetCharField(jobject obj, jfieldID fieldID,
+                      jchar val) {
+        functions->SetCharField(this,obj,fieldID,val);
+    }
+    void SetShortField(jobject obj, jfieldID fieldID,
+                       jshort val) {
+        functions->SetShortField(this,obj,fieldID,val);
+    }
+    void SetIntField(jobject obj, jfieldID fieldID,
+                     jint val) {
+        functions->SetIntField(this,obj,fieldID,val);
+    }
+    void SetLongField(jobject obj, jfieldID fieldID,
+                      jlong val) {
+        functions->SetLongField(this,obj,fieldID,val);
+    }
+    void SetFloatField(jobject obj, jfieldID fieldID,
+                       jfloat val) {
+        functions->SetFloatField(this,obj,fieldID,val);
+    }
+    void SetDoubleField(jobject obj, jfieldID fieldID,
+                        jdouble val) {
+        functions->SetDoubleField(this,obj,fieldID,val);
+    }
+
+    jmethodID GetStaticMethodID(jclass clazz, const char *name,
+                                const char *sig) {
+        return functions->GetStaticMethodID(this,clazz,name,sig);
+    }
+
+    jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID,
+                             ...) {
+        va_list args;
+        jobject result;
+        va_start(args,methodID);
+        result = functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID,
+                              va_list args) {
+        return functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+    }
+    jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID,
+                              const jvalue *args) {
+        return functions->CallStaticObjectMethodA(this,clazz,methodID,args);
+    }
+
+    jboolean CallStaticBooleanMethod(jclass clazz,
+                                     jmethodID methodID, ...) {
+        va_list args;
+        jboolean result;
+        va_start(args,methodID);
+        result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jboolean CallStaticBooleanMethodV(jclass clazz,
+                                      jmethodID methodID, va_list args) {
+        return functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+    }
+    jboolean CallStaticBooleanMethodA(jclass clazz,
+                                      jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticBooleanMethodA(this,clazz,methodID,args);
+    }
+
+    jbyte CallStaticByteMethod(jclass clazz,
+                               jmethodID methodID, ...) {
+        va_list args;
+        jbyte result;
+        va_start(args,methodID);
+        result = functions->CallStaticByteMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jbyte CallStaticByteMethodV(jclass clazz,
+                                jmethodID methodID, va_list args) {
+        return functions->CallStaticByteMethodV(this,clazz,methodID,args);
+    }
+    jbyte CallStaticByteMethodA(jclass clazz,
+                                jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticByteMethodA(this,clazz,methodID,args);
+    }
+
+    jchar CallStaticCharMethod(jclass clazz,
+                               jmethodID methodID, ...) {
+        va_list args;
+        jchar result;
+        va_start(args,methodID);
+        result = functions->CallStaticCharMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jchar CallStaticCharMethodV(jclass clazz,
+                                jmethodID methodID, va_list args) {
+        return functions->CallStaticCharMethodV(this,clazz,methodID,args);
+    }
+    jchar CallStaticCharMethodA(jclass clazz,
+                                jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticCharMethodA(this,clazz,methodID,args);
+    }
+
+    jshort CallStaticShortMethod(jclass clazz,
+                                 jmethodID methodID, ...) {
+        va_list args;
+        jshort result;
+        va_start(args,methodID);
+        result = functions->CallStaticShortMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jshort CallStaticShortMethodV(jclass clazz,
+                                  jmethodID methodID, va_list args) {
+        return functions->CallStaticShortMethodV(this,clazz,methodID,args);
+    }
+    jshort CallStaticShortMethodA(jclass clazz,
+                                  jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticShortMethodA(this,clazz,methodID,args);
+    }
+
+    jint CallStaticIntMethod(jclass clazz,
+                             jmethodID methodID, ...) {
+        va_list args;
+        jint result;
+        va_start(args,methodID);
+        result = functions->CallStaticIntMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jint CallStaticIntMethodV(jclass clazz,
+                              jmethodID methodID, va_list args) {
+        return functions->CallStaticIntMethodV(this,clazz,methodID,args);
+    }
+    jint CallStaticIntMethodA(jclass clazz,
+                              jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticIntMethodA(this,clazz,methodID,args);
+    }
+
+    jlong CallStaticLongMethod(jclass clazz,
+                               jmethodID methodID, ...) {
+        va_list args;
+        jlong result;
+        va_start(args,methodID);
+        result = functions->CallStaticLongMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jlong CallStaticLongMethodV(jclass clazz,
+                                jmethodID methodID, va_list args) {
+        return functions->CallStaticLongMethodV(this,clazz,methodID,args);
+    }
+    jlong CallStaticLongMethodA(jclass clazz,
+                                jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticLongMethodA(this,clazz,methodID,args);
+    }
+
+    jfloat CallStaticFloatMethod(jclass clazz,
+                                 jmethodID methodID, ...) {
+        va_list args;
+        jfloat result;
+        va_start(args,methodID);
+        result = functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jfloat CallStaticFloatMethodV(jclass clazz,
+                                  jmethodID methodID, va_list args) {
+        return functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+    }
+    jfloat CallStaticFloatMethodA(jclass clazz,
+                                  jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticFloatMethodA(this,clazz,methodID,args);
+    }
+
+    jdouble CallStaticDoubleMethod(jclass clazz,
+                                   jmethodID methodID, ...) {
+        va_list args;
+        jdouble result;
+        va_start(args,methodID);
+        result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+        va_end(args);
+        return result;
+    }
+    jdouble CallStaticDoubleMethodV(jclass clazz,
+                                    jmethodID methodID, va_list args) {
+        return functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+    }
+    jdouble CallStaticDoubleMethodA(jclass clazz,
+                                    jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticDoubleMethodA(this,clazz,methodID,args);
+    }
+
+    void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) {
+        va_list args;
+        va_start(args,methodID);
+        functions->CallStaticVoidMethodV(this,cls,methodID,args);
+        va_end(args);
+    }
+    void CallStaticVoidMethodV(jclass cls, jmethodID methodID,
+                               va_list args) {
+        functions->CallStaticVoidMethodV(this,cls,methodID,args);
+    }
+    void CallStaticVoidMethodA(jclass cls, jmethodID methodID,
+                               const jvalue * args) {
+        functions->CallStaticVoidMethodA(this,cls,methodID,args);
+    }
+
+    jfieldID GetStaticFieldID(jclass clazz, const char *name,
+                              const char *sig) {
+        return functions->GetStaticFieldID(this,clazz,name,sig);
+    }
+    jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticObjectField(this,clazz,fieldID);
+    }
+    jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticBooleanField(this,clazz,fieldID);
+    }
+    jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticByteField(this,clazz,fieldID);
+    }
+    jchar GetStaticCharField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticCharField(this,clazz,fieldID);
+    }
+    jshort GetStaticShortField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticShortField(this,clazz,fieldID);
+    }
+    jint GetStaticIntField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticIntField(this,clazz,fieldID);
+    }
+    jlong GetStaticLongField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticLongField(this,clazz,fieldID);
+    }
+    jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticFloatField(this,clazz,fieldID);
+    }
+    jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticDoubleField(this,clazz,fieldID);
+    }
+
+    void SetStaticObjectField(jclass clazz, jfieldID fieldID,
+                        jobject value) {
+      functions->SetStaticObjectField(this,clazz,fieldID,value);
+    }
+    void SetStaticBooleanField(jclass clazz, jfieldID fieldID,
+                        jboolean value) {
+      functions->SetStaticBooleanField(this,clazz,fieldID,value);
+    }
+    void SetStaticByteField(jclass clazz, jfieldID fieldID,
+                        jbyte value) {
+      functions->SetStaticByteField(this,clazz,fieldID,value);
+    }
+    void SetStaticCharField(jclass clazz, jfieldID fieldID,
+                        jchar value) {
+      functions->SetStaticCharField(this,clazz,fieldID,value);
+    }
+    void SetStaticShortField(jclass clazz, jfieldID fieldID,
+                        jshort value) {
+      functions->SetStaticShortField(this,clazz,fieldID,value);
+    }
+    void SetStaticIntField(jclass clazz, jfieldID fieldID,
+                        jint value) {
+      functions->SetStaticIntField(this,clazz,fieldID,value);
+    }
+    void SetStaticLongField(jclass clazz, jfieldID fieldID,
+                        jlong value) {
+      functions->SetStaticLongField(this,clazz,fieldID,value);
+    }
+    void SetStaticFloatField(jclass clazz, jfieldID fieldID,
+                        jfloat value) {
+      functions->SetStaticFloatField(this,clazz,fieldID,value);
+    }
+    void SetStaticDoubleField(jclass clazz, jfieldID fieldID,
+                        jdouble value) {
+      functions->SetStaticDoubleField(this,clazz,fieldID,value);
+    }
+
+    jstring NewString(const jchar *unicode, jsize len) {
+        return functions->NewString(this,unicode,len);
+    }
+    jsize GetStringLength(jstring str) {
+        return functions->GetStringLength(this,str);
+    }
+    const jchar *GetStringChars(jstring str, jboolean *isCopy) {
+        return functions->GetStringChars(this,str,isCopy);
+    }
+    void ReleaseStringChars(jstring str, const jchar *chars) {
+        functions->ReleaseStringChars(this,str,chars);
+    }
+
+    jstring NewStringUTF(const char *utf) {
+        return functions->NewStringUTF(this,utf);
+    }
+    jsize GetStringUTFLength(jstring str) {
+        return functions->GetStringUTFLength(this,str);
+    }
+    const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
+        return functions->GetStringUTFChars(this,str,isCopy);
+    }
+    void ReleaseStringUTFChars(jstring str, const char* chars) {
+        functions->ReleaseStringUTFChars(this,str,chars);
+    }
+
+    jsize GetArrayLength(jarray array) {
+        return functions->GetArrayLength(this,array);
+    }
+
+    jobjectArray NewObjectArray(jsize len, jclass clazz,
+                                jobject init) {
+        return functions->NewObjectArray(this,len,clazz,init);
+    }
+    jobject GetObjectArrayElement(jobjectArray array, jsize index) {
+        return functions->GetObjectArrayElement(this,array,index);
+    }
+    void SetObjectArrayElement(jobjectArray array, jsize index,
+                               jobject val) {
+        functions->SetObjectArrayElement(this,array,index,val);
+    }
+
+    jbooleanArray NewBooleanArray(jsize len) {
+        return functions->NewBooleanArray(this,len);
+    }
+    jbyteArray NewByteArray(jsize len) {
+        return functions->NewByteArray(this,len);
+    }
+    jcharArray NewCharArray(jsize len) {
+        return functions->NewCharArray(this,len);
+    }
+    jshortArray NewShortArray(jsize len) {
+        return functions->NewShortArray(this,len);
+    }
+    jintArray NewIntArray(jsize len) {
+        return functions->NewIntArray(this,len);
+    }
+    jlongArray NewLongArray(jsize len) {
+        return functions->NewLongArray(this,len);
+    }
+    jfloatArray NewFloatArray(jsize len) {
+        return functions->NewFloatArray(this,len);
+    }
+    jdoubleArray NewDoubleArray(jsize len) {
+        return functions->NewDoubleArray(this,len);
+    }
+
+    jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) {
+        return functions->GetBooleanArrayElements(this,array,isCopy);
+    }
+    jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) {
+        return functions->GetByteArrayElements(this,array,isCopy);
+    }
+    jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) {
+        return functions->GetCharArrayElements(this,array,isCopy);
+    }
+    jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) {
+        return functions->GetShortArrayElements(this,array,isCopy);
+    }
+    jint * GetIntArrayElements(jintArray array, jboolean *isCopy) {
+        return functions->GetIntArrayElements(this,array,isCopy);
+    }
+    jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) {
+        return functions->GetLongArrayElements(this,array,isCopy);
+    }
+    jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) {
+        return functions->GetFloatArrayElements(this,array,isCopy);
+    }
+    jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) {
+        return functions->GetDoubleArrayElements(this,array,isCopy);
+    }
+
+    void ReleaseBooleanArrayElements(jbooleanArray array,
+                                     jboolean *elems,
+                                     jint mode) {
+        functions->ReleaseBooleanArrayElements(this,array,elems,mode);
+    }
+    void ReleaseByteArrayElements(jbyteArray array,
+                                  jbyte *elems,
+                                  jint mode) {
+        functions->ReleaseByteArrayElements(this,array,elems,mode);
+    }
+    void ReleaseCharArrayElements(jcharArray array,
+                                  jchar *elems,
+                                  jint mode) {
+        functions->ReleaseCharArrayElements(this,array,elems,mode);
+    }
+    void ReleaseShortArrayElements(jshortArray array,
+                                   jshort *elems,
+                                   jint mode) {
+        functions->ReleaseShortArrayElements(this,array,elems,mode);
+    }
+    void ReleaseIntArrayElements(jintArray array,
+                                 jint *elems,
+                                 jint mode) {
+        functions->ReleaseIntArrayElements(this,array,elems,mode);
+    }
+    void ReleaseLongArrayElements(jlongArray array,
+                                  jlong *elems,
+                                  jint mode) {
+        functions->ReleaseLongArrayElements(this,array,elems,mode);
+    }
+    void ReleaseFloatArrayElements(jfloatArray array,
+                                   jfloat *elems,
+                                   jint mode) {
+        functions->ReleaseFloatArrayElements(this,array,elems,mode);
+    }
+    void ReleaseDoubleArrayElements(jdoubleArray array,
+                                    jdouble *elems,
+                                    jint mode) {
+        functions->ReleaseDoubleArrayElements(this,array,elems,mode);
+    }
+
+    void GetBooleanArrayRegion(jbooleanArray array,
+                               jsize start, jsize len, jboolean *buf) {
+        functions->GetBooleanArrayRegion(this,array,start,len,buf);
+    }
+    void GetByteArrayRegion(jbyteArray array,
+                            jsize start, jsize len, jbyte *buf) {
+        functions->GetByteArrayRegion(this,array,start,len,buf);
+    }
+    void GetCharArrayRegion(jcharArray array,
+                            jsize start, jsize len, jchar *buf) {
+        functions->GetCharArrayRegion(this,array,start,len,buf);
+    }
+    void GetShortArrayRegion(jshortArray array,
+                             jsize start, jsize len, jshort *buf) {
+        functions->GetShortArrayRegion(this,array,start,len,buf);
+    }
+    void GetIntArrayRegion(jintArray array,
+                           jsize start, jsize len, jint *buf) {
+        functions->GetIntArrayRegion(this,array,start,len,buf);
+    }
+    void GetLongArrayRegion(jlongArray array,
+                            jsize start, jsize len, jlong *buf) {
+        functions->GetLongArrayRegion(this,array,start,len,buf);
+    }
+    void GetFloatArrayRegion(jfloatArray array,
+                             jsize start, jsize len, jfloat *buf) {
+        functions->GetFloatArrayRegion(this,array,start,len,buf);
+    }
+    void GetDoubleArrayRegion(jdoubleArray array,
+                              jsize start, jsize len, jdouble *buf) {
+        functions->GetDoubleArrayRegion(this,array,start,len,buf);
+    }
+
+    void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,
+                               const jboolean *buf) {
+        functions->SetBooleanArrayRegion(this,array,start,len,buf);
+    }
+    void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,
+                            const jbyte *buf) {
+        functions->SetByteArrayRegion(this,array,start,len,buf);
+    }
+    void SetCharArrayRegion(jcharArray array, jsize start, jsize len,
+                            const jchar *buf) {
+        functions->SetCharArrayRegion(this,array,start,len,buf);
+    }
+    void SetShortArrayRegion(jshortArray array, jsize start, jsize len,
+                             const jshort *buf) {
+        functions->SetShortArrayRegion(this,array,start,len,buf);
+    }
+    void SetIntArrayRegion(jintArray array, jsize start, jsize len,
+                           const jint *buf) {
+        functions->SetIntArrayRegion(this,array,start,len,buf);
+    }
+    void SetLongArrayRegion(jlongArray array, jsize start, jsize len,
+                            const jlong *buf) {
+        functions->SetLongArrayRegion(this,array,start,len,buf);
+    }
+    void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,
+                             const jfloat *buf) {
+        functions->SetFloatArrayRegion(this,array,start,len,buf);
+    }
+    void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,
+                              const jdouble *buf) {
+        functions->SetDoubleArrayRegion(this,array,start,len,buf);
+    }
+
+    jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,
+                         jint nMethods) {
+        return functions->RegisterNatives(this,clazz,methods,nMethods);
+    }
+    jint UnregisterNatives(jclass clazz) {
+        return functions->UnregisterNatives(this,clazz);
+    }
+
+    jint MonitorEnter(jobject obj) {
+        return functions->MonitorEnter(this,obj);
+    }
+    jint MonitorExit(jobject obj) {
+        return functions->MonitorExit(this,obj);
+    }
+
+    jint GetJavaVM(JavaVM **vm) {
+        return functions->GetJavaVM(this,vm);
+    }
+
+    void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) {
+        functions->GetStringRegion(this,str,start,len,buf);
+    }
+    void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) {
+        functions->GetStringUTFRegion(this,str,start,len,buf);
+    }
+
+    void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) {
+        return functions->GetPrimitiveArrayCritical(this,array,isCopy);
+    }
+    void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) {
+        functions->ReleasePrimitiveArrayCritical(this,array,carray,mode);
+    }
+
+    const jchar * GetStringCritical(jstring string, jboolean *isCopy) {
+        return functions->GetStringCritical(this,string,isCopy);
+    }
+    void ReleaseStringCritical(jstring string, const jchar *cstring) {
+        functions->ReleaseStringCritical(this,string,cstring);
+    }
+
+    jweak NewWeakGlobalRef(jobject obj) {
+        return functions->NewWeakGlobalRef(this,obj);
+    }
+    void DeleteWeakGlobalRef(jweak ref) {
+        functions->DeleteWeakGlobalRef(this,ref);
+    }
+
+    jboolean ExceptionCheck() {
+        return functions->ExceptionCheck(this);
+    }
+
+    jobject NewDirectByteBuffer(void* address, jlong capacity) {
+        return functions->NewDirectByteBuffer(this, address, capacity);
+    }
+    void* GetDirectBufferAddress(jobject buf) {
+        return functions->GetDirectBufferAddress(this, buf);
+    }
+    jlong GetDirectBufferCapacity(jobject buf) {
+        return functions->GetDirectBufferCapacity(this, buf);
+    }
+    jobjectRefType GetObjectRefType(jobject obj) {
+        return functions->GetObjectRefType(this, obj);
+    }
+
+#endif /* __cplusplus */
+};
+
+typedef struct JavaVMOption {
+    char *optionString;
+    void *extraInfo;
+} JavaVMOption;
+
+typedef struct JavaVMInitArgs {
+    jint version;
+
+    jint nOptions;
+    JavaVMOption *options;
+    jboolean ignoreUnrecognized;
+} JavaVMInitArgs;
+
+typedef struct JavaVMAttachArgs {
+    jint version;
+
+    char *name;
+    jobject group;
+} JavaVMAttachArgs;
+
+/* These will be VM-specific. */
+
+#define JDK1_2
+#define JDK1_4
+
+/* End VM-specific. */
+
+struct JNIInvokeInterface_ {
+    void *reserved0;
+    void *reserved1;
+    void *reserved2;
+
+    jint (JNICALL *DestroyJavaVM)(JavaVM *vm);
+
+    jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args);
+
+    jint (JNICALL *DetachCurrentThread)(JavaVM *vm);
+
+    jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version);
+
+    jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args);
+};
+
+struct JavaVM_ {
+    const struct JNIInvokeInterface_ *functions;
+#ifdef __cplusplus
+
+    jint DestroyJavaVM() {
+        return functions->DestroyJavaVM(this);
+    }
+    jint AttachCurrentThread(void **penv, void *args) {
+        return functions->AttachCurrentThread(this, penv, args);
+    }
+    jint DetachCurrentThread() {
+        return functions->DetachCurrentThread(this);
+    }
+
+    jint GetEnv(void **penv, jint version) {
+        return functions->GetEnv(this, penv, version);
+    }
+    jint AttachCurrentThreadAsDaemon(void **penv, void *args) {
+        return functions->AttachCurrentThreadAsDaemon(this, penv, args);
+    }
+#endif
+};
+
+#ifdef _JNI_IMPLEMENTATION_
+#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT
+#else
+#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT
+#endif
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_GetDefaultJavaVMInitArgs(void *args);
+
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);
+
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
+
+/* Defined by native libraries. */
+JNIEXPORT jint JNICALL
+JNI_OnLoad(JavaVM *vm, void *reserved);
+
+JNIEXPORT void JNICALL
+JNI_OnUnload(JavaVM *vm, void *reserved);
+
+#define JNI_VERSION_1_1 0x00010001
+#define JNI_VERSION_1_2 0x00010002
+#define JNI_VERSION_1_4 0x00010004
+#define JNI_VERSION_1_6 0x00010006
+#define JNI_VERSION_1_8 0x00010008
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* !_JAVASOFT_JNI_H_ */
diff --git a/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/linux/jni_md.h b/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/linux/jni_md.h
new file mode 100644
index 0000000..80eedf3
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/arm-linux-jni/linux/jni_md.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef _JAVASOFT_JNI_MD_H_
+#define _JAVASOFT_JNI_MD_H_
+
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
+  #define JNIEXPORT     __attribute__((visibility("default")))
+  #define JNIIMPORT     __attribute__((visibility("default")))
+#else
+  #define JNIEXPORT
+  #define JNIIMPORT
+#endif
+
+#define JNICALL
+
+typedef int jint;
+#ifdef _LP64 /* 64-bit Solaris */
+typedef long jlong;
+#else
+typedef long long jlong;
+#endif
+
+typedef signed char jbyte;
+
+#endif /* !_JAVASOFT_JNI_MD_H_ */
diff --git a/third_party/allwpilib_2018/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java b/third_party/allwpilib_2018/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java
new file mode 100644
index 0000000..fbab673
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java
@@ -0,0 +1,24 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.networktables.NetworkTablesJNI;
+import edu.wpi.first.wpiutil.RuntimeDetector;
+import edu.wpi.first.wpilibj.hal.HALUtil;
+
+public class DevMain {
+  /**
+   * Main entry point.
+   */
+  public static void main(String[] args) {
+    System.out.println("Hello World!");
+    System.out.println(RuntimeDetector.getPlatformPath());
+    System.out.println(NetworkTablesJNI.now());
+    System.out.println(HALUtil.getHALRuntimeType());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_I2C.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_I2C.java
new file mode 100644
index 0000000..ea21f81
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_I2C.java
@@ -0,0 +1,187 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.interfaces.Accelerometer;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * ADXL345 I2C Accelerometer.
+ */
+@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"})
+public class ADXL345_I2C extends SensorBase implements Accelerometer, Sendable {
+  private static final byte kAddress = 0x1D;
+  private static final byte kPowerCtlRegister = 0x2D;
+  private static final byte kDataFormatRegister = 0x31;
+  private static final byte kDataRegister = 0x32;
+  private static final double kGsPerLSB = 0.00390625;
+  private static final byte kPowerCtl_Link = 0x20;
+  private static final byte kPowerCtl_AutoSleep = 0x10;
+  private static final byte kPowerCtl_Measure = 0x08;
+  private static final byte kPowerCtl_Sleep = 0x04;
+
+  private static final byte kDataFormat_SelfTest = (byte) 0x80;
+  private static final byte kDataFormat_SPI = 0x40;
+  private static final byte kDataFormat_IntInvert = 0x20;
+  private static final byte kDataFormat_FullRes = 0x08;
+  private static final byte kDataFormat_Justify = 0x04;
+
+  public enum Axes {
+    kX((byte) 0x00),
+    kY((byte) 0x02),
+    kZ((byte) 0x04);
+
+    /**
+     * The integer value representing this enumeration.
+     */
+    @SuppressWarnings("MemberName")
+    public final byte value;
+
+    Axes(byte value) {
+      this.value = value;
+    }
+  }
+
+  @SuppressWarnings("MemberName")
+  public static class AllAxes {
+    public double XAxis;
+    public double YAxis;
+    public double ZAxis;
+  }
+
+  protected I2C m_i2c;
+
+  /**
+   * Constructs the ADXL345 Accelerometer with I2C address 0x1D.
+   *
+   * @param port  The I2C port the accelerometer is attached to
+   * @param range The range (+ or -) that the accelerometer will measure.
+   */
+  public ADXL345_I2C(I2C.Port port, Range range) {
+    this(port, range, kAddress);
+  }
+
+  /**
+   * Constructs the ADXL345 Accelerometer over I2C.
+   *
+   * @param port          The I2C port the accelerometer is attached to
+   * @param range         The range (+ or -) that the accelerometer will measure.
+   * @param deviceAddress I2C address of the accelerometer (0x1D or 0x53)
+   */
+  public ADXL345_I2C(I2C.Port port, Range range, int deviceAddress) {
+    m_i2c = new I2C(port, deviceAddress);
+
+    // Turn on the measurements
+    m_i2c.write(kPowerCtlRegister, kPowerCtl_Measure);
+
+    setRange(range);
+
+    HAL.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_I2C);
+    setName("ADXL345_I2C", port.value);
+  }
+
+  @Override
+  public void free() {
+    super.free();
+    m_i2c.free();
+  }
+
+  @Override
+  public void setRange(Range range) {
+    final byte value;
+
+    switch (range) {
+      case k2G:
+        value = 0;
+        break;
+      case k4G:
+        value = 1;
+        break;
+      case k8G:
+        value = 2;
+        break;
+      case k16G:
+        value = 3;
+        break;
+      default:
+        throw new IllegalArgumentException(range + " unsupported range type");
+    }
+
+    // Specify the data format to read
+    m_i2c.write(kDataFormatRegister, kDataFormat_FullRes | value);
+  }
+
+  @Override
+  public double getX() {
+    return getAcceleration(Axes.kX);
+  }
+
+  @Override
+  public double getY() {
+    return getAcceleration(Axes.kY);
+  }
+
+  @Override
+  public double getZ() {
+    return getAcceleration(Axes.kZ);
+  }
+
+  /**
+   * Get the acceleration of one axis in Gs.
+   *
+   * @param axis The axis to read from.
+   * @return Acceleration of the ADXL345 in Gs.
+   */
+  public double getAcceleration(Axes axis) {
+    ByteBuffer rawAccel = ByteBuffer.allocate(2);
+    m_i2c.read(kDataRegister + axis.value, 2, rawAccel);
+
+    // Sensor is little endian... swap bytes
+    rawAccel.order(ByteOrder.LITTLE_ENDIAN);
+    return rawAccel.getShort(0) * kGsPerLSB;
+  }
+
+  /**
+   * Get the acceleration of all axes in Gs.
+   *
+   * @return An object containing the acceleration measured on each axis of the ADXL345 in Gs.
+   */
+  public AllAxes getAccelerations() {
+    AllAxes data = new AllAxes();
+    ByteBuffer rawData = ByteBuffer.allocate(6);
+    m_i2c.read(kDataRegister, 6, rawData);
+
+    // Sensor is little endian... swap bytes
+    rawData.order(ByteOrder.LITTLE_ENDIAN);
+    data.XAxis = rawData.getShort(0) * kGsPerLSB;
+    data.YAxis = rawData.getShort(2) * kGsPerLSB;
+    data.ZAxis = rawData.getShort(4) * kGsPerLSB;
+    return data;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("3AxisAccelerometer");
+    NetworkTableEntry entryX = builder.getEntry("X");
+    NetworkTableEntry entryY = builder.getEntry("Y");
+    NetworkTableEntry entryZ = builder.getEntry("Z");
+    builder.setUpdateTable(() -> {
+      AllAxes data = getAccelerations();
+      entryX.setDouble(data.XAxis);
+      entryY.setDouble(data.YAxis);
+      entryZ.setDouble(data.ZAxis);
+    });
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java
new file mode 100644
index 0000000..48e0240
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java
@@ -0,0 +1,203 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.interfaces.Accelerometer;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * ADXL345 SPI Accelerometer.
+ */
+@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"})
+public class ADXL345_SPI extends SensorBase implements Accelerometer, Sendable {
+  private static final int kPowerCtlRegister = 0x2D;
+  private static final int kDataFormatRegister = 0x31;
+  private static final int kDataRegister = 0x32;
+  private static final double kGsPerLSB = 0.00390625;
+
+  private static final int kAddress_Read = 0x80;
+  private static final int kAddress_MultiByte = 0x40;
+
+  private static final int kPowerCtl_Link = 0x20;
+  private static final int kPowerCtl_AutoSleep = 0x10;
+  private static final int kPowerCtl_Measure = 0x08;
+  private static final int kPowerCtl_Sleep = 0x04;
+
+  private static final int kDataFormat_SelfTest = 0x80;
+  private static final int kDataFormat_SPI = 0x40;
+  private static final int kDataFormat_IntInvert = 0x20;
+  private static final int kDataFormat_FullRes = 0x08;
+  private static final int kDataFormat_Justify = 0x04;
+
+  public enum Axes {
+    kX((byte) 0x00),
+    kY((byte) 0x02),
+    kZ((byte) 0x04);
+
+    /**
+     * The integer value representing this enumeration.
+     */
+    @SuppressWarnings("MemberName")
+    public final byte value;
+
+    Axes(byte value) {
+      this.value = value;
+    }
+  }
+
+  @SuppressWarnings("MemberName")
+  public static class AllAxes {
+    public double XAxis;
+    public double YAxis;
+    public double ZAxis;
+  }
+
+  protected SPI m_spi;
+
+  /**
+   * Constructor.
+   *
+   * @param port  The SPI port that the accelerometer is connected to
+   * @param range The range (+ or -) that the accelerometer will measure.
+   */
+  public ADXL345_SPI(SPI.Port port, Range range) {
+    m_spi = new SPI(port);
+    init(range);
+    setName("ADXL345_SPI", port.value);
+  }
+
+  @Override
+  public void free() {
+    super.free();
+    m_spi.free();
+  }
+
+  /**
+   * Set SPI bus parameters, bring device out of sleep and set format.
+   *
+   * @param range The range (+ or -) that the accelerometer will measure.
+   */
+  private void init(Range range) {
+    m_spi.setClockRate(500000);
+    m_spi.setMSBFirst();
+    m_spi.setSampleDataOnFalling();
+    m_spi.setClockActiveLow();
+    m_spi.setChipSelectActiveHigh();
+
+    // Turn on the measurements
+    byte[] commands = new byte[2];
+    commands[0] = kPowerCtlRegister;
+    commands[1] = kPowerCtl_Measure;
+    m_spi.write(commands, 2);
+
+    setRange(range);
+
+    HAL.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_SPI);
+  }
+
+  @Override
+  public void setRange(Range range) {
+    final byte value;
+
+    switch (range) {
+      case k2G:
+        value = 0;
+        break;
+      case k4G:
+        value = 1;
+        break;
+      case k8G:
+        value = 2;
+        break;
+      case k16G:
+        value = 3;
+        break;
+      default:
+        throw new IllegalArgumentException(range + " unsupported");
+    }
+
+    // Specify the data format to read
+    byte[] commands = new byte[]{kDataFormatRegister, (byte) (kDataFormat_FullRes | value)};
+    m_spi.write(commands, commands.length);
+  }
+
+  @Override
+  public double getX() {
+    return getAcceleration(Axes.kX);
+  }
+
+  @Override
+  public double getY() {
+    return getAcceleration(Axes.kY);
+  }
+
+  @Override
+  public double getZ() {
+    return getAcceleration(Axes.kZ);
+  }
+
+  /**
+   * Get the acceleration of one axis in Gs.
+   *
+   * @param axis The axis to read from.
+   * @return Acceleration of the ADXL345 in Gs.
+   */
+  public double getAcceleration(ADXL345_SPI.Axes axis) {
+    ByteBuffer transferBuffer = ByteBuffer.allocate(3);
+    transferBuffer.put(0,
+        (byte) ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value));
+    m_spi.transaction(transferBuffer, transferBuffer, 3);
+    // Sensor is little endian
+    transferBuffer.order(ByteOrder.LITTLE_ENDIAN);
+
+    return transferBuffer.getShort(1) * kGsPerLSB;
+  }
+
+  /**
+   * Get the acceleration of all axes in Gs.
+   *
+   * @return An object containing the acceleration measured on each axis of the ADXL345 in Gs.
+   */
+  public ADXL345_SPI.AllAxes getAccelerations() {
+    ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes();
+    if (m_spi != null) {
+      ByteBuffer dataBuffer = ByteBuffer.allocate(7);
+      // Select the data address.
+      dataBuffer.put(0, (byte) (kAddress_Read | kAddress_MultiByte | kDataRegister));
+      m_spi.transaction(dataBuffer, dataBuffer, 7);
+      // Sensor is little endian... swap bytes
+      dataBuffer.order(ByteOrder.LITTLE_ENDIAN);
+
+      data.XAxis = dataBuffer.getShort(1) * kGsPerLSB;
+      data.YAxis = dataBuffer.getShort(3) * kGsPerLSB;
+      data.ZAxis = dataBuffer.getShort(5) * kGsPerLSB;
+    }
+    return data;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("3AxisAccelerometer");
+    NetworkTableEntry entryX = builder.getEntry("X");
+    NetworkTableEntry entryY = builder.getEntry("Y");
+    NetworkTableEntry entryZ = builder.getEntry("Z");
+    builder.setUpdateTable(() -> {
+      AllAxes data = getAccelerations();
+      entryX.setDouble(data.XAxis);
+      entryY.setDouble(data.YAxis);
+      entryZ.setDouble(data.ZAxis);
+    });
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java
new file mode 100644
index 0000000..021417d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java
@@ -0,0 +1,227 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.interfaces.Accelerometer;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * ADXL362 SPI Accelerometer.
+ *
+ * <p>This class allows access to an Analog Devices ADXL362 3-axis accelerometer.
+ */
+@SuppressWarnings("PMD.UnusedPrivateField")
+public class ADXL362 extends SensorBase implements Accelerometer, Sendable {
+  private static final byte kRegWrite = 0x0A;
+  private static final byte kRegRead = 0x0B;
+
+  private static final byte kPartIdRegister = 0x02;
+  private static final byte kDataRegister = 0x0E;
+  private static final byte kFilterCtlRegister = 0x2C;
+  private static final byte kPowerCtlRegister = 0x2D;
+
+  private static final byte kFilterCtl_Range2G = 0x00;
+  private static final byte kFilterCtl_Range4G = 0x40;
+  private static final byte kFilterCtl_Range8G = (byte) 0x80;
+  private static final byte kFilterCtl_ODR_100Hz = 0x03;
+
+  private static final byte kPowerCtl_UltraLowNoise = 0x20;
+  private static final byte kPowerCtl_AutoSleep = 0x04;
+  private static final byte kPowerCtl_Measure = 0x02;
+
+  public enum Axes {
+    kX((byte) 0x00),
+    kY((byte) 0x02),
+    kZ((byte) 0x04);
+
+    @SuppressWarnings("MemberName")
+    public final byte value;
+
+    Axes(byte value) {
+      this.value = value;
+    }
+  }
+
+  @SuppressWarnings("MemberName")
+  public static class AllAxes {
+    public double XAxis;
+    public double YAxis;
+    public double ZAxis;
+  }
+
+  private SPI m_spi;
+  private double m_gsPerLSB;
+
+  /**
+   * Constructor.  Uses the onboard CS1.
+   *
+   * @param range The range (+ or -) that the accelerometer will measure.
+   */
+  public ADXL362(Range range) {
+    this(SPI.Port.kOnboardCS1, range);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param port  The SPI port that the accelerometer is connected to
+   * @param range The range (+ or -) that the accelerometer will measure.
+   */
+  public ADXL362(SPI.Port port, Range range) {
+    m_spi = new SPI(port);
+
+    m_spi.setClockRate(3000000);
+    m_spi.setMSBFirst();
+    m_spi.setSampleDataOnFalling();
+    m_spi.setClockActiveLow();
+    m_spi.setChipSelectActiveLow();
+
+    // Validate the part ID
+    ByteBuffer transferBuffer = ByteBuffer.allocate(3);
+    transferBuffer.put(0, kRegRead);
+    transferBuffer.put(1, kPartIdRegister);
+    m_spi.transaction(transferBuffer, transferBuffer, 3);
+    if (transferBuffer.get(2) != (byte) 0xF2) {
+      m_spi.free();
+      m_spi = null;
+      DriverStation.reportError("could not find ADXL362 on SPI port " + port.value, false);
+      return;
+    }
+
+    setRange(range);
+
+    // Turn on the measurements
+    transferBuffer.put(0, kRegWrite);
+    transferBuffer.put(1, kPowerCtlRegister);
+    transferBuffer.put(2, (byte) (kPowerCtl_Measure | kPowerCtl_UltraLowNoise));
+    m_spi.write(transferBuffer, 3);
+
+    HAL.report(tResourceType.kResourceType_ADXL362, port.value);
+    setName("ADXL362", port.value);
+  }
+
+  @Override
+  public void free() {
+    super.free();
+    if (m_spi != null) {
+      m_spi.free();
+      m_spi = null;
+    }
+  }
+
+  @Override
+  public void setRange(Range range) {
+    if (m_spi == null) {
+      return;
+    }
+
+    final byte value;
+    switch (range) {
+      case k2G:
+        value = kFilterCtl_Range2G;
+        m_gsPerLSB = 0.001;
+        break;
+      case k4G:
+        value = kFilterCtl_Range4G;
+        m_gsPerLSB = 0.002;
+        break;
+      case k8G:
+      case k16G:  // 16G not supported; treat as 8G
+        value = kFilterCtl_Range8G;
+        m_gsPerLSB = 0.004;
+        break;
+      default:
+        throw new IllegalArgumentException(range + " unsupported");
+
+    }
+
+    // Specify the data format to read
+    byte[] commands = new byte[]{kRegWrite, kFilterCtlRegister, (byte) (kFilterCtl_ODR_100Hz
+        | value)};
+    m_spi.write(commands, commands.length);
+  }
+
+
+  @Override
+  public double getX() {
+    return getAcceleration(Axes.kX);
+  }
+
+  @Override
+  public double getY() {
+    return getAcceleration(Axes.kY);
+  }
+
+  @Override
+  public double getZ() {
+    return getAcceleration(Axes.kZ);
+  }
+
+  /**
+   * Get the acceleration of one axis in Gs.
+   *
+   * @param axis The axis to read from.
+   * @return Acceleration of the ADXL362 in Gs.
+   */
+  public double getAcceleration(ADXL362.Axes axis) {
+    if (m_spi == null) {
+      return 0.0;
+    }
+    ByteBuffer transferBuffer = ByteBuffer.allocate(4);
+    transferBuffer.put(0, kRegRead);
+    transferBuffer.put(1, (byte) (kDataRegister + axis.value));
+    m_spi.transaction(transferBuffer, transferBuffer, 4);
+    // Sensor is little endian
+    transferBuffer.order(ByteOrder.LITTLE_ENDIAN);
+
+    return transferBuffer.getShort(2) * m_gsPerLSB;
+  }
+
+  /**
+   * Get the acceleration of all axes in Gs.
+   *
+   * @return An object containing the acceleration measured on each axis of the ADXL362 in Gs.
+   */
+  public ADXL362.AllAxes getAccelerations() {
+    ADXL362.AllAxes data = new ADXL362.AllAxes();
+    if (m_spi != null) {
+      ByteBuffer dataBuffer = ByteBuffer.allocate(8);
+      // Select the data address.
+      dataBuffer.put(0, kRegRead);
+      dataBuffer.put(1, kDataRegister);
+      m_spi.transaction(dataBuffer, dataBuffer, 8);
+      // Sensor is little endian... swap bytes
+      dataBuffer.order(ByteOrder.LITTLE_ENDIAN);
+
+      data.XAxis = dataBuffer.getShort(2) * m_gsPerLSB;
+      data.YAxis = dataBuffer.getShort(4) * m_gsPerLSB;
+      data.ZAxis = dataBuffer.getShort(6) * m_gsPerLSB;
+    }
+    return data;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("3AxisAccelerometer");
+    NetworkTableEntry entryX = builder.getEntry("X");
+    NetworkTableEntry entryY = builder.getEntry("Y");
+    NetworkTableEntry entryZ = builder.getEntry("Z");
+    builder.setUpdateTable(() -> {
+      AllAxes data = getAccelerations();
+      entryX.setDouble(data.XAxis);
+      entryY.setDouble(data.YAxis);
+      entryZ.setDouble(data.ZAxis);
+    });
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java
new file mode 100644
index 0000000..bbef3c5
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java
@@ -0,0 +1,161 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.interfaces.Gyro;
+
+/**
+ * Use a rate gyro to return the robots heading relative to a starting position. The Gyro class
+ * tracks the robots heading based on the starting position. As the robot rotates the new heading is
+ * computed by integrating the rate of rotation returned by the sensor. When the class is
+ * instantiated, it does a short calibration routine where it samples the gyro while at rest to
+ * determine the default offset. This is subtracted from each sample to determine the heading.
+ *
+ * <p>This class is for the digital ADXRS450 gyro sensor that connects via SPI.
+ */
+@SuppressWarnings({"TypeName", "AbbreviationAsWordInName", "PMD.UnusedPrivateField"})
+public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable {
+  private static final double kSamplePeriod = 0.0005;
+  private static final double kCalibrationSampleTime = 5.0;
+  private static final double kDegreePerSecondPerLSB = 0.0125;
+
+  private static final int kRateRegister = 0x00;
+  private static final int kTemRegister = 0x02;
+  private static final int kLoCSTRegister = 0x04;
+  private static final int kHiCSTRegister = 0x06;
+  private static final int kQuadRegister = 0x08;
+  private static final int kFaultRegister = 0x0A;
+  private static final int kPIDRegister = 0x0C;
+  private static final int kSNHighRegister = 0x0E;
+  private static final int kSNLowRegister = 0x10;
+
+  private SPI m_spi;
+
+  /**
+   * Constructor.  Uses the onboard CS0.
+   */
+  public ADXRS450_Gyro() {
+    this(SPI.Port.kOnboardCS0);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param port The SPI port that the gyro is connected to
+   */
+  public ADXRS450_Gyro(SPI.Port port) {
+    m_spi = new SPI(port);
+
+    m_spi.setClockRate(3000000);
+    m_spi.setMSBFirst();
+    m_spi.setSampleDataOnRising();
+    m_spi.setClockActiveHigh();
+    m_spi.setChipSelectActiveLow();
+
+    // Validate the part ID
+    if ((readRegister(kPIDRegister) & 0xff00) != 0x5200) {
+      m_spi.free();
+      m_spi = null;
+      DriverStation.reportError("could not find ADXRS450 gyro on SPI port " + port.value,
+          false);
+      return;
+    }
+
+    m_spi.initAccumulator(kSamplePeriod, 0x20000000, 4, 0x0c00000e, 0x04000000, 10, 16,
+        true, true);
+
+    calibrate();
+
+    HAL.report(tResourceType.kResourceType_ADXRS450, port.value);
+    setName("ADXRS450_Gyro", port.value);
+  }
+
+  @Override
+  public void calibrate() {
+    if (m_spi == null) {
+      return;
+    }
+
+    Timer.delay(0.1);
+
+    m_spi.setAccumulatorCenter(0);
+    m_spi.resetAccumulator();
+
+    Timer.delay(kCalibrationSampleTime);
+
+    m_spi.setAccumulatorCenter((int) m_spi.getAccumulatorAverage());
+    m_spi.resetAccumulator();
+  }
+
+  private boolean calcParity(int value) {
+    boolean parity = false;
+    while (value != 0) {
+      parity = !parity;
+      value = value & (value - 1);
+    }
+    return parity;
+  }
+
+  private int readRegister(int reg) {
+    int cmdhi = 0x8000 | (reg << 1);
+    boolean parity = calcParity(cmdhi);
+
+    ByteBuffer buf = ByteBuffer.allocate(4);
+    buf.order(ByteOrder.BIG_ENDIAN);
+    buf.put(0, (byte) (cmdhi >> 8));
+    buf.put(1, (byte) (cmdhi & 0xff));
+    buf.put(2, (byte) 0);
+    buf.put(3, (byte) (parity ? 0 : 1));
+
+    m_spi.write(buf, 4);
+    m_spi.read(false, buf, 4);
+
+    if ((buf.get(0) & 0xe0) == 0) {
+      return 0;  // error, return 0
+    }
+    return (buf.getInt(0) >> 5) & 0xffff;
+  }
+
+  @Override
+  public void reset() {
+    m_spi.resetAccumulator();
+  }
+
+  /**
+   * Delete (free) the spi port used for the gyro and stop accumulating.
+   */
+  @Override
+  public void free() {
+    super.free();
+    if (m_spi != null) {
+      m_spi.free();
+      m_spi = null;
+    }
+  }
+
+  @Override
+  public double getAngle() {
+    if (m_spi == null) {
+      return 0.0;
+    }
+    return m_spi.getAccumulatorValue() * kDegreePerSecondPerLSB * kSamplePeriod;
+  }
+
+  @Override
+  public double getRate() {
+    if (m_spi == null) {
+      return 0.0;
+    }
+    return m_spi.getAccumulatorLastValue() * kDegreePerSecondPerLSB;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AccumulatorResult.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AccumulatorResult.java
new file mode 100644
index 0000000..7921637
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj;
+
+/**
+ * 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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogAccelerometer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogAccelerometer.java
new file mode 100644
index 0000000..a7c2c82
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogAccelerometer.java
@@ -0,0 +1,141 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Handle operation of an analog accelerometer. The accelerometer reads acceleration directly
+ * through the sensor. Many sensors have multiple axis and can be treated as multiple devices. Each
+ * is calibrated by finding the center value over a period of time.
+ */
+public class AnalogAccelerometer extends SensorBase implements PIDSource, Sendable {
+  private AnalogInput m_analogChannel;
+  private double m_voltsPerG = 1.0;
+  private double m_zeroGVoltage = 2.5;
+  private boolean m_allocatedChannel;
+  protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
+
+  /**
+   * Common initialization.
+   */
+  private void initAccelerometer() {
+    HAL.report(tResourceType.kResourceType_Accelerometer,
+                                   m_analogChannel.getChannel());
+    setName("Accelerometer", m_analogChannel.getChannel());
+  }
+
+  /**
+   * Create a new instance of an accelerometer.
+   *
+   * <p>The constructor allocates desired analog channel.
+   *
+   * @param channel The channel number for the analog input the accelerometer is connected to
+   */
+  public AnalogAccelerometer(final int channel) {
+    this(new AnalogInput(channel));
+    m_allocatedChannel = true;
+    addChild(m_analogChannel);
+  }
+
+  /**
+   * Create a new instance of Accelerometer from an existing AnalogChannel. Make a new instance of
+   * accelerometer given an AnalogChannel. This is particularly useful if the port is going to be
+   * read as an analog channel as well as through the Accelerometer class.
+   *
+   * @param channel The existing AnalogInput object for the analog input the accelerometer is
+   *                connected to
+   */
+  public AnalogAccelerometer(AnalogInput channel) {
+    requireNonNull(channel, "Analog Channel given was null");
+
+    m_allocatedChannel = false;
+    m_analogChannel = channel;
+    initAccelerometer();
+  }
+
+  /**
+   * Delete the analog components used for the accelerometer.
+   */
+  @Override
+  public void free() {
+    super.free();
+    if (m_analogChannel != null && m_allocatedChannel) {
+      m_analogChannel.free();
+    }
+    m_analogChannel = null;
+  }
+
+  /**
+   * Return the acceleration in Gs.
+   *
+   * <p>The acceleration is returned units of Gs.
+   *
+   * @return The current acceleration of the sensor in Gs.
+   */
+  public double getAcceleration() {
+    if (m_analogChannel == null) {
+      return 0.0;
+    }
+    return (m_analogChannel.getAverageVoltage() - m_zeroGVoltage) / m_voltsPerG;
+  }
+
+  /**
+   * Set the accelerometer sensitivity.
+   *
+   * <p>This sets the sensitivity of the accelerometer used for calculating the acceleration. The
+   * sensitivity varies by accelerometer model. There are constants defined for various models.
+   *
+   * @param sensitivity The sensitivity of accelerometer in Volts per G.
+   */
+  public void setSensitivity(double sensitivity) {
+    m_voltsPerG = sensitivity;
+  }
+
+  /**
+   * Set the voltage that corresponds to 0 G.
+   *
+   * <p>The zero G voltage varies by accelerometer model. There are constants defined for various
+   * models.
+   *
+   * @param zero The zero G voltage.
+   */
+  public void setZero(double zero) {
+    m_zeroGVoltage = zero;
+  }
+
+  @Override
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    m_pidSource = pidSource;
+  }
+
+  @Override
+  public PIDSourceType getPIDSourceType() {
+    return m_pidSource;
+  }
+
+  /**
+   * Get the Acceleration for the PID Source parent.
+   *
+   * @return The current acceleration in Gs.
+   */
+  @Override
+  public double pidGet() {
+    return getAcceleration();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Accelerometer");
+    builder.addDoubleProperty("Value", this::getAcceleration, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogGyro.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogGyro.java
new file mode 100644
index 0000000..b03fa99
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogGyro.java
@@ -0,0 +1,189 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.AnalogGyroJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.interfaces.Gyro;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Use a rate gyro to return the robots heading relative to a starting position. The Gyro class
+ * tracks the robots heading based on the starting position. As the robot rotates the new heading is
+ * computed by integrating the rate of rotation returned by the sensor. When the class is
+ * instantiated, it does a short calibration routine where it samples the gyro while at rest to
+ * determine the default offset. This is subtracted from each sample to determine the heading.
+ *
+ * <p>This class is for gyro sensors that connect to an analog input.
+ */
+public class AnalogGyro extends GyroBase implements Gyro, PIDSource, Sendable {
+  private static final double kDefaultVoltsPerDegreePerSecond = 0.007;
+  protected AnalogInput m_analog;
+  private boolean m_channelAllocated = false;
+
+  private int m_gyroHandle = 0;
+
+  /**
+   * Initialize the gyro. Calibration is handled by calibrate().
+   */
+  public void initGyro() {
+    if (m_gyroHandle == 0) {
+      m_gyroHandle = AnalogGyroJNI.initializeAnalogGyro(m_analog.m_port);
+    }
+
+    AnalogGyroJNI.setupAnalogGyro(m_gyroHandle);
+
+    HAL.report(tResourceType.kResourceType_Gyro, m_analog.getChannel());
+    setName("AnalogGyro", m_analog.getChannel());
+  }
+
+  @Override
+  public void calibrate() {
+    AnalogGyroJNI.calibrateAnalogGyro(m_gyroHandle);
+  }
+
+  /**
+   * Gyro constructor using the channel number.
+   *
+   * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
+   *                channels 0-1.
+   */
+  public AnalogGyro(int channel) {
+    this(new AnalogInput(channel));
+    m_channelAllocated = true;
+    addChild(m_analog);
+  }
+
+  /**
+   * Gyro constructor with a precreated analog channel object. Use this constructor when the analog
+   * channel needs to be shared.
+   *
+   * @param channel The AnalogInput object that the gyro is connected to. Gyros can only be used on
+   *                on-board channels 0-1.
+   */
+  public AnalogGyro(AnalogInput channel) {
+    requireNonNull(channel, "AnalogInput supplied to Gyro constructor is null");
+
+    m_analog = channel;
+    initGyro();
+    calibrate();
+  }
+
+  /**
+   * Gyro constructor using the channel number along with parameters for presetting the center and
+   * offset values. Bypasses calibration.
+   *
+   * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
+   *                channels 0-1.
+   * @param center  Preset uncalibrated value to use as the accumulator center value.
+   * @param offset  Preset uncalibrated value to use as the gyro offset.
+   */
+  public AnalogGyro(int channel, int center, double offset) {
+    this(new AnalogInput(channel), center, offset);
+    m_channelAllocated = true;
+    addChild(m_analog);
+  }
+
+  /**
+   * Gyro constructor with a precreated analog channel object along with parameters for presetting
+   * the center and offset values. Bypasses calibration.
+   *
+   * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
+   *                channels 0-1.
+   * @param center  Preset uncalibrated value to use as the accumulator center value.
+   * @param offset  Preset uncalibrated value to use as the gyro offset.
+   */
+  public AnalogGyro(AnalogInput channel, int center, double offset) {
+    requireNonNull(channel, "AnalogInput supplied to Gyro constructor is null");
+
+    m_analog = channel;
+    initGyro();
+    AnalogGyroJNI.setAnalogGyroParameters(m_gyroHandle, kDefaultVoltsPerDegreePerSecond,
+                                          offset, center);
+    reset();
+  }
+
+  @Override
+  public void reset() {
+    AnalogGyroJNI.resetAnalogGyro(m_gyroHandle);
+  }
+
+  /**
+   * Delete (free) the accumulator and the analog components used for the gyro.
+   */
+  @Override
+  public void free() {
+    super.free();
+    if (m_analog != null && m_channelAllocated) {
+      m_analog.free();
+    }
+    m_analog = null;
+    AnalogGyroJNI.freeAnalogGyro(m_gyroHandle);
+  }
+
+  @Override
+  public double getAngle() {
+    if (m_analog == null) {
+      return 0.0;
+    } else {
+      return AnalogGyroJNI.getAnalogGyroAngle(m_gyroHandle);
+    }
+  }
+
+  @Override
+  public double getRate() {
+    if (m_analog == null) {
+      return 0.0;
+    } else {
+      return AnalogGyroJNI.getAnalogGyroRate(m_gyroHandle);
+    }
+  }
+
+  /**
+   * Return the gyro offset value set during calibration to use as a future preset.
+   *
+   * @return the current offset value
+   */
+  public double getOffset() {
+    return AnalogGyroJNI.getAnalogGyroOffset(m_gyroHandle);
+  }
+
+  /**
+   * Return the gyro center value set during calibration to use as a future preset.
+   *
+   * @return the current center value
+   */
+  public int getCenter() {
+    return AnalogGyroJNI.getAnalogGyroCenter(m_gyroHandle);
+  }
+
+  /**
+   * Set the gyro sensitivity. This takes the number of volts/degree/second sensitivity of the gyro
+   * and uses it in subsequent calculations to allow the code to work with multiple gyros. This
+   * value is typically found in the gyro datasheet.
+   *
+   * @param voltsPerDegreePerSecond The sensitivity in Volts/degree/second.
+   */
+  public void setSensitivity(double voltsPerDegreePerSecond) {
+    AnalogGyroJNI.setAnalogGyroVoltsPerDegreePerSecond(m_gyroHandle,
+                                                       voltsPerDegreePerSecond);
+  }
+
+  /**
+   * Set the size of the neutral zone. Any voltage from the gyro less than this amount from the
+   * center is considered stationary. Setting a deadband will decrease the amount of drift when the
+   * gyro isn't rotating, but will make it less accurate.
+   *
+   * @param volts The size of the deadband in volts
+   */
+  void setDeadband(double volts) {
+    AnalogGyroJNI.setAnalogGyroDeadband(m_gyroHandle, volts);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogInput.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogInput.java
new file mode 100644
index 0000000..43426f8
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogInput.java
@@ -0,0 +1,353 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.AnalogJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+import edu.wpi.first.wpilibj.util.AllocationException;
+
+/**
+ * Analog channel class.
+ *
+ * <p>Each analog channel is read from hardware as a 12-bit number representing 0V to 5V.
+ *
+ * <p>Connected to each analog channel is an averaging and oversampling engine. This engine
+ * accumulates the specified ( by setAverageBits() and setOversampleBits() ) number of samples
+ * before returning a new value. This is not a sliding window average. The only difference between
+ * the oversampled samples and the averaged samples is that the oversampled samples are simply
+ * accumulated effectively increasing the resolution, while the averaged samples are divided by the
+ * number of samples to retain the resolution, but get more stable values.
+ */
+public class AnalogInput extends SensorBase implements PIDSource, Sendable {
+  private static final int kAccumulatorSlot = 1;
+  int m_port; // explicit no modifier, private and package accessible.
+  private int m_channel;
+  private static final int[] kAccumulatorChannels = {0, 1};
+  private long m_accumulatorOffset;
+  protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
+
+  /**
+   * Construct an analog channel.
+   *
+   * @param channel The channel number to represent. 0-3 are on-board 4-7 are on the MXP port.
+   */
+  public AnalogInput(final int channel) {
+    checkAnalogInputChannel(channel);
+    m_channel = channel;
+
+    final int portHandle = AnalogJNI.getPort((byte) channel);
+    m_port = AnalogJNI.initializeAnalogInputPort(portHandle);
+
+    HAL.report(tResourceType.kResourceType_AnalogChannel, channel);
+    setName("AnalogInput", channel);
+  }
+
+  /**
+   * Channel destructor.
+   */
+  @Override
+  public void free() {
+    super.free();
+    AnalogJNI.freeAnalogInputPort(m_port);
+    m_port = 0;
+    m_channel = 0;
+    m_accumulatorOffset = 0;
+  }
+
+  /**
+   * Get a sample straight from this channel. The sample is a 12-bit value representing the 0V to 5V
+   * range of the A/D converter. The units are in A/D converter codes. Use GetVoltage() to get the
+   * analog value in calibrated units.
+   *
+   * @return A sample straight from this channel.
+   */
+  public int getValue() {
+    return AnalogJNI.getAnalogValue(m_port);
+  }
+
+  /**
+   * Get a sample from the output of the oversample and average engine for this channel. The sample
+   * is 12-bit + the bits 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^(OversampleBits + AverageBits) samples have
+   * been acquired from this channel. Use getAverageVoltage() to get the analog value in calibrated
+   * units.
+   *
+   * @return A sample from the oversample and average engine for this channel.
+   */
+  public int getAverageValue() {
+    return AnalogJNI.getAnalogAverageValue(m_port);
+  }
+
+  /**
+   * Get a scaled sample straight from this channel. The value is scaled to units of Volts using the
+   * calibrated scaling data from getLSBWeight() and getOffset().
+   *
+   * @return A scaled sample straight from this channel.
+   */
+  public double getVoltage() {
+    return AnalogJNI.getAnalogVoltage(m_port);
+  }
+
+  /**
+   * Get a scaled sample from the output of the oversample and average engine for this 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.
+   *
+   * @return A scaled sample from the output of the oversample and average engine for this channel.
+   */
+  public double getAverageVoltage() {
+    return AnalogJNI.getAnalogAverageVoltage(m_port);
+  }
+
+  /**
+   * Get 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.
+   *
+   * <p>Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
+   *
+   * @return Least significant bit weight.
+   */
+  public long getLSBWeight() {
+    return AnalogJNI.getAnalogLSBWeight(m_port);
+  }
+
+  /**
+   * Get the factory scaling offset constant. The offset constant for the channel that was
+   * calibrated in manufacturing and stored in an eeprom.
+   *
+   * <p>Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
+   *
+   * @return Offset constant.
+   */
+  public int getOffset() {
+    return AnalogJNI.getAnalogOffset(m_port);
+  }
+
+  /**
+   * Get the channel number.
+   *
+   * @return The channel number.
+   */
+  public int getChannel() {
+    return m_channel;
+  }
+
+  /**
+   * Set the number of averaging bits. This sets the number of averaging bits. The actual number of
+   * averaged samples is 2^bits. The averaging is done automatically in the FPGA.
+   *
+   * @param bits The number of averaging bits.
+   */
+  public void setAverageBits(final int bits) {
+    AnalogJNI.setAnalogAverageBits(m_port, bits);
+  }
+
+  /**
+   * Get 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.
+   *
+   * @return The number of averaging bits.
+   */
+  public int getAverageBits() {
+    return AnalogJNI.getAnalogAverageBits(m_port);
+  }
+
+  /**
+   * Set the number of oversample bits. This sets the number of oversample bits. The actual number
+   * of oversampled values is 2^bits. The oversampling is done automatically in the FPGA.
+   *
+   * @param bits The number of oversample bits.
+   */
+  public void setOversampleBits(final int bits) {
+    AnalogJNI.setAnalogOversampleBits(m_port, bits);
+  }
+
+  /**
+   * Get 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.
+   *
+   * @return The number of oversample bits.
+   */
+  public int getOversampleBits() {
+    return AnalogJNI.getAnalogOversampleBits(m_port);
+  }
+
+  /**
+   * Initialize the accumulator.
+   */
+  public void initAccumulator() {
+    if (!isAccumulatorChannel()) {
+      throw new AllocationException("Accumulators are only available on slot " + kAccumulatorSlot
+          + " on channels " + kAccumulatorChannels[0] + ", " + kAccumulatorChannels[1]);
+    }
+    m_accumulatorOffset = 0;
+    AnalogJNI.initAccumulator(m_port);
+  }
+
+  /**
+   * Set an initial value for the accumulator.
+   *
+   * <p>This will be added to all values returned to the user.
+   *
+   * @param initialValue The value that the accumulator should start from when reset.
+   */
+  public void setAccumulatorInitialValue(long initialValue) {
+    m_accumulatorOffset = initialValue;
+  }
+
+  /**
+   * Resets the accumulator to the initial value.
+   */
+  public void resetAccumulator() {
+    AnalogJNI.resetAccumulator(m_port);
+
+    // Wait until the next sample, so the next call to getAccumulator*()
+    // won't have old values.
+    final double sampleTime = 1.0 / getGlobalSampleRate();
+    final double overSamples = 1 << getOversampleBits();
+    final double averageSamples = 1 << getAverageBits();
+    Timer.delay(sampleTime * overSamples * averageSamples);
+
+  }
+
+  /**
+   * Set the center value of the accumulator.
+   *
+   * <p>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 take the device
+   * offset into account when integrating.
+   *
+   * <p>This center value is based on the output of the oversampled and averaged source the
+   * accumulator channel. Because of this, any non-zero oversample bits will affect the size of the
+   * value for this field.
+   */
+  public void setAccumulatorCenter(int center) {
+    AnalogJNI.setAccumulatorCenter(m_port, center);
+  }
+
+  /**
+   * Set the accumulator's deadband.
+   *
+   * @param deadband The deadband size in ADC codes (12-bit value)
+   */
+  public void setAccumulatorDeadband(int deadband) {
+    AnalogJNI.setAccumulatorDeadband(m_port, deadband);
+  }
+
+  /**
+   * Read the accumulated value.
+   *
+   * <p>Read the value that has been accumulating. The accumulator is attached after the oversample
+   * and average engine.
+   *
+   * @return The 64-bit value accumulated since the last Reset().
+   */
+  public long getAccumulatorValue() {
+    return AnalogJNI.getAccumulatorValue(m_port) + m_accumulatorOffset;
+  }
+
+  /**
+   * Read the number of accumulated values.
+   *
+   * <p>Read the count of the accumulated values since the accumulator was last Reset().
+   *
+   * @return The number of times samples from the channel were accumulated.
+   */
+  public long getAccumulatorCount() {
+    return AnalogJNI.getAccumulatorCount(m_port);
+  }
+
+  /**
+   * Read the accumulated value and the number of accumulated values atomically.
+   *
+   * <p>This function reads the value and count from the FPGA atomically. This can be used for
+   * averaging.
+   *
+   * @param result AccumulatorResult object to store the results in.
+   */
+  public void getAccumulatorOutput(AccumulatorResult result) {
+    if (result == null) {
+      throw new IllegalArgumentException("Null parameter `result'");
+    }
+    if (!isAccumulatorChannel()) {
+      throw new IllegalArgumentException(
+          "Channel " + m_channel + " is not an accumulator channel.");
+    }
+    AnalogJNI.getAccumulatorOutput(m_port, result);
+    result.value += m_accumulatorOffset;
+  }
+
+  /**
+   * Is the channel attached to an accumulator.
+   *
+   * @return The analog channel is attached to an accumulator.
+   */
+  public boolean isAccumulatorChannel() {
+    for (int channel : kAccumulatorChannels) {
+      if (m_channel == channel) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Set the sample rate per channel.
+   *
+   * <p>This is a global setting for all channels. The maximum rate is 500kS/s divided by the number
+   * of channels in use. This is 62500 samples/s per channel if all 8 channels are used.
+   *
+   * @param samplesPerSecond The number of samples per second.
+   */
+  public static void setGlobalSampleRate(final double samplesPerSecond) {
+    AnalogJNI.setAnalogSampleRate(samplesPerSecond);
+  }
+
+  /**
+   * Get the current sample rate.
+   *
+   * <p>This assumes one entry in the scan list. This is a global setting for all channels.
+   *
+   * @return Sample rate.
+   */
+  public static double getGlobalSampleRate() {
+    return AnalogJNI.getAnalogSampleRate();
+  }
+
+  @Override
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    m_pidSource = pidSource;
+  }
+
+  @Override
+  public PIDSourceType getPIDSourceType() {
+    return m_pidSource;
+  }
+
+  /**
+   * Get the average voltage for use with PIDController.
+   *
+   * @return the average voltage
+   */
+  @Override
+  public double pidGet() {
+    return getAverageVoltage();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Analog Input");
+    builder.addDoubleProperty("Value", this::getAverageVoltage, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogOutput.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogOutput.java
new file mode 100644
index 0000000..e354234
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogOutput.java
@@ -0,0 +1,69 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2014-2018 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.AnalogJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Analog output class.
+ */
+public class AnalogOutput extends SendableBase implements Sendable {
+  private int m_port;
+  private int m_channel;
+
+  /**
+   * Construct an analog output on a specified MXP channel.
+   *
+   * @param channel The channel number to represent.
+   */
+  public AnalogOutput(final int channel) {
+    SensorBase.checkAnalogOutputChannel(channel);
+    m_channel = channel;
+
+    final int portHandle = AnalogJNI.getPort((byte) channel);
+    m_port = AnalogJNI.initializeAnalogOutputPort(portHandle);
+
+    HAL.report(tResourceType.kResourceType_AnalogOutput, channel);
+    setName("AnalogOutput", channel);
+  }
+
+  /**
+   * Channel destructor.
+   */
+  @Override
+  public void free() {
+    super.free();
+    AnalogJNI.freeAnalogOutputPort(m_port);
+    m_port = 0;
+    m_channel = 0;
+  }
+
+  /**
+   * Get the channel of this AnalogOutput.
+   */
+  public int getChannel() {
+    return m_channel;
+  }
+
+  public void setVoltage(double voltage) {
+    AnalogJNI.setAnalogOutput(m_port, voltage);
+  }
+
+  public double getVoltage() {
+    return AnalogJNI.getAnalogOutput(m_port);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Analog Output");
+    builder.addDoubleProperty("Value", this::getVoltage, this::setVoltage);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java
new file mode 100644
index 0000000..d2ae80b
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java
@@ -0,0 +1,169 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.wpilibj.interfaces.Potentiometer;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Class for reading analog potentiometers. Analog potentiometers read in an analog voltage that
+ * corresponds to a position. The position is in whichever units you choose, by way of the scaling
+ * and offset constants passed to the constructor.
+ */
+public class AnalogPotentiometer extends SensorBase implements Potentiometer, Sendable {
+  private AnalogInput m_analogInput;
+  private boolean m_initAnalogInput;
+  private double m_fullRange;
+  private double m_offset;
+  protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
+
+  /**
+   * AnalogPotentiometer constructor.
+   *
+   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
+   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
+   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
+   * point after scaling is 135 degrees. This will calculate the result from the fullRange times
+   * the fraction of the supply voltage, plus the offset.
+   *
+   * @param channel   The analog channel this potentiometer is plugged into.
+   * @param fullRange The scaling to multiply the fraction by to get a meaningful unit.
+   * @param offset    The offset to add to the scaled value for controlling the zero value
+   */
+  public AnalogPotentiometer(final int channel, double fullRange, double offset) {
+    this(new AnalogInput(channel), fullRange, offset);
+    m_initAnalogInput = true;
+    addChild(m_analogInput);
+  }
+
+  /**
+   * AnalogPotentiometer constructor.
+   *
+   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
+   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
+   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
+   * point after scaling is 135 degrees. This will calculate the result from the fullRange times
+   * the fraction of the supply voltage, plus the offset.
+   *
+   * @param input     The {@link AnalogInput} this potentiometer is plugged into.
+   * @param fullRange The scaling to multiply the fraction by to get a meaningful unit.
+   * @param offset    The offset to add to the scaled value for controlling the zero value
+   */
+  public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) {
+    setName("AnalogPotentiometer", input.getChannel());
+    m_analogInput = input;
+    m_initAnalogInput = false;
+
+    m_fullRange = fullRange;
+    m_offset = offset;
+  }
+
+  /**
+   * AnalogPotentiometer constructor.
+   *
+   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
+   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
+   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
+   * point after scaling is 135 degrees.
+   *
+   * @param channel The analog channel this potentiometer is plugged into.
+   * @param scale   The scaling to multiply the voltage by to get a meaningful unit.
+   */
+  public AnalogPotentiometer(final int channel, double scale) {
+    this(channel, scale, 0);
+  }
+
+  /**
+   * AnalogPotentiometer constructor.
+   *
+   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
+   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
+   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
+   * point after scaling is 135 degrees.
+   *
+   * @param input The {@link AnalogInput} this potentiometer is plugged into.
+   * @param scale The scaling to multiply the voltage by to get a meaningful unit.
+   */
+  public AnalogPotentiometer(final AnalogInput input, double scale) {
+    this(input, scale, 0);
+  }
+
+  /**
+   * AnalogPotentiometer constructor.
+   *
+   * @param channel The analog channel this potentiometer is plugged into.
+   */
+  public AnalogPotentiometer(final int channel) {
+    this(channel, 1, 0);
+  }
+
+  /**
+   * AnalogPotentiometer constructor.
+   *
+   * @param input The {@link AnalogInput} this potentiometer is plugged into.
+   */
+  public AnalogPotentiometer(final AnalogInput input) {
+    this(input, 1, 0);
+  }
+
+  /**
+   * Get the current reading of the potentiometer.
+   *
+   * @return The current position of the potentiometer.
+   */
+  @Override
+  public double get() {
+    if (m_analogInput == null) {
+      return m_offset;
+    }
+    return (m_analogInput.getVoltage() / RobotController.getVoltage5V()) * m_fullRange + m_offset;
+  }
+
+  @Override
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    if (!pidSource.equals(PIDSourceType.kDisplacement)) {
+      throw new IllegalArgumentException("Only displacement PID is allowed for potentiometers.");
+    }
+    m_pidSource = pidSource;
+  }
+
+  @Override
+  public PIDSourceType getPIDSourceType() {
+    return m_pidSource;
+  }
+
+  /**
+   * Implement the PIDSource interface.
+   *
+   * @return The current reading.
+   */
+  @Override
+  public double pidGet() {
+    return get();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    if (m_analogInput != null) {
+      m_analogInput.initSendable(builder);
+    }
+  }
+
+  /**
+   * Frees this resource.
+   */
+  @Override
+  public void free() {
+    super.free();
+    if (m_initAnalogInput) {
+      m_analogInput.free();
+      m_analogInput = null;
+      m_initAnalogInput = false;
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTrigger.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTrigger.java
new file mode 100644
index 0000000..f7f7c1e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTrigger.java
@@ -0,0 +1,186 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
+import edu.wpi.first.wpilibj.hal.AnalogJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+import edu.wpi.first.wpilibj.util.BoundaryException;
+
+/**
+ * Class for creating and configuring Analog Triggers.
+ */
+public class AnalogTrigger extends SensorBase implements Sendable {
+  /**
+   * Exceptions dealing with improper operation of the Analog trigger.
+   */
+  public class AnalogTriggerException extends RuntimeException {
+    /**
+     * Create a new exception with the given message.
+     *
+     * @param message the message to pass with the exception
+     */
+    public AnalogTriggerException(String message) {
+      super(message);
+    }
+
+  }
+
+  /**
+   * Where the analog trigger is attached.
+   */
+  protected int m_port;
+  protected int m_index;
+  protected AnalogInput m_analogInput = null;
+  protected boolean m_ownsAnalog = false;
+
+  /**
+   * Constructor for an analog trigger given a channel number.
+   *
+   * @param channel the port to use for the analog trigger
+   */
+  public AnalogTrigger(final int channel) {
+    this(new AnalogInput(channel));
+    m_ownsAnalog = true;
+    addChild(m_analogInput);
+  }
+
+  /**
+   * Construct an analog trigger given an analog channel. This should be used in the case of sharing
+   * an analog channel between the trigger and an analog input object.
+   *
+   * @param channel the AnalogInput to use for the analog trigger
+   */
+  public AnalogTrigger(AnalogInput channel) {
+    m_analogInput = channel;
+    ByteBuffer index = ByteBuffer.allocateDirect(4);
+    index.order(ByteOrder.LITTLE_ENDIAN);
+
+    m_port =
+        AnalogJNI.initializeAnalogTrigger(channel.m_port, index.asIntBuffer());
+    m_index = index.asIntBuffer().get(0);
+
+    HAL.report(tResourceType.kResourceType_AnalogTrigger, channel.getChannel());
+    setName("AnalogTrigger", channel.getChannel());
+  }
+
+  /**
+   * Release the resources used by this object.
+   */
+  @Override
+  public void free() {
+    super.free();
+    AnalogJNI.cleanAnalogTrigger(m_port);
+    m_port = 0;
+    if (m_ownsAnalog && m_analogInput != null) {
+      m_analogInput.free();
+    }
+  }
+
+  /**
+   * Set the upper and lower limits of the analog trigger. The limits are given in ADC codes. If
+   * oversampling is used, the units must be scaled appropriately.
+   *
+   * @param lower the lower raw limit
+   * @param upper the upper raw limit
+   */
+  public void setLimitsRaw(final int lower, final int upper) {
+    if (lower > upper) {
+      throw new BoundaryException("Lower bound is greater than upper");
+    }
+    AnalogJNI.setAnalogTriggerLimitsRaw(m_port, lower, upper);
+  }
+
+  /**
+   * Set the upper and lower limits of the analog trigger. The limits are given as floating point
+   * voltage values.
+   *
+   * @param lower the lower voltage limit
+   * @param upper the upper voltage limit
+   */
+  public void setLimitsVoltage(double lower, double upper) {
+    if (lower > upper) {
+      throw new BoundaryException("Lower bound is greater than upper bound");
+    }
+    AnalogJNI.setAnalogTriggerLimitsVoltage(m_port, lower, upper);
+  }
+
+  /**
+   * Configure 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 useAveragedValue true to use an averaged value, false otherwise
+   */
+  public void setAveraged(boolean useAveragedValue) {
+    AnalogJNI.setAnalogTriggerAveraged(m_port, useAveragedValue);
+  }
+
+  /**
+   * Configure 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 useFilteredValue true to use a filtered value, false otherwise
+   */
+  public void setFiltered(boolean useFilteredValue) {
+    AnalogJNI.setAnalogTriggerFiltered(m_port, useFilteredValue);
+  }
+
+  /**
+   * Return the index of the analog trigger. This is the FPGA index of this analog trigger
+   * instance.
+   *
+   * @return The index of the analog trigger.
+   */
+  public int getIndex() {
+    return m_index;
+  }
+
+  /**
+   * Return the InWindow output of the analog trigger. True if the analog input is between the upper
+   * and lower limits.
+   *
+   * @return The InWindow output of the analog trigger.
+   */
+  public boolean getInWindow() {
+    return AnalogJNI.getAnalogTriggerInWindow(m_port);
+  }
+
+  /**
+   * Return the TriggerState output of the analog trigger. True if above upper limit. False if below
+   * lower limit. If in Hysteresis, maintain previous state.
+   *
+   * @return The TriggerState output of the analog trigger.
+   */
+  public boolean getTriggerState() {
+    return AnalogJNI.getAnalogTriggerTriggerState(m_port);
+  }
+
+  /**
+   * Creates an AnalogTriggerOutput object. Gets an output object that can be used for routing.
+   * Caller is responsible for deleting the AnalogTriggerOutput object.
+   *
+   * @param type An enum of the type of output object to create.
+   * @return A pointer to a new AnalogTriggerOutput object.
+   */
+  public AnalogTriggerOutput createOutput(AnalogTriggerType type) {
+    return new AnalogTriggerOutput(this, type);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    if (m_ownsAnalog) {
+      m_analogInput.initSendable(builder);
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTriggerOutput.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTriggerOutput.java
new file mode 100644
index 0000000..ade6c9f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTriggerOutput.java
@@ -0,0 +1,128 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.AnalogJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Class to represent a specific output from an analog trigger. This class is used to get the
+ * current output value and also as a DigitalSource to provide routing of an output to digital
+ * subsystems on the FPGA such as Counter, Encoder, and Interrupt.
+ *
+ * <p>The TriggerState output indicates the primary output value of the trigger. If the analog
+ * signal is less than the lower limit, the output is false. If the analog value is greater than the
+ * upper limit, then the output is true. If the analog value is in between, then the trigger output
+ * state maintains its most recent value.
+ *
+ * <p>The InWindow output indicates whether or not the analog signal is inside the range defined by
+ * the limits.
+ *
+ * <p>The RisingPulse and FallingPulse outputs detect an instantaneous transition from above the
+ * upper limit to below the lower limit, and vise versa. These pulses represent a rollover condition
+ * of a sensor and can be routed to an up / down counter or to interrupts. Because the outputs
+ * generate a pulse, they cannot be read directly. To help ensure that a rollover condition is not
+ * missed, there is an average rejection filter available that operates on the upper 8 bits of a 12
+ * bit number and selects the nearest outlier of 3 samples. This will reject a sample that is (due
+ * to averaging or sampling) errantly between the two limits. This filter will fail if more than one
+ * sample in a row is errantly in between the two limits. You may see this problem if attempting to
+ * use this feature with a mechanical rollover sensor, such as a 360 degree no-stop potentiometer
+ * without signal conditioning, because the rollover transition is not sharp / clean enough. Using
+ * the averaging engine may help with this, but rotational speeds of the sensor will then be
+ * limited.
+ */
+public class AnalogTriggerOutput extends DigitalSource {
+  /**
+   * Exceptions dealing with improper operation of the Analog trigger output.
+   */
+  public class AnalogTriggerOutputException extends RuntimeException {
+    /**
+     * Create a new exception with the given message.
+     *
+     * @param message the message to pass with the exception
+     */
+    public AnalogTriggerOutputException(String message) {
+      super(message);
+    }
+  }
+
+  private final AnalogTrigger m_trigger;
+  private final AnalogTriggerType m_outputType;
+
+  /**
+   * Create an object that represents one of the four outputs from an analog trigger.
+   *
+   * <p>Because this class derives from DigitalSource, it can be passed into routing functions for
+   * Counter, Encoder, etc.
+   *
+   * @param trigger    The trigger for which this is an output.
+   * @param outputType An enum that specifies the output on the trigger to represent.
+   */
+  public AnalogTriggerOutput(AnalogTrigger trigger, final AnalogTriggerType outputType) {
+    requireNonNull(trigger, "Analog Trigger given was null");
+    requireNonNull(outputType, "Analog Trigger Type given was null");
+
+    m_trigger = trigger;
+    m_outputType = outputType;
+    HAL.report(tResourceType.kResourceType_AnalogTriggerOutput,
+        trigger.getIndex(), outputType.value);
+  }
+
+  /**
+   * Get the state of the analog trigger output.
+   *
+   * @return The state of the analog trigger output.
+   */
+  public boolean get() {
+    return AnalogJNI.getAnalogTriggerOutput(m_trigger.m_port, m_outputType.value);
+  }
+
+  @Override
+  public int getPortHandleForRouting() {
+    return m_trigger.m_port;
+  }
+
+  @Override
+  public int getAnalogTriggerTypeForRouting() {
+    return m_outputType.value;
+  }
+
+  @Override
+  public int getChannel() {
+    return m_trigger.m_index;
+  }
+
+  @Override
+  public boolean isAnalogTrigger() {
+    return true;
+  }
+
+  /**
+   * Defines the state in which the AnalogTrigger triggers.
+   */
+  public enum AnalogTriggerType {
+    kInWindow(AnalogJNI.AnalogTriggerType.kInWindow), kState(AnalogJNI.AnalogTriggerType.kState),
+    kRisingPulse(AnalogJNI.AnalogTriggerType.kRisingPulse),
+    kFallingPulse(AnalogJNI.AnalogTriggerType.kFallingPulse);
+
+    @SuppressWarnings("MemberName")
+    private final int value;
+
+    AnalogTriggerType(int value) {
+      this.value = value;
+    }
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/BuiltInAccelerometer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/BuiltInAccelerometer.java
new file mode 100644
index 0000000..ec46b9a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/BuiltInAccelerometer.java
@@ -0,0 +1,100 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2014-2018 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.AccelerometerJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.interfaces.Accelerometer;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Built-in accelerometer.
+ *
+ * <p>This class allows access to the roboRIO's internal accelerometer.
+ */
+public class BuiltInAccelerometer extends SensorBase implements Accelerometer, Sendable {
+  /**
+   * Constructor.
+   *
+   * @param range The range the accelerometer will measure
+   */
+  public BuiltInAccelerometer(Range range) {
+    setRange(range);
+    HAL.report(tResourceType.kResourceType_Accelerometer, 0, 0, "Built-in accelerometer");
+    setName("BuiltInAccel", 0);
+  }
+
+  /**
+   * Constructor. The accelerometer will measure +/-8 g-forces
+   */
+  public BuiltInAccelerometer() {
+    this(Range.k8G);
+  }
+
+  @Override
+  public void setRange(Range range) {
+    AccelerometerJNI.setAccelerometerActive(false);
+
+    switch (range) {
+      case k2G:
+        AccelerometerJNI.setAccelerometerRange(0);
+        break;
+      case k4G:
+        AccelerometerJNI.setAccelerometerRange(1);
+        break;
+      case k8G:
+        AccelerometerJNI.setAccelerometerRange(2);
+        break;
+      case k16G:
+      default:
+        throw new IllegalArgumentException(range + " range not supported (use k2G, k4G, or k8G)");
+
+    }
+
+    AccelerometerJNI.setAccelerometerActive(true);
+  }
+
+  /**
+   * The acceleration in the X axis.
+   *
+   * @return The acceleration of the roboRIO along the X axis in g-forces
+   */
+  @Override
+  public double getX() {
+    return AccelerometerJNI.getAccelerometerX();
+  }
+
+  /**
+   * The acceleration in the Y axis.
+   *
+   * @return The acceleration of the roboRIO along the Y axis in g-forces
+   */
+  @Override
+  public double getY() {
+    return AccelerometerJNI.getAccelerometerY();
+  }
+
+  /**
+   * The acceleration in the Z axis.
+   *
+   * @return The acceleration of the roboRIO along the Z axis in g-forces
+   */
+  @Override
+  public double getZ() {
+    return AccelerometerJNI.getAccelerometerZ();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("3AxisAccelerometer");
+    builder.addDoubleProperty("X", this::getX, null);
+    builder.addDoubleProperty("Y", this::getY, null);
+    builder.addDoubleProperty("Z", this::getZ, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CameraServer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CameraServer.java
new file mode 100644
index 0000000..fc596ee
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CameraServer.java
@@ -0,0 +1,768 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.cscore.AxisCamera;
+import edu.wpi.cscore.CameraServerJNI;
+import edu.wpi.cscore.CvSink;
+import edu.wpi.cscore.CvSource;
+import edu.wpi.cscore.MjpegServer;
+import edu.wpi.cscore.UsbCamera;
+import edu.wpi.cscore.VideoEvent;
+import edu.wpi.cscore.VideoException;
+import edu.wpi.cscore.VideoListener;
+import edu.wpi.cscore.VideoMode;
+import edu.wpi.cscore.VideoMode.PixelFormat;
+import edu.wpi.cscore.VideoProperty;
+import edu.wpi.cscore.VideoSink;
+import edu.wpi.cscore.VideoSource;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.networktables.EntryListenerFlags;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+/**
+ * Singleton class for creating and keeping camera servers.
+ * Also publishes camera information to NetworkTables.
+ */
+public class CameraServer {
+  public static final int kBasePort = 1181;
+
+  @Deprecated
+  public static final int kSize640x480 = 0;
+  @Deprecated
+  public static final int kSize320x240 = 1;
+  @Deprecated
+  public static final int kSize160x120 = 2;
+
+  private static final String kPublishName = "/CameraPublisher";
+  private static CameraServer server;
+
+  /**
+   * Get the CameraServer instance.
+   */
+  public static synchronized CameraServer getInstance() {
+    if (server == null) {
+      server = new CameraServer();
+    }
+    return server;
+  }
+
+  private AtomicInteger m_defaultUsbDevice;
+  private String m_primarySourceName;
+  private final Hashtable<String, VideoSource> m_sources;
+  private final Hashtable<String, VideoSink> m_sinks;
+  private final Hashtable<Integer, NetworkTable> m_tables;  // indexed by source handle
+  private final NetworkTable m_publishTable;
+  private final VideoListener m_videoListener; //NOPMD
+  private final int m_tableListener; //NOPMD
+  private int m_nextPort;
+  private String[] m_addresses;
+
+  @SuppressWarnings("JavadocMethod")
+  private static String makeSourceValue(int source) {
+    switch (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))) {
+      case kUsb:
+        return "usb:" + CameraServerJNI.getUsbCameraPath(source);
+      case kHttp: {
+        String[] urls = CameraServerJNI.getHttpCameraUrls(source);
+        if (urls.length > 0) {
+          return "ip:" + urls[0];
+        } else {
+          return "ip:";
+        }
+      }
+      case kCv:
+        // FIXME: Should be "cv:", but LabVIEW dashboard requires "usb:".
+        // https://github.com/wpilibsuite/allwpilib/issues/407
+        return "usb:";
+      default:
+        return "unknown:";
+    }
+  }
+
+  @SuppressWarnings("JavadocMethod")
+  private static String makeStreamValue(String address, int port) {
+    return "mjpg:http://" + address + ":" + port + "/?action=stream";
+  }
+
+  @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
+  private synchronized String[] getSinkStreamValues(int sink) {
+    // Ignore all but MjpegServer
+    if (VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink)) != VideoSink.Kind.kMjpeg) {
+      return new String[0];
+    }
+
+    // Get port
+    int port = CameraServerJNI.getMjpegServerPort(sink);
+
+    // Generate values
+    ArrayList<String> values = new ArrayList<>(m_addresses.length + 1);
+    String listenAddress = CameraServerJNI.getMjpegServerListenAddress(sink);
+    if (!listenAddress.isEmpty()) {
+      // If a listen address is specified, only use that
+      values.add(makeStreamValue(listenAddress, port));
+    } else {
+      // Otherwise generate for hostname and all interface addresses
+      values.add(makeStreamValue(CameraServerJNI.getHostname() + ".local", port));
+      for (String addr : m_addresses) {
+        if (addr.equals("127.0.0.1")) {
+          continue;  // ignore localhost
+        }
+        values.add(makeStreamValue(addr, port));
+      }
+    }
+
+    return values.toArray(new String[0]);
+  }
+
+  @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
+  private synchronized String[] getSourceStreamValues(int source) {
+    // Ignore all but HttpCamera
+    if (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))
+            != VideoSource.Kind.kHttp) {
+      return new String[0];
+    }
+
+    // Generate values
+    String[] values = CameraServerJNI.getHttpCameraUrls(source);
+    for (int j = 0; j < values.length; j++) {
+      values[j] = "mjpg:" + values[j];
+    }
+
+    // Look to see if we have a passthrough server for this source
+    for (VideoSink i : m_sinks.values()) {
+      int sink = i.getHandle();
+      int sinkSource = CameraServerJNI.getSinkSource(sink);
+      if (source == sinkSource
+          && VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink)) == VideoSink.Kind.kMjpeg) {
+        // Add USB-only passthrough
+        String[] finalValues = new String[values.length + 1];
+        for (int j = 0; j < values.length; j++) {
+          finalValues[j] = values[j];
+        }
+        int port = CameraServerJNI.getMjpegServerPort(sink);
+        finalValues[values.length] = makeStreamValue("172.22.11.2", port);
+        return finalValues;
+      }
+    }
+
+    return values;
+  }
+
+  @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
+  private synchronized void updateStreamValues() {
+    // Over all the sinks...
+    for (VideoSink i : m_sinks.values()) {
+      int sink = i.getHandle();
+
+      // Get the source's subtable (if none exists, we're done)
+      int source = CameraServerJNI.getSinkSource(sink);
+      if (source == 0) {
+        continue;
+      }
+      NetworkTable table = m_tables.get(source);
+      if (table != null) {
+        // Don't set stream values if this is a HttpCamera passthrough
+        if (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))
+            == VideoSource.Kind.kHttp) {
+          continue;
+        }
+
+        // Set table value
+        String[] values = getSinkStreamValues(sink);
+        if (values.length > 0) {
+          table.getEntry("streams").setStringArray(values);
+        }
+      }
+    }
+
+    // Over all the sources...
+    for (VideoSource i : m_sources.values()) {
+      int source = i.getHandle();
+
+      // Get the source's subtable (if none exists, we're done)
+      NetworkTable table = m_tables.get(source);
+      if (table != null) {
+        // Set table value
+        String[] values = getSourceStreamValues(source);
+        if (values.length > 0) {
+          table.getEntry("streams").setStringArray(values);
+        }
+      }
+    }
+  }
+
+  @SuppressWarnings("JavadocMethod")
+  private static String pixelFormatToString(PixelFormat pixelFormat) {
+    switch (pixelFormat) {
+      case kMJPEG:
+        return "MJPEG";
+      case kYUYV:
+        return "YUYV";
+      case kRGB565:
+        return "RGB565";
+      case kBGR:
+        return "BGR";
+      case kGray:
+        return "Gray";
+      default:
+        return "Unknown";
+    }
+  }
+
+  /// Provide string description of video mode.
+  /// The returned string is "{width}x{height} {format} {fps} fps".
+  @SuppressWarnings("JavadocMethod")
+  private static String videoModeToString(VideoMode mode) {
+    return mode.width + "x" + mode.height + " " + pixelFormatToString(mode.pixelFormat)
+        + " " + mode.fps + " fps";
+  }
+
+  @SuppressWarnings("JavadocMethod")
+  private static String[] getSourceModeValues(int sourceHandle) {
+    VideoMode[] modes = CameraServerJNI.enumerateSourceVideoModes(sourceHandle);
+    String[] modeStrings = new String[modes.length];
+    for (int i = 0; i < modes.length; i++) {
+      modeStrings[i] = videoModeToString(modes[i]);
+    }
+    return modeStrings;
+  }
+
+  @SuppressWarnings("JavadocMethod")
+  private static void putSourcePropertyValue(NetworkTable table, VideoEvent event, boolean isNew) {
+    String name;
+    String infoName;
+    if (event.name.startsWith("raw_")) {
+      name = "RawProperty/" + event.name;
+      infoName = "RawPropertyInfo/" + event.name;
+    } else {
+      name = "Property/" + event.name;
+      infoName = "PropertyInfo/" + event.name;
+    }
+
+    NetworkTableEntry entry = table.getEntry(name);
+    switch (event.propertyKind) {
+      case kBoolean:
+        if (isNew) {
+          entry.setDefaultBoolean(event.value != 0);
+        } else {
+          entry.setBoolean(event.value != 0);
+        }
+        break;
+      case kInteger:
+      case kEnum:
+        if (isNew) {
+          entry.setDefaultDouble(event.value);
+          table.getEntry(infoName + "/min").setDouble(
+              CameraServerJNI.getPropertyMin(event.propertyHandle));
+          table.getEntry(infoName + "/max").setDouble(
+              CameraServerJNI.getPropertyMax(event.propertyHandle));
+          table.getEntry(infoName + "/step").setDouble(
+              CameraServerJNI.getPropertyStep(event.propertyHandle));
+          table.getEntry(infoName + "/default").setDouble(
+              CameraServerJNI.getPropertyDefault(event.propertyHandle));
+        } else {
+          entry.setDouble(event.value);
+        }
+        break;
+      case kString:
+        if (isNew) {
+          entry.setDefaultString(event.valueStr);
+        } else {
+          entry.setString(event.valueStr);
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  @SuppressWarnings({"JavadocMethod", "PMD.UnusedLocalVariable"})
+  private CameraServer() {
+    m_defaultUsbDevice = new AtomicInteger();
+    m_sources = new Hashtable<>();
+    m_sinks = new Hashtable<>();
+    m_tables = new Hashtable<>();
+    m_publishTable = NetworkTableInstance.getDefault().getTable(kPublishName);
+    m_nextPort = kBasePort;
+    m_addresses = new String[0];
+
+    // We publish sources to NetworkTables using the following structure:
+    // "/CameraPublisher/{Source.Name}/" - root
+    // - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
+    // - "streams" (string array): URLs that can be used to stream data
+    // - "description" (string): Description of the source
+    // - "connected" (boolean): Whether source is connected
+    // - "mode" (string): Current video mode
+    // - "modes" (string array): Available video modes
+    // - "Property/{Property}" - Property values
+    // - "PropertyInfo/{Property}" - Property supporting information
+
+    // Listener for video events
+    m_videoListener = new VideoListener(event -> {
+      switch (event.kind) {
+        case kSourceCreated: {
+          // Create subtable for the camera
+          NetworkTable table = m_publishTable.getSubTable(event.name);
+          m_tables.put(event.sourceHandle, table);
+          table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
+          table.getEntry("description").setString(
+              CameraServerJNI.getSourceDescription(event.sourceHandle));
+          table.getEntry("connected").setBoolean(
+              CameraServerJNI.isSourceConnected(event.sourceHandle));
+          table.getEntry("streams").setStringArray(getSourceStreamValues(event.sourceHandle));
+          try {
+            VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
+            table.getEntry("mode").setDefaultString(videoModeToString(mode));
+            table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
+          } catch (VideoException ex) {
+            // Do nothing. Let the other event handlers update this if there is an error.
+          }
+          break;
+        }
+        case kSourceDestroyed: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            table.getEntry("source").setString("");
+            table.getEntry("streams").setStringArray(new String[0]);
+            table.getEntry("modes").setStringArray(new String[0]);
+          }
+          break;
+        }
+        case kSourceConnected: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            // update the description too (as it may have changed)
+            table.getEntry("description").setString(
+                CameraServerJNI.getSourceDescription(event.sourceHandle));
+            table.getEntry("connected").setBoolean(true);
+          }
+          break;
+        }
+        case kSourceDisconnected: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            table.getEntry("connected").setBoolean(false);
+          }
+          break;
+        }
+        case kSourceVideoModesUpdated: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
+          }
+          break;
+        }
+        case kSourceVideoModeChanged: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            table.getEntry("mode").setString(videoModeToString(event.mode));
+          }
+          break;
+        }
+        case kSourcePropertyCreated: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            putSourcePropertyValue(table, event, true);
+          }
+          break;
+        }
+        case kSourcePropertyValueUpdated: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            putSourcePropertyValue(table, event, false);
+          }
+          break;
+        }
+        case kSourcePropertyChoicesUpdated: {
+          NetworkTable table = m_tables.get(event.sourceHandle);
+          if (table != null) {
+            String[] choices = CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
+            table.getEntry("PropertyInfo/" + event.name + "/choices").setStringArray(choices);
+          }
+          break;
+        }
+        case kSinkSourceChanged:
+        case kSinkCreated:
+        case kSinkDestroyed:
+        case kNetworkInterfacesChanged: {
+          m_addresses = CameraServerJNI.getNetworkInterfaces();
+          updateStreamValues();
+          break;
+        }
+        default:
+          break;
+      }
+    }, 0x4fff, true);
+
+    // Listener for NetworkTable events
+    // We don't currently support changing settings via NT due to
+    // synchronization issues, so just update to current setting if someone
+    // else tries to change it.
+    m_tableListener = NetworkTableInstance.getDefault().addEntryListener(kPublishName + "/",
+      (event) -> {
+        String relativeKey = event.name.substring(kPublishName.length() + 1);
+
+        // get source (sourceName/...)
+        int subKeyIndex = relativeKey.indexOf('/');
+        if (subKeyIndex == -1) {
+          return;
+        }
+        String sourceName = relativeKey.substring(0, subKeyIndex);
+        VideoSource source = m_sources.get(sourceName);
+        if (source == null) {
+          return;
+        }
+
+        // get subkey
+        relativeKey = relativeKey.substring(subKeyIndex + 1);
+
+        // handle standard names
+        String propName;
+        if (relativeKey.equals("mode")) {
+          // reset to current mode
+          event.getEntry().setString(videoModeToString(source.getVideoMode()));
+          return;
+        } else if (relativeKey.startsWith("Property/")) {
+          propName = relativeKey.substring(9);
+        } else if (relativeKey.startsWith("RawProperty/")) {
+          propName = relativeKey.substring(12);
+        } else {
+          return;  // ignore
+        }
+
+        // everything else is a property
+        VideoProperty property = source.getProperty(propName);
+        switch (property.getKind()) {
+          case kNone:
+            return;
+          case kBoolean:
+            // reset to current setting
+            event.getEntry().setBoolean(property.get() != 0);
+            return;
+          case kInteger:
+          case kEnum:
+            // reset to current setting
+            event.getEntry().setDouble(property.get());
+            return;
+          case kString:
+            // reset to current setting
+            event.getEntry().setString(property.getString());
+            return;
+          default:
+            return;
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
+  }
+
+  /**
+   * Start automatically capturing images to send to the dashboard.
+   *
+   * <p>You should call this method to see a camera feed on the dashboard.
+   * If you also want to perform vision processing on the roboRIO, use
+   * getVideo() to get access to the camera images.
+   *
+   * <p>The first time this overload is called, it calls
+   * {@link #startAutomaticCapture(int)} with device 0, creating a camera
+   * named "USB Camera 0".  Subsequent calls increment the device number
+   * (e.g. 1, 2, etc).
+   */
+  public UsbCamera startAutomaticCapture() {
+    UsbCamera camera = startAutomaticCapture(m_defaultUsbDevice.getAndIncrement());
+    HAL.report(tResourceType.kResourceType_PCVideoServer, camera.getHandle());
+    return camera;
+  }
+
+  /**
+   * Start automatically capturing images to send to the dashboard.
+   *
+   * <p>This overload calls {@link #startAutomaticCapture(String, int)} with
+   * a name of "USB Camera {dev}".
+   *
+   * @param dev The device number of the camera interface
+   */
+  public UsbCamera startAutomaticCapture(int dev) {
+    UsbCamera camera = new UsbCamera("USB Camera " + dev, dev);
+    startAutomaticCapture(camera);
+    HAL.report(tResourceType.kResourceType_PCVideoServer, camera.getHandle());
+    return camera;
+  }
+
+  /**
+   * Start automatically capturing images to send to the dashboard.
+   *
+   * @param name The name to give the camera
+   * @param dev The device number of the camera interface
+   */
+  public UsbCamera startAutomaticCapture(String name, int dev) {
+    UsbCamera camera = new UsbCamera(name, dev);
+    startAutomaticCapture(camera);
+    HAL.report(tResourceType.kResourceType_PCVideoServer, camera.getHandle());
+    return camera;
+  }
+
+  /**
+   * Start automatically capturing images to send to the dashboard.
+   *
+   * @param name The name to give the camera
+   * @param path The device path (e.g. "/dev/video0") of the camera
+   */
+  public UsbCamera startAutomaticCapture(String name, String path) {
+    UsbCamera camera = new UsbCamera(name, path);
+    startAutomaticCapture(camera);
+    HAL.report(tResourceType.kResourceType_PCVideoServer, camera.getHandle());
+    return camera;
+  }
+
+  /**
+   * Start automatically capturing images to send to the dashboard from
+   * an existing camera.
+   *
+   * @param camera Camera
+   */
+  public void startAutomaticCapture(VideoSource camera) {
+    addCamera(camera);
+    VideoSink server = addServer("serve_" + camera.getName());
+    server.setSource(camera);
+  }
+
+  /**
+   * Adds an Axis IP camera.
+   *
+   * <p>This overload calls {@link #addAxisCamera(String, String)} with
+   * name "Axis Camera".
+   *
+   * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
+   */
+  public AxisCamera addAxisCamera(String host) {
+    return addAxisCamera("Axis Camera", host);
+  }
+
+  /**
+   * Adds an Axis IP camera.
+   *
+   * <p>This overload calls {@link #addAxisCamera(String, String[])} with
+   * name "Axis Camera".
+   *
+   * @param hosts Array of Camera host IPs/DNS names
+   */
+  public AxisCamera addAxisCamera(String[] hosts) {
+    return addAxisCamera("Axis Camera", hosts);
+  }
+
+  /**
+   * Adds an Axis IP camera.
+   *
+   * @param name The name to give the camera
+   * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
+   */
+  public AxisCamera addAxisCamera(String name, String host) {
+    AxisCamera camera = new AxisCamera(name, host);
+    // Create a passthrough MJPEG server for USB access
+    startAutomaticCapture(camera);
+    HAL.report(tResourceType.kResourceType_AxisCamera, camera.getHandle());
+    return camera;
+  }
+
+  /**
+   * Adds an Axis IP camera.
+   *
+   * @param name The name to give the camera
+   * @param hosts Array of Camera host IPs/DNS names
+   */
+  public AxisCamera addAxisCamera(String name, String[] hosts) {
+    AxisCamera camera = new AxisCamera(name, hosts);
+    // Create a passthrough MJPEG server for USB access
+    startAutomaticCapture(camera);
+    HAL.report(tResourceType.kResourceType_AxisCamera, camera.getHandle());
+    return camera;
+  }
+
+  /**
+   * Get OpenCV access to the primary camera feed.  This allows you to
+   * get images from the camera for image processing on the roboRIO.
+   *
+   * <p>This is only valid to call after a camera feed has been added
+   * with startAutomaticCapture() or addServer().
+   */
+  public CvSink getVideo() {
+    VideoSource source;
+    synchronized (this) {
+      if (m_primarySourceName == null) {
+        throw new VideoException("no camera available");
+      }
+      source = m_sources.get(m_primarySourceName);
+    }
+    if (source == null) {
+      throw new VideoException("no camera available");
+    }
+    return getVideo(source);
+  }
+
+  /**
+   * Get OpenCV access to the specified camera.  This allows you to get
+   * images from the camera for image processing on the roboRIO.
+   *
+   * @param camera Camera (e.g. as returned by startAutomaticCapture).
+   */
+  public CvSink getVideo(VideoSource camera) {
+    String name = "opencv_" + camera.getName();
+
+    synchronized (this) {
+      VideoSink sink = m_sinks.get(name);
+      if (sink != null) {
+        VideoSink.Kind kind = sink.getKind();
+        if (kind != VideoSink.Kind.kCv) {
+          throw new VideoException("expected OpenCV sink, but got " + kind);
+        }
+        return (CvSink) sink;
+      }
+    }
+
+    CvSink newsink = new CvSink(name);
+    newsink.setSource(camera);
+    addServer(newsink);
+    return newsink;
+  }
+
+  /**
+   * Get OpenCV access to the specified camera.  This allows you to get
+   * images from the camera for image processing on the roboRIO.
+   *
+   * @param name Camera name
+   */
+  public CvSink getVideo(String name) {
+    VideoSource source;
+    synchronized (this) {
+      source = m_sources.get(name);
+      if (source == null) {
+        throw new VideoException("could not find camera " + name);
+      }
+    }
+    return getVideo(source);
+  }
+
+  /**
+   * Create a MJPEG stream with OpenCV input. This can be called to pass custom
+   * annotated images to the dashboard.
+   *
+   * @param name Name to give the stream
+   * @param width Width of the image being sent
+   * @param height Height of the image being sent
+   */
+  public CvSource putVideo(String name, int width, int height) {
+    CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, width, height, 30);
+    startAutomaticCapture(source);
+    return source;
+  }
+
+  /**
+   * Adds a MJPEG server at the next available port.
+   *
+   * @param name Server name
+   */
+  public MjpegServer addServer(String name) {
+    int port;
+    synchronized (this) {
+      port = m_nextPort;
+      m_nextPort++;
+    }
+    return addServer(name, port);
+  }
+
+  /**
+   * Adds a MJPEG server.
+   *
+   * @param name Server name
+   */
+  public MjpegServer addServer(String name, int port) {
+    MjpegServer server = new MjpegServer(name, port);
+    addServer(server);
+    return server;
+  }
+
+  /**
+   * Adds an already created server.
+   *
+   * @param server Server
+   */
+  public void addServer(VideoSink server) {
+    synchronized (this) {
+      m_sinks.put(server.getName(), server);
+    }
+  }
+
+  /**
+   * Removes a server by name.
+   *
+   * @param name Server name
+   */
+  public void removeServer(String name) {
+    synchronized (this) {
+      m_sinks.remove(name);
+    }
+  }
+
+  /**
+   * Get server for the primary camera feed.
+   *
+   * <p>This is only valid to call after a camera feed has been added
+   * with startAutomaticCapture() or addServer().
+   */
+  public VideoSink getServer() {
+    synchronized (this) {
+      if (m_primarySourceName == null) {
+        throw new VideoException("no camera available");
+      }
+      return getServer("serve_" + m_primarySourceName);
+    }
+  }
+
+  /**
+   * Gets a server by name.
+   *
+   * @param name Server name
+   */
+  public VideoSink getServer(String name) {
+    synchronized (this) {
+      return m_sinks.get(name);
+    }
+  }
+
+  /**
+   * Adds an already created camera.
+   *
+   * @param camera Camera
+   */
+  public void addCamera(VideoSource camera) {
+    String name = camera.getName();
+    synchronized (this) {
+      if (m_primarySourceName == null) {
+        m_primarySourceName = name;
+      }
+      m_sources.put(name, camera);
+    }
+  }
+
+  /**
+   * Removes a camera by name.
+   *
+   * @param name Camera name
+   */
+  public void removeCamera(String name) {
+    synchronized (this) {
+      m_sources.remove(name);
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CircularBuffer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CircularBuffer.java
new file mode 100644
index 0000000..c7089bb
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CircularBuffer.java
@@ -0,0 +1,186 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+/**
+ * This is a simple circular buffer so we don't need to "bucket brigade" copy old values.
+ */
+public class CircularBuffer {
+  private double[] m_data;
+
+  // Index of element at front of buffer
+  private int m_front = 0;
+
+  // Number of elements used in buffer
+  private int m_length = 0;
+
+  /**
+   * Create a CircularBuffer with the provided size.
+   *
+   * @param size The size of the circular buffer.
+   */
+  public CircularBuffer(int size) {
+    m_data = new double[size];
+    for (int i = 0; i < m_data.length; i++) {
+      m_data[i] = 0.0;
+    }
+  }
+
+  /**
+   * Returns number of elements in buffer.
+   *
+   * @return number of elements in buffer
+   */
+  double size() {
+    return m_length;
+  }
+
+  /**
+   * Get value at front of buffer.
+   *
+   * @return value at front of buffer
+   */
+  double getFirst() {
+    return m_data[m_front];
+  }
+
+  /**
+   * Get value at back of buffer.
+   *
+   * @return value at back of buffer
+   */
+  double getLast() {
+    // If there are no elements in the buffer, do nothing
+    if (m_length == 0) {
+      return 0.0;
+    }
+
+    return m_data[(m_front + m_length - 1) % m_data.length];
+  }
+
+  /**
+   * Push new value onto front of the buffer. The value at the back is overwritten if the buffer is
+   * full.
+   */
+  public void addFirst(double value) {
+    if (m_data.length == 0) {
+      return;
+    }
+
+    m_front = moduloDec(m_front);
+
+    m_data[m_front] = value;
+
+    if (m_length < m_data.length) {
+      m_length++;
+    }
+  }
+
+  /**
+   * Push new value onto back of the buffer. The value at the front is overwritten if the buffer is
+   * full.
+   */
+  public void addLast(double value) {
+    if (m_data.length == 0) {
+      return;
+    }
+
+    m_data[(m_front + m_length) % m_data.length] = value;
+
+    if (m_length < m_data.length) {
+      m_length++;
+    } else {
+      // Increment front if buffer is full to maintain size
+      m_front = moduloInc(m_front);
+    }
+  }
+
+  /**
+   * Pop value at front of buffer.
+   *
+   * @return value at front of buffer
+   */
+  public double removeFirst() {
+    // If there are no elements in the buffer, do nothing
+    if (m_length == 0) {
+      return 0.0;
+    }
+
+    double temp = m_data[m_front];
+    m_front = moduloInc(m_front);
+    m_length--;
+    return temp;
+  }
+
+
+  /**
+   * Pop value at back of buffer.
+   */
+  public double removeLast() {
+    // If there are no elements in the buffer, do nothing
+    if (m_length == 0) {
+      return 0.0;
+    }
+
+    m_length--;
+    return m_data[(m_front + m_length) % m_data.length];
+  }
+
+  /**
+   * Resizes internal buffer to given size.
+   *
+   * <p>A new buffer is allocated because arrays are not resizable.
+   */
+  void resize(int size) {
+    double[] newBuffer = new double[size];
+    m_length = Math.min(m_length, size);
+    for (int i = 0; i < m_length; i++) {
+      newBuffer[i] = m_data[(m_front + i) % m_data.length];
+    }
+    m_data = newBuffer;
+    m_front = 0;
+  }
+
+  /**
+   * Sets internal buffer contents to zero.
+   */
+  public void clear() {
+    for (int i = 0; i < m_data.length; i++) {
+      m_data[i] = 0.0;
+    }
+    m_front = 0;
+    m_length = 0;
+  }
+
+  /**
+   * Get the element at the provided index relative to the start of the buffer.
+   *
+   * @return Element at index starting from front of buffer.
+   */
+  public double get(int index) {
+    return m_data[(m_front + index) % m_data.length];
+  }
+
+  /**
+   * Increment an index modulo the length of the m_data buffer.
+   */
+  private int moduloInc(int index) {
+    return (index + 1) % m_data.length;
+  }
+
+  /**
+   * Decrement an index modulo the length of the m_data buffer.
+   */
+  private int moduloDec(int index) {
+    if (index == 0) {
+      return m_data.length - 1;
+    } else {
+      return index - 1;
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java
new file mode 100644
index 0000000..e0f8c2d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java
@@ -0,0 +1,205 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.CompressorJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Class for operating a compressor connected to a PCM (Pneumatic Control Module). The PCM will
+ * automatically run in closed loop mode by default whenever a {@link Solenoid} object is created.
+ * For most cases, a Compressor object does not need to be instantiated or used in a robot program.
+ * This class is only required in cases where the robot program needs a more detailed status of the
+ * compressor or to enable/disable closed loop control.
+ *
+ * <p>Note: you cannot operate the compressor directly from this class as doing so would circumvent
+ * the safety provided by using the pressure switch and closed loop control. You can only turn off
+ * closed loop control, thereby stopping the compressor from operating.
+ */
+public class Compressor extends SendableBase implements Sendable {
+  private int m_compressorHandle;
+  private byte m_module;
+
+  /**
+   * Makes a new instance of the compressor using the provided CAN device ID.  Use this constructor
+   * when you have more than one PCM.
+   *
+   * @param module The PCM CAN device ID (0 - 62 inclusive)
+   */
+  public Compressor(int module) {
+    m_module = (byte) module;
+
+    m_compressorHandle = CompressorJNI.initializeCompressor((byte) module);
+
+    HAL.report(tResourceType.kResourceType_Compressor, module);
+    setName("Compressor", module);
+  }
+
+  /**
+   * Makes a new instance of the compressor using the default PCM ID of 0.
+   *
+   * <p>Additional modules can be supported by making a new instance and {@link #Compressor(int)
+   * specifying the CAN ID.}
+   */
+  public Compressor() {
+    this(SensorBase.getDefaultSolenoidModule());
+  }
+
+  /**
+   * Start the compressor running in closed loop control mode.
+   *
+   * <p>Use the method in cases where you would like to manually stop and start the compressor for
+   * applications such as conserving battery or making sure that the compressor motor doesn't start
+   * during critical operations.
+   */
+  public void start() {
+    setClosedLoopControl(true);
+  }
+
+  /**
+   * Stop the compressor from running in closed loop control mode.
+   *
+   * <p>Use the method in cases where you would like to manually stop and start the compressor for
+   * applications such as conserving battery or making sure that the compressor motor doesn't start
+   * during critical operations.
+   */
+  public void stop() {
+    setClosedLoopControl(false);
+  }
+
+  /**
+   * Get the status of the compressor.
+   *
+   * @return true if the compressor is on
+   */
+  public boolean enabled() {
+    return CompressorJNI.getCompressor(m_compressorHandle);
+  }
+
+  /**
+   * Get the pressure switch value.
+   *
+   * @return true if the pressure is low
+   */
+  public boolean getPressureSwitchValue() {
+    return CompressorJNI.getCompressorPressureSwitch(m_compressorHandle);
+  }
+
+  /**
+   * Get the current being used by the compressor.
+   *
+   * @return current consumed by the compressor in amps
+   */
+  public double getCompressorCurrent() {
+    return CompressorJNI.getCompressorCurrent(m_compressorHandle);
+  }
+
+  /**
+   * Set the PCM in closed loop control mode.
+   *
+   * @param on if true sets the compressor to be in closed loop control mode (default)
+   */
+  public void setClosedLoopControl(boolean on) {
+    CompressorJNI.setCompressorClosedLoopControl(m_compressorHandle, on);
+  }
+
+  /**
+   * Gets the current operating mode of the PCM.
+   *
+   * @return true if compressor is operating on closed-loop mode
+   */
+  public boolean getClosedLoopControl() {
+    return CompressorJNI.getCompressorClosedLoopControl(m_compressorHandle);
+  }
+
+  /**
+   * If PCM is in fault state : Compressor Drive is disabled due to compressor current being too
+   * high.
+   *
+   * @return true if PCM is in fault state.
+   */
+  public boolean getCompressorCurrentTooHighFault() {
+    return CompressorJNI.getCompressorCurrentTooHighFault(m_compressorHandle);
+  }
+
+  /**
+   * If PCM sticky fault is set : Compressor is disabled due to compressor current being too
+   * high.
+   *
+   * @return true if PCM sticky fault is set.
+   */
+  public boolean getCompressorCurrentTooHighStickyFault() {
+    return CompressorJNI.getCompressorCurrentTooHighStickyFault(m_compressorHandle);
+  }
+
+  /**
+   * If PCM sticky fault is set : Compressor output appears to be shorted.
+   *
+   * @return true if PCM sticky fault is set.
+   */
+  public boolean getCompressorShortedStickyFault() {
+    return CompressorJNI.getCompressorShortedStickyFault(m_compressorHandle);
+  }
+
+  /**
+   * If PCM is in fault state : Compressor output appears to be shorted.
+   *
+   * @return true if PCM is in fault state.
+   */
+  public boolean getCompressorShortedFault() {
+    return CompressorJNI.getCompressorShortedFault(m_compressorHandle);
+  }
+
+  /**
+   * If PCM sticky fault is set : Compressor does not appear to be wired, i.e. compressor is not
+   * drawing enough current.
+   *
+   * @return true if PCM sticky fault is set.
+   */
+  public boolean getCompressorNotConnectedStickyFault() {
+    return CompressorJNI.getCompressorNotConnectedStickyFault(m_compressorHandle);
+  }
+
+  /**
+   * If PCM is in fault state : Compressor does not appear to be wired, i.e. compressor is not
+   * drawing enough current.
+   *
+   * @return true if PCM is in fault state.
+   */
+  public boolean getCompressorNotConnectedFault() {
+    return CompressorJNI.getCompressorNotConnectedFault(m_compressorHandle);
+  }
+
+  /**
+   * Clear ALL sticky faults inside PCM that Compressor is wired to.
+   *
+   * <p>If a sticky fault is set, then it will be persistently cleared. The compressor might
+   * momentarily disable while the flags are being cleared. Doo not call this method too
+   * frequently, otherwise normal compressor functionality may be prevented.
+   *
+   * <p>If no sticky faults are set then this call will have no effect.
+   */
+  public void clearAllPCMStickyFaults() {
+    CompressorJNI.clearAllPCMStickyFaults(m_module);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Compressor");
+    builder.addBooleanProperty("Enabled", this::enabled, (value) -> {
+      if (value) {
+        start();
+      } else {
+        stop();
+      }
+    });
+    builder.addBooleanProperty("Pressure switch", this::getPressureSwitchValue, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Controller.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Controller.java
new file mode 100644
index 0000000..fa2c4dc
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Controller.java
@@ -0,0 +1,25 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * An interface for controllers. Controllers run control loops, the most command are PID controllers
+ * and there variants, but this includes anything that is controlling an actuator in a separate
+ * thread.
+ */
+interface Controller {
+  /**
+   * Allows the control loop to run.
+   */
+  void enable();
+
+  /**
+   * Stops the control loop from running until explicitly re-enabled by calling {@link #enable()}.
+   */
+  void disable();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ControllerPower.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ControllerPower.java
new file mode 100644
index 0000000..fde4ad4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/ControllerPower.java
@@ -0,0 +1,160 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.PowerJNI;
+
+/**
+ * Old Controller PR class.
+ * @deprecated Use RobotController class instead
+ */
+@Deprecated
+public class ControllerPower {
+  /**
+   * Get the input voltage to the robot controller.
+   *
+   * @return The controller input voltage value in Volts
+   */
+  @Deprecated
+  public static double getInputVoltage() {
+    return PowerJNI.getVinVoltage();
+  }
+
+  /**
+   * Get the input current to the robot controller.
+   *
+   * @return The controller input current value in Amps
+   */
+  @Deprecated
+  public static double getInputCurrent() {
+    return PowerJNI.getVinCurrent();
+  }
+
+  /**
+   * Get the voltage of the 3.3V rail.
+   *
+   * @return The controller 3.3V rail voltage value in Volts
+   */
+  @Deprecated
+  public static double getVoltage3V3() {
+    return PowerJNI.getUserVoltage3V3();
+  }
+
+  /**
+   * Get the current output of the 3.3V rail.
+   *
+   * @return The controller 3.3V rail output current value in Volts
+   */
+  @Deprecated
+  public static double getCurrent3V3() {
+    return PowerJNI.getUserCurrent3V3();
+  }
+
+  /**
+   * Get the enabled state of the 3.3V rail. The rail may be disabled due to a controller brownout,
+   * a short circuit on the rail, or controller over-voltage.
+   *
+   * @return The controller 3.3V rail enabled value
+   */
+  @Deprecated
+  public static boolean getEnabled3V3() {
+    return PowerJNI.getUserActive3V3();
+  }
+
+  /**
+   * Get the count of the total current faults on the 3.3V rail since the controller has booted.
+   *
+   * @return The number of faults
+   */
+  @Deprecated
+  public static int getFaultCount3V3() {
+    return PowerJNI.getUserCurrentFaults3V3();
+  }
+
+  /**
+   * Get the voltage of the 5V rail.
+   *
+   * @return The controller 5V rail voltage value in Volts
+   */
+  @Deprecated
+  public static double getVoltage5V() {
+    return PowerJNI.getUserVoltage5V();
+  }
+
+  /**
+   * Get the current output of the 5V rail.
+   *
+   * @return The controller 5V rail output current value in Amps
+   */
+  @Deprecated
+  public static double getCurrent5V() {
+    return PowerJNI.getUserCurrent5V();
+  }
+
+  /**
+   * Get the enabled state of the 5V rail. The rail may be disabled due to a controller brownout, a
+   * short circuit on the rail, or controller over-voltage.
+   *
+   * @return The controller 5V rail enabled value
+   */
+  @Deprecated
+  public static boolean getEnabled5V() {
+    return PowerJNI.getUserActive5V();
+  }
+
+  /**
+   * Get the count of the total current faults on the 5V rail since the controller has booted.
+   *
+   * @return The number of faults
+   */
+  @Deprecated
+  public static int getFaultCount5V() {
+    return PowerJNI.getUserCurrentFaults5V();
+  }
+
+  /**
+   * Get the voltage of the 6V rail.
+   *
+   * @return The controller 6V rail voltage value in Volts
+   */
+  @Deprecated
+  public static double getVoltage6V() {
+    return PowerJNI.getUserVoltage6V();
+  }
+
+  /**
+   * Get the current output of the 6V rail.
+   *
+   * @return The controller 6V rail output current value in Amps
+   */
+  @Deprecated
+  public static double getCurrent6V() {
+    return PowerJNI.getUserCurrent6V();
+  }
+
+  /**
+   * Get the enabled state of the 6V rail. The rail may be disabled due to a controller brownout, a
+   * short circuit on the rail, or controller over-voltage.
+   *
+   * @return The controller 6V rail enabled value
+   */
+  @Deprecated
+  public static boolean getEnabled6V() {
+    return PowerJNI.getUserActive6V();
+  }
+
+  /**
+   * Get the count of the total current faults on the 6V rail since the controller has booted.
+   *
+   * @return The number of faults
+   */
+  @Deprecated
+  public static int getFaultCount6V() {
+    return PowerJNI.getUserCurrentFaults6V();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Counter.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Counter.java
new file mode 100644
index 0000000..e0ae1e4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Counter.java
@@ -0,0 +1,561 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
+import edu.wpi.first.wpilibj.hal.CounterJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Class for counting the number of ticks on a digital input channel.
+ *
+ * <p>This is a general purpose class for counting repetitive events. It can return the number of
+ * counts, the period of the most recent cycle, and detect when the signal being counted has
+ * stopped by supplying a maximum cycle time.
+ *
+ * <p>All counters will immediately start counting - reset() them if you need them to be zeroed
+ * before use.
+ */
+public class Counter extends SensorBase implements CounterBase, Sendable, PIDSource {
+  /**
+   * Mode determines how and what the counter counts.
+   */
+  public enum Mode {
+    /**
+     * mode: two pulse.
+     */
+    kTwoPulse(0),
+    /**
+     * mode: semi period.
+     */
+    kSemiperiod(1),
+    /**
+     * mode: pulse length.
+     */
+    kPulseLength(2),
+    /**
+     * mode: external direction.
+     */
+    kExternalDirection(3);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    Mode(int value) {
+      this.value = value;
+    }
+  }
+
+  protected DigitalSource m_upSource; // /< What makes the counter count up.
+  protected DigitalSource m_downSource; // /< What makes the counter count down.
+  private boolean m_allocatedUpSource;
+  private boolean m_allocatedDownSource;
+  private int m_counter; // /< The FPGA counter object.
+  private int m_index; // /< The index of this counter.
+  private PIDSourceType m_pidSource;
+  private double m_distancePerPulse; // distance of travel for each tick
+
+  /**
+   * Create an instance of a counter with the given mode.
+   */
+  public Counter(final Mode mode) {
+    ByteBuffer index = ByteBuffer.allocateDirect(4);
+    // set the byte order
+    index.order(ByteOrder.LITTLE_ENDIAN);
+    m_counter = CounterJNI.initializeCounter(mode.value, index.asIntBuffer());
+    m_index = index.asIntBuffer().get(0);
+
+    m_allocatedUpSource = false;
+    m_allocatedDownSource = false;
+    m_upSource = null;
+    m_downSource = null;
+
+    setMaxPeriod(.5);
+
+    HAL.report(tResourceType.kResourceType_Counter, m_index, mode.value);
+    setName("Counter", m_index);
+  }
+
+  /**
+   * Create an instance of a counter where no sources are selected. Then they all must be selected
+   * by calling functions to specify the upsource and the downsource independently.
+   *
+   * <p>The counter will start counting immediately.
+   */
+  public Counter() {
+    this(Mode.kTwoPulse);
+  }
+
+  /**
+   * Create an instance of a counter from a Digital Input. This is used if an existing digital input
+   * is to be shared by multiple other objects such as encoders or if the Digital Source is not a
+   * DIO channel (such as an Analog Trigger)
+   *
+   * <p>The counter will start counting immediately.
+   *
+   * @param source the digital source to count
+   */
+  public Counter(DigitalSource source) {
+    this();
+
+    requireNonNull(source, "Digital Source given was null");
+    setUpSource(source);
+  }
+
+  /**
+   * Create an instance of a Counter object. Create an up-Counter instance given a channel.
+   *
+   * <p>The counter will start counting immediately.
+   *
+   * @param channel the DIO channel to use as the up source. 0-9 are on-board, 10-25 are on the MXP
+   */
+  public Counter(int channel) {
+    this();
+    setUpSource(channel);
+  }
+
+  /**
+   * Create an instance of a Counter object. Create an instance of a simple up-Counter given an
+   * analog trigger. Use the trigger state output from the analog trigger.
+   *
+   * <p>The counter will start counting immediately.
+   *
+   * @param encodingType which edges to count
+   * @param upSource     first source to count
+   * @param downSource   second source for direction
+   * @param inverted     true to invert the count
+   */
+  public Counter(EncodingType encodingType, DigitalSource upSource, DigitalSource downSource,
+                 boolean inverted) {
+    this(Mode.kExternalDirection);
+
+    requireNonNull(encodingType, "Encoding type given was null");
+    requireNonNull(upSource, "Up Source given was null");
+    requireNonNull(downSource, "Down Source given was null");
+
+    if (encodingType != EncodingType.k1X && encodingType != EncodingType.k2X) {
+      throw new RuntimeException("Counters only support 1X and 2X quadrature decoding!");
+    }
+
+    setUpSource(upSource);
+    setDownSource(downSource);
+
+    if (encodingType == EncodingType.k1X) {
+      setUpSourceEdge(true, false);
+      CounterJNI.setCounterAverageSize(m_counter, 1);
+    } else {
+      setUpSourceEdge(true, true);
+      CounterJNI.setCounterAverageSize(m_counter, 2);
+    }
+
+    setDownSourceEdge(inverted, true);
+  }
+
+  /**
+   * Create an instance of a Counter object. Create an instance of a simple up-Counter given an
+   * analog trigger. Use the trigger state output from the analog trigger.
+   *
+   * <p>The counter will start counting immediately.
+   *
+   * @param trigger the analog trigger to count
+   */
+  public Counter(AnalogTrigger trigger) {
+    this();
+
+    requireNonNull(trigger, "The Analog Trigger given was null");
+
+    setUpSource(trigger.createOutput(AnalogTriggerType.kState));
+  }
+
+  @Override
+  public void free() {
+    super.free();
+    setUpdateWhenEmpty(true);
+
+    clearUpSource();
+    clearDownSource();
+
+    CounterJNI.freeCounter(m_counter);
+
+    m_upSource = null;
+    m_downSource = null;
+    m_counter = 0;
+  }
+
+  /**
+   * The counter's FPGA index.
+   *
+   * @return the Counter's FPGA index
+   */
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public int getFPGAIndex() {
+    return m_index;
+  }
+
+  /**
+   * Set the upsource for the counter as a digital input channel.
+   *
+   * @param channel the DIO channel to count 0-9 are on-board, 10-25 are on the MXP
+   */
+  public void setUpSource(int channel) {
+    setUpSource(new DigitalInput(channel));
+    m_allocatedUpSource = true;
+    addChild(m_upSource);
+  }
+
+  /**
+   * Set the source object that causes the counter to count up. Set the up counting DigitalSource.
+   *
+   * @param source the digital source to count
+   */
+  public void setUpSource(DigitalSource source) {
+    if (m_upSource != null && m_allocatedUpSource) {
+      m_upSource.free();
+      m_allocatedUpSource = false;
+    }
+    m_upSource = source;
+    CounterJNI.setCounterUpSource(m_counter, source.getPortHandleForRouting(),
+        source.getAnalogTriggerTypeForRouting());
+  }
+
+  /**
+   * Set the up counting source to be an analog trigger.
+   *
+   * @param analogTrigger The analog trigger object that is used for the Up Source
+   * @param triggerType   The analog trigger output that will trigger the counter.
+   */
+  public void setUpSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) {
+    requireNonNull(analogTrigger, "Analog Trigger given was null");
+    requireNonNull(triggerType, "Analog Trigger Type given was null");
+
+    setUpSource(analogTrigger.createOutput(triggerType));
+    m_allocatedUpSource = true;
+  }
+
+  /**
+   * Set the edge sensitivity on an up counting source. Set the up source to either detect rising
+   * edges or falling edges.
+   *
+   * @param risingEdge  true to count rising edge
+   * @param fallingEdge true to count falling edge
+   */
+  public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
+    if (m_upSource == null) {
+      throw new RuntimeException("Up Source must be set before setting the edge!");
+    }
+    CounterJNI.setCounterUpSourceEdge(m_counter, risingEdge, fallingEdge);
+  }
+
+  /**
+   * Disable the up counting source to the counter.
+   */
+  public void clearUpSource() {
+    if (m_upSource != null && m_allocatedUpSource) {
+      m_upSource.free();
+      m_allocatedUpSource = false;
+    }
+    m_upSource = null;
+
+    CounterJNI.clearCounterUpSource(m_counter);
+  }
+
+  /**
+   * Set the down counting source to be a digital input channel.
+   *
+   * @param channel the DIO channel to count 0-9 are on-board, 10-25 are on the MXP
+   */
+  public void setDownSource(int channel) {
+    setDownSource(new DigitalInput(channel));
+    m_allocatedDownSource = true;
+    addChild(m_downSource);
+  }
+
+  /**
+   * Set the source object that causes the counter to count down. Set the down counting
+   * DigitalSource.
+   *
+   * @param source the digital source to count
+   */
+  public void setDownSource(DigitalSource source) {
+    requireNonNull(source, "The Digital Source given was null");
+
+    if (m_downSource != null && m_allocatedDownSource) {
+      m_downSource.free();
+      m_allocatedDownSource = false;
+    }
+    CounterJNI.setCounterDownSource(m_counter, source.getPortHandleForRouting(),
+        source.getAnalogTriggerTypeForRouting());
+    m_downSource = source;
+  }
+
+  /**
+   * Set the down counting source to be an analog trigger.
+   *
+   * @param analogTrigger The analog trigger object that is used for the Down Source
+   * @param triggerType   The analog trigger output that will trigger the counter.
+   */
+  public void setDownSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) {
+    requireNonNull(analogTrigger, "Analog Trigger given was null");
+    requireNonNull(triggerType, "Analog Trigger Type given was null");
+
+    setDownSource(analogTrigger.createOutput(triggerType));
+    m_allocatedDownSource = true;
+  }
+
+  /**
+   * Set the edge sensitivity on a down counting source. Set the down source to either detect rising
+   * edges or falling edges.
+   *
+   * @param risingEdge  true to count the rising edge
+   * @param fallingEdge true to count the falling edge
+   */
+  public void setDownSourceEdge(boolean risingEdge, boolean fallingEdge) {
+    requireNonNull(m_downSource, "Down Source must be set before setting the edge!");
+
+    CounterJNI.setCounterDownSourceEdge(m_counter, risingEdge, fallingEdge);
+  }
+
+  /**
+   * Disable the down counting source to the counter.
+   */
+  public void clearDownSource() {
+    if (m_downSource != null && m_allocatedDownSource) {
+      m_downSource.free();
+      m_allocatedDownSource = false;
+    }
+    m_downSource = null;
+
+    CounterJNI.clearCounterDownSource(m_counter);
+  }
+
+  /**
+   * Set standard up / down counting mode on this counter. Up and down counts are sourced
+   * independently from two inputs.
+   */
+  public void setUpDownCounterMode() {
+    CounterJNI.setCounterUpDownMode(m_counter);
+  }
+
+  /**
+   * Set external direction mode on this counter. Counts are sourced on the Up counter input. The
+   * Down counter input represents the direction to count.
+   */
+  public void setExternalDirectionMode() {
+    CounterJNI.setCounterExternalDirectionMode(m_counter);
+  }
+
+  /**
+   * Set Semi-period mode on this counter. Counts up on both rising and falling edges.
+   *
+   * @param highSemiPeriod true to count up on both rising and falling
+   */
+  public void setSemiPeriodMode(boolean highSemiPeriod) {
+    CounterJNI.setCounterSemiPeriodMode(m_counter, highSemiPeriod);
+  }
+
+  /**
+   * Configure 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 threshold The pulse length beyond which the counter counts the opposite direction. Units
+   *                  are seconds.
+   */
+  public void setPulseLengthMode(double threshold) {
+    CounterJNI.setCounterPulseLengthMode(m_counter, threshold);
+  }
+
+  /**
+   * Read the current counter 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.
+   */
+  @Override
+  public int get() {
+    return CounterJNI.getCounter(m_counter);
+  }
+
+  /**
+   * Read the current scaled counter value. Read the value at this instant, scaled by the distance
+   * per pulse (defaults to 1).
+   *
+   * @return The distance since the last reset
+   */
+  public double getDistance() {
+    return get() * m_distancePerPulse;
+  }
+
+  /**
+   * Reset the Counter to zero. Set the counter value to zero. This doesn't effect the running state
+   * of the counter, just sets the current value to zero.
+   */
+  @Override
+  public void reset() {
+    CounterJNI.resetCounter(m_counter);
+  }
+
+  /**
+   * Set 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 GetStopped method.
+   *
+   * @param maxPeriod The maximum period where the counted device is considered moving in seconds.
+   */
+  @Override
+  public void setMaxPeriod(double maxPeriod) {
+    CounterJNI.setCounterMaxPeriod(m_counter, maxPeriod);
+  }
+
+  /**
+   * Select 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 enabled true to continue updating
+   */
+  public void setUpdateWhenEmpty(boolean enabled) {
+    CounterJNI.setCounterUpdateWhenEmpty(m_counter, enabled);
+  }
+
+  /**
+   * Determine 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.
+   *
+   * @return true if the most recent counter period exceeds the MaxPeriod value set by SetMaxPeriod.
+   */
+  @Override
+  public boolean getStopped() {
+    return CounterJNI.getCounterStopped(m_counter);
+  }
+
+  /**
+   * The last direction the counter value changed.
+   *
+   * @return The last direction the counter value changed.
+   */
+  @Override
+  public boolean getDirection() {
+    return CounterJNI.getCounterDirection(m_counter);
+  }
+
+  /**
+   * Set 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 reverseDirection true if the value counted should be negated.
+   */
+  public void setReverseDirection(boolean reverseDirection) {
+    CounterJNI.setCounterReverseDirection(m_counter, reverseDirection);
+  }
+
+  /**
+   * Get 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.
+   *
+   * @return The period of the last two pulses in units of seconds.
+   */
+  @Override
+  public double getPeriod() {
+    return CounterJNI.getCounterPeriod(m_counter);
+  }
+
+  /**
+   * Get the current rate of the Counter. Read the current rate of the counter accounting for the
+   * distance per pulse value. The default value for distance per pulse (1) yields units of pulses
+   * per second.
+   *
+   * @return The rate in units/sec
+   */
+  public double getRate() {
+    return m_distancePerPulse / getPeriod();
+  }
+
+  /**
+   * 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.
+   */
+  public void setSamplesToAverage(int samplesToAverage) {
+    CounterJNI.setCounterSamplesToAverage(m_counter, samplesToAverage);
+  }
+
+  /**
+   * 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)
+   */
+  public int getSamplesToAverage() {
+    return CounterJNI.getCounterSamplesToAverage(m_counter);
+  }
+
+  /**
+   * Set the distance per pulse for this counter. This sets the multiplier used to determine the
+   * distance driven based on the count value from the encoder. Set this value based on the Pulses
+   * per Revolution and factor in any gearing reductions. This distance can be in any units you
+   * like, linear or angular.
+   *
+   * @param distancePerPulse The scale factor that will be used to convert pulses to useful units.
+   */
+  public void setDistancePerPulse(double distancePerPulse) {
+    m_distancePerPulse = distancePerPulse;
+  }
+
+  /**
+   * Set which parameter of the encoder you are using as a process control variable. The counter
+   * class supports the rate and distance parameters.
+   *
+   * @param pidSource An enum to select the parameter.
+   */
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    requireNonNull(pidSource, "PID Source Parameter given was null");
+    if (pidSource != PIDSourceType.kDisplacement && pidSource != PIDSourceType.kRate) {
+      throw new IllegalArgumentException("PID Source parameter was not valid type: " + pidSource);
+    }
+
+    m_pidSource = pidSource;
+  }
+
+  public PIDSourceType getPIDSourceType() {
+    return m_pidSource;
+  }
+
+  @Override
+  public double pidGet() {
+    switch (m_pidSource) {
+      case kDisplacement:
+        return getDistance();
+      case kRate:
+        return getRate();
+      default:
+        return 0.0;
+    }
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Counter");
+    builder.addDoubleProperty("Value", this::get, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CounterBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CounterBase.java
new file mode 100644
index 0000000..2663fab
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/CounterBase.java
@@ -0,0 +1,84 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * Interface for counting the number of ticks on a digital input channel. Encoders, Gear tooth
+ * sensors, and counters should all subclass this so it can be used to build more advanced classes
+ * for control and driving.
+ *
+ * <p>All counters will immediately start counting - reset() them if you need them to be zeroed
+ * before use.
+ */
+public interface CounterBase {
+
+  /**
+   * The number of edges for the counterbase to increment or decrement on.
+   */
+  enum EncodingType {
+    /**
+     * Count only the rising edge.
+     */
+    k1X(0),
+    /**
+     * Count both the rising and falling edge.
+     */
+    k2X(1),
+    /**
+     * Count rising and falling on both channels.
+     */
+    k4X(2);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    EncodingType(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Get the count.
+   *
+   * @return the count
+   */
+  int get();
+
+  /**
+   * Reset the count to zero.
+   */
+  void reset();
+
+  /**
+   * Get the time between the last two edges counted.
+   *
+   * @return the time between the last two ticks in seconds
+   */
+  double getPeriod();
+
+  /**
+   * Set the maximum time between edges to be considered stalled.
+   *
+   * @param maxPeriod the maximum period in seconds
+   */
+  void setMaxPeriod(double maxPeriod);
+
+  /**
+   * Determine if the counter is not moving.
+   *
+   * @return true if the counter has not changed for the max period
+   */
+  boolean getStopped();
+
+  /**
+   * Determine which direction the counter is going.
+   *
+   * @return true for one direction, false for the other
+   */
+  boolean getDirection();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMC60.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMC60.java
new file mode 100644
index 0000000..95770fc
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMC60.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+//import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+//import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Digilent DMC 60 Speed Controller.
+ */
+public class DMC60 extends PWMSpeedController {
+  /**
+   * Constructor.
+   *
+   * <p>Note that the DMC uses the following bounds for PWM values. These values should work
+   * reasonably well for most controllers, but if users experience issues such as asymmetric
+   * behavior around the deadband or inability to saturate the controller in either direction,
+   * calibration is recommended. The calibration procedure can be found in the DMC 60 User Manual
+   * available from Digilent
+   *
+   * <p>- 2.004ms = full "forward" - 1.52ms = the "high end" of the deadband range - 1.50ms =
+   * center of the deadband range (off) - 1.48ms = the "low end" of the deadband range - .997ms =
+   * full "reverse"
+   *
+   * @param channel The PWM channel that the DMC60 is attached to. 0-9 are
+   *        on-board, 10-19 are on the MXP port
+   */
+  public DMC60(final int channel) {
+    super(channel);
+
+    setBounds(2.004, 1.52, 1.50, 1.48, .997);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    //HAL.report(tResourceType.kResourceType_VictorSP, getChannel());
+    setName("DMC60", getChannel());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalGlitchFilter.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalGlitchFilter.java
new file mode 100644
index 0000000..2082647
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalGlitchFilter.java
@@ -0,0 +1,182 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import edu.wpi.first.wpilibj.hal.DigitalGlitchFilterJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Class to enable glitch filtering on a set of digital inputs. This class will manage adding and
+ * removing digital inputs from a FPGA glitch filter. The filter lets the user configure the time
+ * that an input must remain high or low before it is classified as high or low.
+ */
+public class DigitalGlitchFilter extends SensorBase {
+  /**
+   * Configures the Digital Glitch Filter to its default settings.
+   */
+  public DigitalGlitchFilter() {
+    synchronized (m_mutex) {
+      int index = 0;
+      while (m_filterAllocated[index] && index < m_filterAllocated.length) {
+        index++;
+      }
+      if (index != m_filterAllocated.length) {
+        m_channelIndex = index;
+        m_filterAllocated[index] = true;
+        HAL.report(tResourceType.kResourceType_DigitalFilter,
+            m_channelIndex, 0);
+        setName("DigitalGlitchFilter", index);
+      }
+    }
+  }
+
+  /**
+   * Free the resources used by this object.
+   */
+  public void free() {
+    super.free();
+    if (m_channelIndex >= 0) {
+      synchronized (m_mutex) {
+        m_filterAllocated[m_channelIndex] = false;
+      }
+      m_channelIndex = -1;
+    }
+  }
+
+  private static void setFilter(DigitalSource input, int channelIndex) {
+    if (input != null) { // Counter might have just one input
+      // analog triggers are not supported for DigitalGlitchFilters
+      if (input.isAnalogTrigger()) {
+        throw new IllegalStateException("Analog Triggers not supported for DigitalGlitchFilters");
+      }
+      DigitalGlitchFilterJNI.setFilterSelect(input.getPortHandleForRouting(), channelIndex);
+
+      int selected = DigitalGlitchFilterJNI.getFilterSelect(input.getPortHandleForRouting());
+      if (selected != channelIndex) {
+        throw new IllegalStateException("DigitalGlitchFilterJNI.setFilterSelect("
+            + channelIndex + ") failed -> " + selected);
+      }
+    }
+  }
+
+  /**
+   * Assigns the DigitalSource to this glitch filter.
+   *
+   * @param input The DigitalSource to add.
+   */
+  public void add(DigitalSource input) {
+    setFilter(input, m_channelIndex + 1);
+  }
+
+  /**
+   * Assigns the Encoder to this glitch filter.
+   *
+   * @param input The Encoder to add.
+   */
+  public void add(Encoder input) {
+    add(input.m_aSource);
+    add(input.m_bSource);
+  }
+
+  /**
+   * Assigns the Counter to this glitch filter.
+   *
+   * @param input The Counter to add.
+   */
+  public void add(Counter input) {
+    add(input.m_upSource);
+    add(input.m_downSource);
+  }
+
+  /**
+   * Removes this filter from the given digital input.
+   *
+   * @param input The DigitalSource to stop filtering.
+   */
+  public void remove(DigitalSource input) {
+    setFilter(input, 0);
+  }
+
+  /**
+   * Removes this filter from the given Encoder.
+   *
+   * @param input the Encoder to stop filtering.
+   */
+  public void remove(Encoder input) {
+    remove(input.m_aSource);
+    remove(input.m_bSource);
+  }
+
+  /**
+   * Removes this filter from the given Counter.
+   *
+   * @param input The Counter to stop filtering.
+   */
+  public void remove(Counter input) {
+    remove(input.m_upSource);
+    remove(input.m_downSource);
+  }
+
+  /**
+   * Sets the number of FPGA cycles that the input must hold steady to pass through this glitch
+   * filter.
+   *
+   * @param fpgaCycles The number of FPGA cycles.
+   */
+  public void setPeriodCycles(int fpgaCycles) {
+    DigitalGlitchFilterJNI.setFilterPeriod(m_channelIndex, fpgaCycles);
+  }
+
+  /**
+   * Sets the number of nanoseconds that the input must hold steady to pass through this glitch
+   * filter.
+   *
+   * @param nanoseconds The number of nanoseconds.
+   */
+  public void setPeriodNanoSeconds(long nanoseconds) {
+    int fpgaCycles = (int) (nanoseconds * kSystemClockTicksPerMicrosecond / 4
+        / 1000);
+    setPeriodCycles(fpgaCycles);
+  }
+
+  /**
+   * Gets the number of FPGA cycles that the input must hold steady to pass through this glitch
+   * filter.
+   *
+   * @return The number of cycles.
+   */
+  public int getPeriodCycles() {
+    return DigitalGlitchFilterJNI.getFilterPeriod(m_channelIndex);
+  }
+
+  /**
+   * Gets the number of nanoseconds that the input must hold steady to pass through this glitch
+   * filter.
+   *
+   * @return The number of nanoseconds.
+   */
+  public long getPeriodNanoSeconds() {
+    int fpgaCycles = getPeriodCycles();
+
+    return (long) fpgaCycles * 1000L
+        / (long) (kSystemClockTicksPerMicrosecond / 4);
+  }
+
+  @SuppressWarnings("PMD.UnusedFormalParameter")
+  public void initSendable(SendableBuilder builder) {
+  }
+
+  private int m_channelIndex = -1;
+  private static final Lock m_mutex = new ReentrantLock(true);
+  private static final boolean[] m_filterAllocated = new boolean[3];
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalInput.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalInput.java
new file mode 100644
index 0000000..f7e54b7
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalInput.java
@@ -0,0 +1,107 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.DIOJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Class to read a digital input. This class will read digital inputs and return the current value
+ * on the channel. Other devices such as encoders, gear tooth sensors, etc. that are implemented
+ * elsewhere will automatically allocate digital inputs and outputs as required. This class is only
+ * for devices like switches etc. that aren't implemented anywhere else.
+ */
+public class DigitalInput extends DigitalSource implements Sendable {
+  private int m_channel = 0;
+  private int m_handle = 0;
+
+  /**
+   * Create an instance of a Digital Input class. Creates a digital input given a channel.
+   *
+   * @param channel the DIO channel for the digital input 0-9 are on-board, 10-25 are on the MXP
+   */
+  public DigitalInput(int channel) {
+    checkDigitalChannel(channel);
+    m_channel = channel;
+
+    m_handle = DIOJNI.initializeDIOPort(DIOJNI.getPort((byte) channel), true);
+
+    HAL.report(tResourceType.kResourceType_DigitalInput, channel);
+    setName("DigitalInput", channel);
+  }
+
+  /**
+   * Frees the resources for this output.
+   */
+  public void free() {
+    super.free();
+    if (m_interrupt != 0) {
+      cancelInterrupts();
+    }
+
+    DIOJNI.freeDIOPort(m_handle);
+  }
+
+  /**
+   * Get the value from a digital input channel. Retrieve the value of a single digital input
+   * channel from the FPGA.
+   *
+   * @return the status of the digital input
+   */
+  public boolean get() {
+    return DIOJNI.getDIO(m_handle);
+  }
+
+  /**
+   * Get the channel of the digital input.
+   *
+   * @return The GPIO channel number that this object represents.
+   */
+  @Override
+  public int getChannel() {
+    return m_channel;
+  }
+
+  /**
+   * Get the analog trigger type.
+   *
+   * @return false
+   */
+  @Override
+  public int getAnalogTriggerTypeForRouting() {
+    return 0;
+  }
+
+  /**
+   * Is this an analog trigger.
+   *
+   * @return true if this is an analog trigger
+   */
+  @Override
+  public boolean isAnalogTrigger() {
+    return false;
+  }
+
+  /**
+   * Get the HAL Port Handle.
+   *
+   * @return The HAL Handle to the specified source.
+   */
+  @Override
+  public int getPortHandleForRouting() {
+    return m_handle;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Digital Input");
+    builder.addBooleanProperty("Value", this::get, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java
new file mode 100644
index 0000000..d1ff8f0
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java
@@ -0,0 +1,172 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.DIOJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Class to write digital outputs. This class will write digital outputs. Other devices that are
+ * implemented elsewhere will automatically allocate digital inputs and outputs as required.
+ */
+public class DigitalOutput extends SendableBase implements Sendable {
+  private static final int invalidPwmGenerator = 0;
+  private int m_pwmGenerator = invalidPwmGenerator;
+
+  private int m_channel = 0;
+  private int m_handle = 0;
+
+  /**
+   * Create an instance of a digital output. Create an instance of a digital output given a
+   * channel.
+   *
+   * @param channel the DIO channel to use for the digital output. 0-9 are on-board, 10-25 are on
+   *                the MXP
+   */
+  public DigitalOutput(int channel) {
+    SensorBase.checkDigitalChannel(channel);
+    m_channel = channel;
+
+    m_handle = DIOJNI.initializeDIOPort(DIOJNI.getPort((byte) channel), false);
+
+    HAL.report(tResourceType.kResourceType_DigitalOutput, channel);
+    setName("DigitalOutput", channel);
+  }
+
+  /**
+   * Free the resources associated with a digital output.
+   */
+  @Override
+  public void free() {
+    super.free();
+    // disable the pwm only if we have allocated it
+    if (m_pwmGenerator != invalidPwmGenerator) {
+      disablePWM();
+    }
+    DIOJNI.freeDIOPort(m_handle);
+    m_handle = 0;
+  }
+
+  /**
+   * Set the value of a digital output.
+   *
+   * @param value true is on, off is false
+   */
+  public void set(boolean value) {
+    DIOJNI.setDIO(m_handle, (short) (value ? 1 : 0));
+  }
+
+  /**
+   * Gets the value being output from the Digital Output.
+   *
+   * @return the state of the digital output.
+   */
+  public boolean get() {
+    return DIOJNI.getDIO(m_handle);
+  }
+
+  /**
+   * Get the GPIO channel number that this object represents.
+   *
+   * @return The GPIO channel number.
+   */
+  public int getChannel() {
+    return m_channel;
+  }
+
+  /**
+   * Generate a single pulse. There can only be a single pulse going at any time.
+   *
+   * @param pulseLength The length of the pulse.
+   */
+  public void pulse(final double pulseLength) {
+    DIOJNI.pulse(m_handle, pulseLength);
+  }
+
+  /**
+   * Determine if the pulse is still going. Determine if a previously started pulse is still going.
+   *
+   * @return true if pulsing
+   */
+  public boolean isPulsing() {
+    return DIOJNI.isPulsing(m_handle);
+  }
+
+  /**
+   * Change the PWM frequency of the PWM output on a Digital Output line.
+   *
+   * <p>The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is logarithmic.
+   *
+   * <p>There is only one PWM frequency for all channels.
+   *
+   * @param rate The frequency to output all digital output PWM signals.
+   */
+  public void setPWMRate(double rate) {
+    DIOJNI.setDigitalPWMRate(rate);
+  }
+
+  /**
+   * Enable a PWM Output on this line.
+   *
+   * <p>Allocate one of the 6 DO PWM generator resources.
+   *
+   * <p>Supply the initial duty-cycle to output so as to avoid a glitch when first starting.
+   *
+   * <p>The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less) but is reduced
+   * the higher the frequency of the PWM signal is.
+   *
+   * @param initialDutyCycle The duty-cycle to start generating. [0..1]
+   */
+  public void enablePWM(double initialDutyCycle) {
+    if (m_pwmGenerator != invalidPwmGenerator) {
+      return;
+    }
+    m_pwmGenerator = DIOJNI.allocateDigitalPWM();
+    DIOJNI.setDigitalPWMDutyCycle(m_pwmGenerator, initialDutyCycle);
+    DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, m_channel);
+  }
+
+  /**
+   * Change this line from a PWM output back to a static Digital Output line.
+   *
+   * <p>Free up one of the 6 DO PWM generator resources that were in use.
+   */
+  public void disablePWM() {
+    if (m_pwmGenerator == invalidPwmGenerator) {
+      return;
+    }
+    // Disable the output by routing to a dead bit.
+    DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, SensorBase.kDigitalChannels);
+    DIOJNI.freeDigitalPWM(m_pwmGenerator);
+    m_pwmGenerator = invalidPwmGenerator;
+  }
+
+  /**
+   * Change the duty-cycle that is being generated on the line.
+   *
+   * <p>The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less) but is reduced
+   * the
+   * higher the frequency of the PWM signal is.
+   *
+   * @param dutyCycle The duty-cycle to change to. [0..1]
+   */
+  public void updateDutyCycle(double dutyCycle) {
+    if (m_pwmGenerator == invalidPwmGenerator) {
+      return;
+    }
+    DIOJNI.setDigitalPWMDutyCycle(m_pwmGenerator, dutyCycle);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Digital Output");
+    builder.addBooleanProperty("Value", this::get, this::set);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalSource.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalSource.java
new file mode 100644
index 0000000..d31e191
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalSource.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.wpilibj;
+
+/**
+ * DigitalSource Interface. The DigitalSource represents all the possible inputs for a counter or a
+ * quadrature encoder. The source may be either a digital input or an analog input. If the caller
+ * just provides a channel, then a digital input will be constructed and freed when finished for the
+ * source. The source can either be a digital input or analog trigger but not both.
+ */
+public abstract class DigitalSource extends InterruptableSensorBase {
+  public abstract boolean isAnalogTrigger();
+
+  public abstract int getChannel();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DoubleSolenoid.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DoubleSolenoid.java
new file mode 100644
index 0000000..9542408
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DoubleSolenoid.java
@@ -0,0 +1,183 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.SolenoidJNI;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * DoubleSolenoid class for running 2 channels of high voltage Digital Output on the PCM.
+ *
+ * <p>The DoubleSolenoid class is typically used for pneumatics solenoids that have two positions
+ * controlled by two separate channels.
+ */
+public class DoubleSolenoid extends SolenoidBase implements Sendable {
+  /**
+   * Possible values for a DoubleSolenoid.
+   */
+  public enum Value {
+    kOff,
+    kForward,
+    kReverse
+  }
+
+  private byte m_forwardMask; // The mask for the forward channel.
+  private byte m_reverseMask; // The mask for the reverse channel.
+  private int m_forwardHandle = 0;
+  private int m_reverseHandle = 0;
+
+  /**
+   * Constructor. Uses the default PCM ID (defaults to 0).
+   *
+   * @param forwardChannel The forward channel number on the PCM (0..7).
+   * @param reverseChannel The reverse channel number on the PCM (0..7).
+   */
+  public DoubleSolenoid(final int forwardChannel, final int reverseChannel) {
+    this(SensorBase.getDefaultSolenoidModule(), forwardChannel, reverseChannel);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param moduleNumber   The module number of the solenoid module to use.
+   * @param forwardChannel The forward channel on the module to control (0..7).
+   * @param reverseChannel The reverse channel on the module to control (0..7).
+   */
+  public DoubleSolenoid(final int moduleNumber, final int forwardChannel,
+                        final int reverseChannel) {
+    super(moduleNumber);
+
+    SensorBase.checkSolenoidModule(m_moduleNumber);
+    SensorBase.checkSolenoidChannel(forwardChannel);
+    SensorBase.checkSolenoidChannel(reverseChannel);
+
+    int portHandle = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) forwardChannel);
+    m_forwardHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
+
+    try {
+      portHandle = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) reverseChannel);
+      m_reverseHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
+    } catch (RuntimeException ex) {
+      // free the forward handle on exception, then rethrow
+      SolenoidJNI.freeSolenoidPort(m_forwardHandle);
+      m_forwardHandle = 0;
+      m_reverseHandle = 0;
+      throw ex;
+    }
+
+    m_forwardMask = (byte) (1 << forwardChannel);
+    m_reverseMask = (byte) (1 << reverseChannel);
+
+    HAL.report(tResourceType.kResourceType_Solenoid, forwardChannel,
+                                   m_moduleNumber);
+    HAL.report(tResourceType.kResourceType_Solenoid, reverseChannel,
+                                   m_moduleNumber);
+    setName("DoubleSolenoid", m_moduleNumber, forwardChannel);
+  }
+
+  /**
+   * Destructor.
+   */
+  @Override
+  public synchronized void free() {
+    super.free();
+    SolenoidJNI.freeSolenoidPort(m_forwardHandle);
+    SolenoidJNI.freeSolenoidPort(m_reverseHandle);
+    super.free();
+  }
+
+  /**
+   * Set the value of a solenoid.
+   *
+   * @param value The value to set (Off, Forward, Reverse)
+   */
+  public void set(final Value value) {
+    boolean forward = false;
+    boolean reverse = false;
+
+    switch (value) {
+      case kOff:
+        forward = false;
+        reverse = false;
+        break;
+      case kForward:
+        forward = true;
+        reverse = false;
+        break;
+      case kReverse:
+        forward = false;
+        reverse = true;
+        break;
+      default:
+        throw new AssertionError("Illegal value: " + value);
+
+    }
+
+    SolenoidJNI.setSolenoid(m_forwardHandle, forward);
+    SolenoidJNI.setSolenoid(m_reverseHandle, reverse);
+  }
+
+  /**
+   * Read the current value of the solenoid.
+   *
+   * @return The current value of the solenoid.
+   */
+  public Value get() {
+    boolean valueForward = SolenoidJNI.getSolenoid(m_forwardHandle);
+    boolean valueReverse = SolenoidJNI.getSolenoid(m_reverseHandle);
+
+    if (valueForward) {
+      return Value.kForward;
+    }
+    if (valueReverse) {
+      return Value.kReverse;
+    }
+    return Value.kOff;
+  }
+
+  /**
+   * Check if the forward solenoid is blacklisted. If a solenoid is shorted, it is added to the
+   * blacklist and disabled until power cycle, or until faults are cleared.
+   *
+   * @return If solenoid is disabled due to short.
+   * @see #clearAllPCMStickyFaults()
+   */
+  public boolean isFwdSolenoidBlackListed() {
+    int blackList = getPCMSolenoidBlackList();
+    return (blackList & m_forwardMask) != 0;
+  }
+
+  /**
+   * Check if the reverse solenoid is blacklisted. If a solenoid is shorted, it is added to the
+   * blacklist and disabled until power cycle, or until faults are cleared.
+   *
+   * @return If solenoid is disabled due to short.
+   * @see #clearAllPCMStickyFaults()
+   */
+  public boolean isRevSolenoidBlackListed() {
+    int blackList = getPCMSolenoidBlackList();
+    return (blackList & m_reverseMask) != 0;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Double Solenoid");
+    builder.setSafeState(() -> set(Value.kOff));
+    builder.addStringProperty("Value", () -> get().name().substring(1), (value) -> {
+      if ("Forward".equals(value)) {
+        set(Value.kForward);
+      } else if ("Reverse".equals(value)) {
+        set(Value.kReverse);
+      } else {
+        set(Value.kOff);
+      }
+    });
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DriverStation.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DriverStation.java
new file mode 100644
index 0000000..f6c847d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/DriverStation.java
@@ -0,0 +1,1147 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import edu.wpi.first.wpilibj.hal.AllianceStationID;
+import edu.wpi.first.wpilibj.hal.ControlWord;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.MatchInfoData;
+import edu.wpi.first.wpilibj.hal.PowerJNI;
+
+/**
+ * Provide access to the network communication data to / from the Driver Station.
+ */
+public class DriverStation implements RobotState.Interface {
+  /**
+   * Number of Joystick Ports.
+   */
+  public static final int kJoystickPorts = 6;
+
+  private class HALJoystickButtons {
+    public int m_buttons;
+    public byte m_count;
+  }
+
+  private class HALJoystickAxes {
+    public float[] m_axes;
+    public short m_count;
+
+    HALJoystickAxes(int count) {
+      m_axes = new float[count];
+    }
+  }
+
+  private class HALJoystickPOVs {
+    public short[] m_povs;
+    public short m_count;
+
+    HALJoystickPOVs(int count) {
+      m_povs = new short[count];
+    }
+  }
+
+  /**
+   * The robot alliance that the robot is a part of.
+   */
+  public enum Alliance {
+    Red, Blue, Invalid
+  }
+
+  public enum MatchType {
+    None, Practice, Qualification, Elimination
+  }
+
+  private static final double JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL = 1.0;
+  private double m_nextMessageTime = 0.0;
+
+  private static class DriverStationTask implements Runnable {
+    private DriverStation m_ds;
+
+    DriverStationTask(DriverStation ds) {
+      m_ds = ds;
+    }
+
+    public void run() {
+      m_ds.run();
+    }
+  } /* DriverStationTask */
+
+  private static class MatchDataSender {
+    @SuppressWarnings("MemberName")
+    NetworkTable table;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry typeMetadata;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry gameSpecificMessage;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry eventName;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry matchNumber;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry replayNumber;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry matchType;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry alliance;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry station;
+    @SuppressWarnings("MemberName")
+    NetworkTableEntry controlWord;
+
+    MatchDataSender() {
+      table = NetworkTableInstance.getDefault().getTable("FMSInfo");
+      typeMetadata = table.getEntry(".type");
+      typeMetadata.forceSetString("FMSInfo");
+      gameSpecificMessage = table.getEntry("GameSpecificMessage");
+      gameSpecificMessage.forceSetString("");
+      eventName = table.getEntry("EventName");
+      eventName.forceSetString("");
+      matchNumber = table.getEntry("MatchNumber");
+      matchNumber.forceSetDouble(0);
+      replayNumber = table.getEntry("ReplayNumber");
+      replayNumber.forceSetDouble(0);
+      matchType = table.getEntry("MatchType");
+      matchType.forceSetDouble(0);
+      alliance = table.getEntry("IsRedAlliance");
+      alliance.forceSetBoolean(true);
+      station = table.getEntry("StationNumber");
+      station.forceSetDouble(1);
+      controlWord = table.getEntry("FMSControlData");
+      controlWord.forceSetDouble(0);
+    }
+  }
+
+  private static DriverStation instance = new DriverStation();
+
+  // Joystick User Data
+  private HALJoystickAxes[] m_joystickAxes = new HALJoystickAxes[kJoystickPorts];
+  private HALJoystickPOVs[] m_joystickPOVs = new HALJoystickPOVs[kJoystickPorts];
+  private HALJoystickButtons[] m_joystickButtons = new HALJoystickButtons[kJoystickPorts];
+  private MatchInfoData m_matchInfo = new MatchInfoData();
+
+  // Joystick Cached Data
+  private HALJoystickAxes[] m_joystickAxesCache = new HALJoystickAxes[kJoystickPorts];
+  private HALJoystickPOVs[] m_joystickPOVsCache = new HALJoystickPOVs[kJoystickPorts];
+  private HALJoystickButtons[] m_joystickButtonsCache = new HALJoystickButtons[kJoystickPorts];
+  private MatchInfoData m_matchInfoCache = new MatchInfoData();
+
+  // Joystick button rising/falling edge flags
+  HALJoystickButtons[] m_joystickButtonsPressed = new HALJoystickButtons[kJoystickPorts];
+  HALJoystickButtons[] m_joystickButtonsReleased = new HALJoystickButtons[kJoystickPorts];
+
+  // preallocated byte buffer for button count
+  private ByteBuffer m_buttonCountBuffer = ByteBuffer.allocateDirect(1);
+
+  private MatchDataSender m_matchDataSender;
+
+  // Internal Driver Station thread
+  private Thread m_thread;
+  private volatile boolean m_threadKeepAlive = true;
+
+  private final Object m_cacheDataMutex;
+
+  private final Lock m_waitForDataMutex;
+  private final Condition m_waitForDataCond;
+  private int m_waitForDataCount;
+
+  // Robot state status variables
+  private boolean m_userInDisabled = false;
+  private boolean m_userInAutonomous = false;
+  private boolean m_userInTeleop = false;
+  private boolean m_userInTest = false;
+
+  // Control word variables
+  private final Object m_controlWordMutex;
+  private ControlWord m_controlWordCache;
+  private long m_lastControlWordUpdate;
+
+  /**
+   * Gets an instance of the DriverStation.
+   *
+   * @return The DriverStation.
+   */
+  public static DriverStation getInstance() {
+    return DriverStation.instance;
+  }
+
+  /**
+   * DriverStation constructor.
+   *
+   * <p>The single DriverStation instance is created statically with the instance static member
+   * variable.
+   */
+  private DriverStation() {
+    m_waitForDataCount = 0;
+    m_waitForDataMutex = new ReentrantLock();
+    m_waitForDataCond = m_waitForDataMutex.newCondition();
+
+    m_cacheDataMutex = new Object();
+    for (int i = 0; i < kJoystickPorts; i++) {
+      m_joystickButtons[i] = new HALJoystickButtons();
+      m_joystickAxes[i] = new HALJoystickAxes(HAL.kMaxJoystickAxes);
+      m_joystickPOVs[i] = new HALJoystickPOVs(HAL.kMaxJoystickPOVs);
+
+      m_joystickButtonsCache[i] = new HALJoystickButtons();
+      m_joystickAxesCache[i] = new HALJoystickAxes(HAL.kMaxJoystickAxes);
+      m_joystickPOVsCache[i] = new HALJoystickPOVs(HAL.kMaxJoystickPOVs);
+
+      m_joystickButtonsPressed[i] = new HALJoystickButtons();
+      m_joystickButtonsReleased[i] = new HALJoystickButtons();
+    }
+
+    m_controlWordMutex = new Object();
+    m_controlWordCache = new ControlWord();
+    m_lastControlWordUpdate = 0;
+
+    m_matchDataSender = new MatchDataSender();
+
+    m_thread = new Thread(new DriverStationTask(this), "FRCDriverStation");
+    m_thread.setPriority((Thread.NORM_PRIORITY + Thread.MAX_PRIORITY) / 2);
+
+    m_thread.start();
+  }
+
+  /**
+   * Kill the thread.
+   */
+  public void release() {
+    m_threadKeepAlive = false;
+  }
+
+  /**
+   * Report error to Driver Station. Optionally appends Stack trace
+   * to error message.
+   *
+   * @param printTrace If true, append stack trace to error string
+   */
+  public static void reportError(String error, boolean printTrace) {
+    reportErrorImpl(true, 1, error, printTrace);
+  }
+
+  /**
+   * Report error to Driver Station. Appends provided stack trace
+   * to error message.
+   *
+   * @param stackTrace The stack trace to append
+   */
+  public static void reportError(String error, StackTraceElement[] stackTrace) {
+    reportErrorImpl(true, 1, error, stackTrace);
+  }
+
+  /**
+   * Report warning to Driver Station. Optionally appends Stack
+   * trace to warning message.
+   *
+   * @param printTrace If true, append stack trace to warning string
+   */
+  public static void reportWarning(String error, boolean printTrace) {
+    reportErrorImpl(false, 1, error, printTrace);
+  }
+
+  /**
+   * Report warning to Driver Station. Appends provided stack
+   * trace to warning message.
+   *
+   * @param stackTrace The stack trace to append
+   */
+  public static void reportWarning(String error, StackTraceElement[] stackTrace) {
+    reportErrorImpl(false, 1, error, stackTrace);
+  }
+
+  private static void reportErrorImpl(boolean isError, int code, String error, boolean
+      printTrace) {
+    reportErrorImpl(isError, code, error, printTrace, Thread.currentThread().getStackTrace(), 3);
+  }
+
+  private static void reportErrorImpl(boolean isError, int code, String error,
+      StackTraceElement[] stackTrace) {
+    reportErrorImpl(isError, code, error, true, stackTrace, 0);
+  }
+
+  private static void reportErrorImpl(boolean isError, int code, String error,
+      boolean printTrace, StackTraceElement[] stackTrace, int stackTraceFirst) {
+    String locString;
+    if (stackTrace.length >= stackTraceFirst + 1) {
+      locString = stackTrace[stackTraceFirst].toString();
+    } else {
+      locString = "";
+    }
+    String traceString = "";
+    if (printTrace) {
+      boolean haveLoc = false;
+      for (int i = stackTraceFirst; i < stackTrace.length; i++) {
+        String loc = stackTrace[i].toString();
+        traceString += "\tat " + loc + "\n";
+        // get first user function
+        if (!haveLoc && !loc.startsWith("edu.wpi.first")) {
+          locString = loc;
+          haveLoc = true;
+        }
+      }
+    }
+    HAL.sendError(isError, code, false, error, locString, traceString, true);
+  }
+
+  /**
+   * The state of one joystick button. Button indexes begin at 1.
+   *
+   * @param stick  The joystick to read.
+   * @param button The button index, beginning at 1.
+   * @return The state of the joystick button.
+   */
+  public boolean getStickButton(final int stick, final int button) {
+    if (button <= 0) {
+      reportJoystickUnpluggedError("Button indexes begin at 1 in WPILib for C++ and Java\n");
+      return false;
+    }
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-3");
+    }
+    boolean error = false;
+    boolean retVal = false;
+    synchronized (m_cacheDataMutex) {
+      if (button > m_joystickButtons[stick].m_count) {
+        error = true;
+        retVal = false;
+      } else {
+        retVal = (m_joystickButtons[stick].m_buttons & 1 << (button - 1)) != 0;
+      }
+    }
+    if (error) {
+      reportJoystickUnpluggedWarning("Joystick Button " + button + " on port " + stick
+          + " not available, check if controller is plugged in");
+    }
+    return retVal;
+  }
+
+  /**
+   * Whether one joystick button was pressed since the last check. Button indexes begin at 1.
+   *
+   * @param stick  The joystick to read.
+   * @param button The button index, beginning at 1.
+   * @return Whether the joystick button was pressed since the last check.
+   */
+  boolean getStickButtonPressed(final int stick, final int button) {
+    if (button <= 0) {
+      reportJoystickUnpluggedError("Button indexes begin at 1 in WPILib for C++ and Java\n");
+      return false;
+    }
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-3");
+    }
+
+    // If button was pressed, clear flag and return true
+    if ((m_joystickButtonsPressed[stick].m_buttons & 1 << (button - 1)) != 0) {
+      m_joystickButtonsPressed[stick].m_buttons &= ~(1 << (button - 1));
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Whether one joystick button was released since the last check. Button indexes
+   * begin at 1.
+   *
+   * @param stick  The joystick to read.
+   * @param button The button index, beginning at 1.
+   * @return Whether the joystick button was released since the last check.
+   */
+  boolean getStickButtonReleased(final int stick, final int button) {
+    if (button <= 0) {
+      reportJoystickUnpluggedError("Button indexes begin at 1 in WPILib for C++ and Java\n");
+      return false;
+    }
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-3");
+    }
+
+    // If button was released, clear flag and return true
+    if ((m_joystickButtonsReleased[stick].m_buttons & 1 << (button - 1)) != 0) {
+      m_joystickButtonsReleased[stick].m_buttons &= ~(1 << (button - 1));
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Get the value of the axis on a joystick. This depends on the mapping of the joystick connected
+   * to the specified port.
+   *
+   * @param stick The joystick to read.
+   * @param axis  The analog axis value to read from the joystick.
+   * @return The value of the axis on the joystick.
+   */
+  public double getStickAxis(int stick, int axis) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    if (axis < 0 || axis >= HAL.kMaxJoystickAxes) {
+      throw new RuntimeException("Joystick axis is out of range");
+    }
+
+    boolean error = false;
+    double retVal = 0.0;
+    synchronized (m_cacheDataMutex) {
+      if (axis >= m_joystickAxes[stick].m_count) {
+        // set error
+        error = true;
+        retVal = 0.0;
+      } else {
+        retVal =  m_joystickAxes[stick].m_axes[axis];
+      }
+    }
+    if (error) {
+      reportJoystickUnpluggedWarning("Joystick axis " + axis + " on port " + stick
+          + " not available, check if controller is plugged in");
+    }
+    return retVal;
+  }
+
+  /**
+   * Get the state of a POV on the joystick.
+   *
+   * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
+   */
+  public int getStickPOV(int stick, int pov) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    if (pov < 0 || pov >= HAL.kMaxJoystickPOVs) {
+      throw new RuntimeException("Joystick POV is out of range");
+    }
+    boolean error = false;
+    int retVal = -1;
+    synchronized (m_cacheDataMutex) {
+      if (pov >= m_joystickPOVs[stick].m_count) {
+        error = true;
+        retVal = -1;
+      } else {
+        retVal = m_joystickPOVs[stick].m_povs[pov];
+      }
+    }
+    if (error) {
+      reportJoystickUnpluggedWarning("Joystick POV " + pov + " on port " + stick
+          + " not available, check if controller is plugged in");
+    }
+    return retVal;
+  }
+
+  /**
+   * The state of the buttons on the joystick.
+   *
+   * @param stick The joystick to read.
+   * @return The state of the buttons on the joystick.
+   */
+  public int getStickButtons(final int stick) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-3");
+    }
+    synchronized (m_cacheDataMutex) {
+      return m_joystickButtons[stick].m_buttons;
+    }
+  }
+
+  /**
+   * Returns the number of axes on a given joystick port.
+   *
+   * @param stick The joystick port number
+   * @return The number of axes on the indicated joystick
+   */
+  public int getStickAxisCount(int stick) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    synchronized (m_cacheDataMutex) {
+      return m_joystickAxes[stick].m_count;
+    }
+  }
+
+  /**
+   * Returns the number of POVs on a given joystick port.
+   *
+   * @param stick The joystick port number
+   * @return The number of POVs on the indicated joystick
+   */
+  public int getStickPOVCount(int stick) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    synchronized (m_cacheDataMutex) {
+      return m_joystickPOVs[stick].m_count;
+    }
+  }
+
+  /**
+   * Gets the number of buttons on a joystick.
+   *
+   * @param stick The joystick port number
+   * @return The number of buttons on the indicated joystick
+   */
+  public int getStickButtonCount(int stick) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    synchronized (m_cacheDataMutex) {
+      return m_joystickButtons[stick].m_count;
+    }
+  }
+
+  /**
+   * Gets the value of isXbox on a joystick.
+   *
+   * @param stick The joystick port number
+   * @return A boolean that returns the value of isXbox
+   */
+  public boolean getJoystickIsXbox(int stick) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    boolean error = false;
+    boolean retVal = false;
+    synchronized (m_cacheDataMutex) {
+      // TODO: Remove this when calling for descriptor on empty stick no longer
+      // crashes
+      if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].m_count) {
+        error = true;
+        retVal = false;
+      } else if (HAL.getJoystickIsXbox((byte) stick) == 1) {
+        retVal = true;
+      }
+    }
+    if (error) {
+      reportJoystickUnpluggedWarning("Joystick on port " + stick
+          + " not available, check if controller is plugged in");
+    }
+    return retVal;
+  }
+
+  /**
+   * Gets the value of type on a joystick.
+   *
+   * @param stick The joystick port number
+   * @return The value of type
+   */
+  public int getJoystickType(int stick) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    boolean error = false;
+    int retVal = -1;
+    synchronized (m_cacheDataMutex) {
+      // TODO: Remove this when calling for descriptor on empty stick no longer
+      // crashes
+      if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].m_count) {
+        error = true;
+        retVal = -1;
+      } else {
+        retVal = HAL.getJoystickType((byte) stick);
+      }
+    }
+    if (error) {
+      reportJoystickUnpluggedWarning("Joystick on port " + stick
+          + " not available, check if controller is plugged in");
+    }
+    return retVal;
+  }
+
+  /**
+   * Gets the name of the joystick at a port.
+   *
+   * @param stick The joystick port number
+   * @return The value of name
+   */
+  public String getJoystickName(int stick) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+    boolean error = false;
+    String retVal = "";
+    synchronized (m_cacheDataMutex) {
+      // TODO: Remove this when calling for descriptor on empty stick no longer
+      // crashes
+      if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].m_count) {
+        error = true;
+        retVal = "";
+      } else {
+        retVal = HAL.getJoystickName((byte) stick);
+      }
+    }
+    if (error) {
+      reportJoystickUnpluggedWarning("Joystick on port " + stick
+          + " not available, check if controller is plugged in");
+    }
+    return retVal;
+  }
+
+  /**
+   * Returns the types of Axes on a given joystick port.
+   *
+   * @param stick The joystick port number
+   * @param axis The target axis
+   * @return What type of axis the axis is reporting to be
+   */
+  public int getJoystickAxisType(int stick, int axis) {
+    if (stick < 0 || stick >= kJoystickPorts) {
+      throw new RuntimeException("Joystick index is out of range, should be 0-5");
+    }
+
+    int retVal = -1;
+    synchronized (m_cacheDataMutex) {
+      retVal = HAL.getJoystickAxisType((byte) stick, (byte) axis);
+    }
+    return retVal;
+  }
+
+  /**
+   * Gets a value indicating whether the Driver Station requires the robot to be enabled.
+   *
+   * @return True if the robot is enabled, false otherwise.
+   */
+  public boolean isEnabled() {
+    synchronized (m_controlWordMutex) {
+      updateControlWord(false);
+      return m_controlWordCache.getEnabled() && m_controlWordCache.getDSAttached();
+    }
+  }
+
+  /**
+   * Gets a value indicating whether the Driver Station requires the robot to be disabled.
+   *
+   * @return True if the robot should be disabled, false otherwise.
+   */
+  public boolean isDisabled() {
+    return !isEnabled();
+  }
+
+  /**
+   * Gets a value indicating whether the Driver Station requires the robot to be running in
+   * autonomous mode.
+   *
+   * @return True if autonomous mode should be enabled, false otherwise.
+   */
+  public boolean isAutonomous() {
+    synchronized (m_controlWordMutex) {
+      updateControlWord(false);
+      return m_controlWordCache.getAutonomous();
+    }
+  }
+
+  /**
+   * Gets a value indicating whether the Driver Station requires the robot to be running in
+   * operator-controlled mode.
+   *
+   * @return True if operator-controlled mode should be enabled, false otherwise.
+   */
+  public boolean isOperatorControl() {
+    return !(isAutonomous() || isTest());
+  }
+
+  /**
+   * Gets a value indicating whether the Driver Station requires the robot to be running in test
+   * mode.
+   *
+   * @return True if test mode should be enabled, false otherwise.
+   */
+  public boolean isTest() {
+    synchronized (m_controlWordMutex) {
+      updateControlWord(false);
+      return m_controlWordCache.getTest();
+    }
+  }
+
+  /**
+   * Gets a value indicating whether the Driver Station is attached.
+   *
+   * @return True if Driver Station is attached, false otherwise.
+   */
+  public boolean isDSAttached() {
+    synchronized (m_controlWordMutex) {
+      updateControlWord(false);
+      return m_controlWordCache.getDSAttached();
+    }
+  }
+
+  /**
+   * Gets if 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.
+   */
+  public boolean isNewControlData() {
+    return HAL.isNewControlData();
+  }
+
+  /**
+   * Gets if the driver station attached to a Field Management System.
+   *
+   * @return true if the robot is competing on a field being controlled by a Field Management System
+   */
+  public boolean isFMSAttached() {
+    synchronized (m_controlWordMutex) {
+      updateControlWord(false);
+      return m_controlWordCache.getFMSAttached();
+    }
+  }
+
+  /**
+   * Gets a value indicating whether the FPGA outputs are enabled. The outputs may be disabled if
+   * the robot is disabled or e-stopped, the watchdog has expired, or if the roboRIO browns out.
+   *
+   * @return True if the FPGA outputs are enabled.
+   * @deprecated Use RobotController.isSysActive()
+   */
+  @Deprecated
+  public boolean isSysActive() {
+    return HAL.getSystemActive();
+  }
+
+  /**
+   * Check if the system is browned out.
+   *
+   * @return True if the system is browned out
+   * @deprecated Use RobotController.isBrownedOut()
+   */
+  @Deprecated
+  public boolean isBrownedOut() {
+    return HAL.getBrownedOut();
+  }
+
+  /**
+   * Get the game specific message.
+   *
+   * @return the game specific message
+   */
+  public String getGameSpecificMessage() {
+    synchronized (m_cacheDataMutex) {
+      return m_matchInfo.gameSpecificMessage;
+    }
+  }
+
+  /**
+   * Get the event name.
+   *
+   * @return the event name
+   */
+  public String getEventName() {
+    synchronized (m_cacheDataMutex) {
+      return m_matchInfo.eventName;
+    }
+  }
+
+  /**
+   * Get the match type.
+   *
+   * @return the match type
+   */
+  public MatchType getMatchType() {
+    int matchType;
+    synchronized (m_cacheDataMutex) {
+      matchType = m_matchInfo.matchType;
+    }
+    switch (matchType) {
+      case 1:
+        return MatchType.Practice;
+      case 2:
+        return MatchType.Qualification;
+      case 3:
+        return MatchType.Elimination;
+      default:
+        return MatchType.None;
+    }
+  }
+
+  /**
+   * Get the match number.
+   *
+   * @return the match number
+   */
+  public int getMatchNumber() {
+    synchronized (m_cacheDataMutex) {
+      return m_matchInfo.matchNumber;
+    }
+  }
+
+  /**
+   * Get the replay number.
+   *
+   * @return the replay number
+   */
+  public int getReplayNumber() {
+    synchronized (m_cacheDataMutex) {
+      return m_matchInfo.replayNumber;
+    }
+  }
+
+  /**
+   * Get the current alliance from the FMS.
+   *
+   * @return the current alliance
+   */
+  public Alliance getAlliance() {
+    AllianceStationID allianceStationID = HAL.getAllianceStation();
+    if (allianceStationID == null) {
+      return Alliance.Invalid;
+    }
+
+    switch (allianceStationID) {
+      case Red1:
+      case Red2:
+      case Red3:
+        return Alliance.Red;
+
+      case Blue1:
+      case Blue2:
+      case Blue3:
+        return Alliance.Blue;
+
+      default:
+        return Alliance.Invalid;
+    }
+  }
+
+  /**
+   * Gets the location of the team's driver station controls.
+   *
+   * @return the location of the team's driver station controls: 1, 2, or 3
+   */
+  public int getLocation() {
+    AllianceStationID allianceStationID = HAL.getAllianceStation();
+    if (allianceStationID == null) {
+      return 0;
+    }
+    switch (allianceStationID) {
+      case Red1:
+      case Blue1:
+        return 1;
+
+      case Red2:
+      case Blue2:
+        return 2;
+
+      case Blue3:
+      case Red3:
+        return 3;
+
+      default:
+        return 0;
+    }
+  }
+
+  /**
+   * Wait for new data from the driver station.
+   */
+  public void waitForData() {
+    waitForData(0);
+  }
+
+  /**
+   * Wait for new data or for timeout, which ever comes first. If timeout is 0, wait for new data
+   * only.
+   *
+   * @param timeout The maximum time in seconds to wait.
+   * @return true if there is new data, otherwise false
+   */
+  public boolean waitForData(double timeout) {
+    long startTime = RobotController.getFPGATime();
+    long timeoutMicros = (long) (timeout * 1000000);
+    m_waitForDataMutex.lock();
+    try {
+      int currentCount = m_waitForDataCount;
+      while (m_waitForDataCount == currentCount) {
+        if (timeout > 0) {
+          long now = RobotController.getFPGATime();
+          if (now < startTime + timeoutMicros) {
+            // We still have time to wait
+            boolean signaled = m_waitForDataCond.await(startTime + timeoutMicros - now,
+                                                TimeUnit.MICROSECONDS);
+            if (!signaled) {
+              // Return false if a timeout happened
+              return false;
+            }
+          } else {
+            // Time has elapsed.
+            return false;
+          }
+        } else {
+          m_waitForDataCond.await();
+        }
+      }
+      // Return true if we have received a proper signal
+      return true;
+    } catch (InterruptedException ex) {
+      // return false on a thread interrupt
+      return false;
+    } finally {
+      m_waitForDataMutex.unlock();
+    }
+  }
+
+  /**
+   * Return 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.
+   *
+   * @return Time remaining in current match period (auto or teleop) in seconds
+   */
+  public double getMatchTime() {
+    return HAL.getMatchTime();
+  }
+
+  /**
+   * Read the battery voltage.
+   *
+   * @return The battery voltage in Volts.
+   * @deprecated Use RobotController.getBatteryVoltage
+   */
+  @Deprecated
+  public double getBatteryVoltage() {
+    return PowerJNI.getVinVoltage();
+  }
+
+  /**
+   * Only to be used to tell the Driver Station what code you claim to be executing for diagnostic
+   * purposes only.
+   *
+   * @param entering If true, starting disabled code; if false, leaving disabled code
+   */
+  @SuppressWarnings("MethodName")
+  public void InDisabled(boolean entering) {
+    m_userInDisabled = entering;
+  }
+
+  /**
+   * Only to be used to tell the Driver Station what code you claim to be executing for diagnostic
+   * purposes only.
+   *
+   * @param entering If true, starting autonomous code; if false, leaving autonomous code
+   */
+  @SuppressWarnings("MethodName")
+  public void InAutonomous(boolean entering) {
+    m_userInAutonomous = entering;
+  }
+
+  /**
+   * Only to be used to tell the Driver Station what code you claim to be executing for diagnostic
+   * purposes only.
+   *
+   * @param entering If true, starting teleop code; if false, leaving teleop code
+   */
+  @SuppressWarnings("MethodName")
+  public void InOperatorControl(boolean entering) {
+    m_userInTeleop = entering;
+  }
+
+  /**
+   * Only to be used to tell the Driver Station what code you claim to be executing for diagnostic
+   * purposes only.
+   *
+   * @param entering If true, starting test code; if false, leaving test code
+   */
+  @SuppressWarnings("MethodName")
+  public void InTest(boolean entering) {
+    m_userInTest = entering;
+  }
+
+  private void sendMatchData() {
+    AllianceStationID alliance = HAL.getAllianceStation();
+    boolean isRedAlliance = false;
+    int stationNumber = 1;
+    switch (alliance) {
+      case Blue1:
+        isRedAlliance = false;
+        stationNumber = 1;
+        break;
+      case Blue2:
+        isRedAlliance = false;
+        stationNumber = 2;
+        break;
+      case Blue3:
+        isRedAlliance = false;
+        stationNumber = 3;
+        break;
+      case Red1:
+        isRedAlliance = true;
+        stationNumber = 1;
+        break;
+      case Red2:
+        isRedAlliance = true;
+        stationNumber = 2;
+        break;
+      default:
+        isRedAlliance = true;
+        stationNumber = 3;
+        break;
+    }
+
+
+    String eventName;
+    String gameSpecificMessage;
+    int matchNumber;
+    int replayNumber;
+    int matchType;
+    synchronized (m_cacheDataMutex) {
+      eventName = m_matchInfo.eventName;
+      gameSpecificMessage = m_matchInfo.gameSpecificMessage;
+      matchNumber = m_matchInfo.matchNumber;
+      replayNumber = m_matchInfo.replayNumber;
+      matchType = m_matchInfo.matchType;
+    }
+
+    m_matchDataSender.alliance.setBoolean(isRedAlliance);
+    m_matchDataSender.station.setDouble(stationNumber);
+    m_matchDataSender.eventName.setString(eventName);
+    m_matchDataSender.gameSpecificMessage.setString(gameSpecificMessage);
+    m_matchDataSender.matchNumber.setDouble(matchNumber);
+    m_matchDataSender.replayNumber.setDouble(replayNumber);
+    m_matchDataSender.matchType.setDouble(matchType);
+    m_matchDataSender.controlWord.setDouble(HAL.nativeGetControlWord());
+  }
+
+  /**
+   * Copy data from the DS task for the user. If no new data exists, it will just be returned,
+   * otherwise the data will be copied from the DS polling loop.
+   */
+  protected void getData() {
+    // Get the status of all of the joysticks
+    for (byte stick = 0; stick < kJoystickPorts; stick++) {
+      m_joystickAxesCache[stick].m_count =
+          HAL.getJoystickAxes(stick, m_joystickAxesCache[stick].m_axes);
+      m_joystickPOVsCache[stick].m_count =
+          HAL.getJoystickPOVs(stick, m_joystickPOVsCache[stick].m_povs);
+      m_joystickButtonsCache[stick].m_buttons = HAL.getJoystickButtons(stick, m_buttonCountBuffer);
+      m_joystickButtonsCache[stick].m_count = m_buttonCountBuffer.get(0);
+    }
+
+    HAL.getMatchInfo(m_matchInfoCache);
+
+    // Force a control word update, to make sure the data is the newest.
+    updateControlWord(true);
+
+    // lock joystick mutex to swap cache data
+    synchronized (m_cacheDataMutex) {
+      for (int i = 0; i < kJoystickPorts; i++) {
+        // If buttons weren't pressed and are now, set flags in m_buttonsPressed
+        m_joystickButtonsPressed[i].m_buttons |=
+            ~m_joystickButtons[i].m_buttons & m_joystickButtonsCache[i].m_buttons;
+
+        // If buttons were pressed and aren't now, set flags in m_buttonsReleased
+        m_joystickButtonsReleased[i].m_buttons |=
+            m_joystickButtons[i].m_buttons & ~m_joystickButtonsCache[i].m_buttons;
+      }
+
+      // move cache to actual data
+      HALJoystickAxes[] currentAxes = m_joystickAxes;
+      m_joystickAxes = m_joystickAxesCache;
+      m_joystickAxesCache = currentAxes;
+
+      HALJoystickButtons[] currentButtons = m_joystickButtons;
+      m_joystickButtons = m_joystickButtonsCache;
+      m_joystickButtonsCache = currentButtons;
+
+      HALJoystickPOVs[] currentPOVs = m_joystickPOVs;
+      m_joystickPOVs = m_joystickPOVsCache;
+      m_joystickPOVsCache = currentPOVs;
+
+      MatchInfoData currentInfo = m_matchInfo;
+      m_matchInfo = m_matchInfoCache;
+      m_matchInfoCache = currentInfo;
+    }
+
+    m_waitForDataMutex.lock();
+    m_waitForDataCount++;
+    m_waitForDataCond.signalAll();
+    m_waitForDataMutex.unlock();
+
+    sendMatchData();
+  }
+
+  /**
+   * Reports errors related to unplugged joysticks Throttles the errors so that they don't overwhelm
+   * the DS.
+   */
+  private void reportJoystickUnpluggedError(String message) {
+    double currentTime = Timer.getFPGATimestamp();
+    if (currentTime > m_nextMessageTime) {
+      reportError(message, false);
+      m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
+    }
+  }
+
+  /**
+   * Reports errors related to unplugged joysticks Throttles the errors so that they don't overwhelm
+   * the DS.
+   */
+  private void reportJoystickUnpluggedWarning(String message) {
+    double currentTime = Timer.getFPGATimestamp();
+    if (currentTime > m_nextMessageTime) {
+      reportWarning(message, false);
+      m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
+    }
+  }
+
+  /**
+   * Provides the service routine for the DS polling m_thread.
+   */
+  private void run() {
+    int safetyCounter = 0;
+    while (m_threadKeepAlive) {
+      HAL.waitForDSData();
+      getData();
+
+      if (isDisabled()) {
+        safetyCounter = 0;
+      }
+
+      if (++safetyCounter >= 4) {
+        MotorSafetyHelper.checkMotors();
+        safetyCounter = 0;
+      }
+      if (m_userInDisabled) {
+        HAL.observeUserProgramDisabled();
+      }
+      if (m_userInAutonomous) {
+        HAL.observeUserProgramAutonomous();
+      }
+      if (m_userInTeleop) {
+        HAL.observeUserProgramTeleop();
+      }
+      if (m_userInTest) {
+        HAL.observeUserProgramTest();
+      }
+    }
+  }
+
+  /**
+   * Updates the data in the control word cache. Updates if the force parameter is set, or if
+   * 50ms have passed since the last update.
+   *
+   * @param force True to force an update to the cache, otherwise update if 50ms have passed.
+   */
+  private void updateControlWord(boolean force) {
+    long now = System.currentTimeMillis();
+    synchronized (m_controlWordMutex) {
+      if (now - m_lastControlWordUpdate > 50 || force) {
+        HAL.getControlWord(m_controlWordCache);
+        m_lastControlWordUpdate = now;
+      }
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Encoder.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Encoder.java
new file mode 100644
index 0000000..93d70f1
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Encoder.java
@@ -0,0 +1,570 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.EncoderJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+import edu.wpi.first.wpilibj.util.AllocationException;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Class to read quadrature encoders.
+ *
+ * <p>Quadrature encoders are devices that count shaft rotation and can sense direction. The output
+ * of the Encoder class is an integer that can count either up or down, and can go negative for
+ * reverse direction counting. When creating Encoders, a direction can be supplied that inverts the
+ * sense of the output to make code more readable if the encoder is mounted such that forward
+ * movement generates negative values. Quadrature encoders have two digital outputs, an A Channel
+ * and a B Channel, that are out of phase with each other for direction sensing.
+ *
+ * <p>All encoders will immediately start counting - reset() them if you need them to be zeroed
+ * before use.
+ */
+public class Encoder extends SensorBase implements CounterBase, PIDSource, Sendable {
+  public enum IndexingType {
+    kResetWhileHigh(0), kResetWhileLow(1), kResetOnFallingEdge(2), kResetOnRisingEdge(3);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    IndexingType(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * The a source.
+   */
+  @SuppressWarnings("MemberName")
+  protected DigitalSource m_aSource; // the A phase of the quad encoder
+  /**
+   * The b source.
+   */
+  @SuppressWarnings("MemberName")
+  protected DigitalSource m_bSource; // the B phase of the quad encoder
+  /**
+   * The index source.
+   */
+  protected DigitalSource m_indexSource = null; // Index on some encoders
+  private boolean m_allocatedA;
+  private boolean m_allocatedB;
+  private boolean m_allocatedI;
+  private PIDSourceType m_pidSource;
+
+  private int m_encoder; // the HAL encoder object
+
+
+  /**
+   * Common initialization code for Encoders. This code allocates resources for Encoders and is
+   * common to all constructors.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param reverseDirection If true, counts down instead of up (this is all relative)
+   */
+  private void initEncoder(boolean reverseDirection, final EncodingType type) {
+    m_encoder = EncoderJNI.initializeEncoder(m_aSource.getPortHandleForRouting(),
+        m_aSource.getAnalogTriggerTypeForRouting(), m_bSource.getPortHandleForRouting(),
+        m_bSource.getAnalogTriggerTypeForRouting(), reverseDirection, type.value);
+
+    m_pidSource = PIDSourceType.kDisplacement;
+
+    int fpgaIndex = getFPGAIndex();
+    HAL.report(tResourceType.kResourceType_Encoder, fpgaIndex, type.value);
+    setName("Encoder", fpgaIndex);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param channelA         The a channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
+   * @param channelB         The b channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
+   * @param reverseDirection represents the orientation of the encoder and inverts the output values
+   *                         if necessary so forward represents positive values.
+   */
+  public Encoder(final int channelA, final int channelB, boolean reverseDirection) {
+    this(channelA, channelB, reverseDirection, EncodingType.k4X);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param channelA The a channel digital input channel.
+   * @param channelB The b channel digital input channel.
+   */
+  public Encoder(final int channelA, final int channelB) {
+    this(channelA, channelB, false);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param channelA         The a channel digital input channel.
+   * @param channelB         The b channel digital input channel.
+   * @param reverseDirection represents the orientation of the encoder and inverts the output values
+   *                         if necessary so forward represents positive values.
+   * @param encodingType     either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
+   *                         selected, then an encoder FPGA object is used and the returned counts
+   *                         will be 4x the encoder spec'd value since all rising and falling edges
+   *                         are counted. If 1X or 2X are selected then a m_counter object will be
+   *                         used and the returned value will either exactly match the spec'd count
+   *                         or be double (2x) the spec'd count.
+   */
+  public Encoder(final int channelA, final int channelB, boolean reverseDirection,
+                 final EncodingType encodingType) {
+    requireNonNull(encodingType, "Given encoding type was null");
+
+    m_allocatedA = true;
+    m_allocatedB = true;
+    m_allocatedI = false;
+    m_aSource = new DigitalInput(channelA);
+    m_bSource = new DigitalInput(channelB);
+    addChild(m_aSource);
+    addChild(m_bSource);
+    initEncoder(reverseDirection, encodingType);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels. Using an index pulse forces 4x
+   * encoding
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param channelA         The a channel digital input channel.
+   * @param channelB         The b channel digital input channel.
+   * @param indexChannel     The index channel digital input channel.
+   * @param reverseDirection represents the orientation of the encoder and inverts the output values
+   *                         if necessary so forward represents positive values.
+   */
+  public Encoder(final int channelA, final int channelB, final int indexChannel,
+                 boolean reverseDirection) {
+    this(channelA, channelB, reverseDirection);
+    m_allocatedI = true;
+    m_indexSource = new DigitalInput(indexChannel);
+    addChild(m_indexSource);
+    setIndexSource(m_indexSource);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels. Using an index pulse forces 4x
+   * encoding
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param channelA     The a channel digital input channel.
+   * @param channelB     The b channel digital input channel.
+   * @param indexChannel The index channel digital input channel.
+   */
+  public Encoder(final int channelA, final int channelB, final int indexChannel) {
+    this(channelA, channelB, indexChannel, false);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels as digital inputs. This is used
+   * in the case where the digital inputs are shared. The Encoder class will not allocate the
+   * digital inputs and assume that they already are counted.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param sourceA          The source that should be used for the a channel.
+   * @param sourceB          the source that should be used for the b channel.
+   * @param reverseDirection represents the orientation of the encoder and inverts the output values
+   *                         if necessary so forward represents positive values.
+   */
+  public Encoder(DigitalSource sourceA, DigitalSource sourceB, boolean reverseDirection) {
+    this(sourceA, sourceB, reverseDirection, EncodingType.k4X);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels as digital inputs. This is used
+   * in the case where the digital inputs are shared. The Encoder class will not allocate the
+   * digital inputs and assume that they already are counted.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param sourceA The source that should be used for the a channel.
+   * @param sourceB the source that should be used for the b channel.
+   */
+  public Encoder(DigitalSource sourceA, DigitalSource sourceB) {
+    this(sourceA, sourceB, false);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a and b channels as digital inputs. This is used
+   * in the case where the digital inputs are shared. The Encoder class will not allocate the
+   * digital inputs and assume that they already are counted.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param sourceA          The source that should be used for the a channel.
+   * @param sourceB          the source that should be used for the b channel.
+   * @param reverseDirection represents the orientation of the encoder and inverts the output values
+   *                         if necessary so forward represents positive values.
+   * @param encodingType     either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
+   *                         selected, then an encoder FPGA object is used and the returned counts
+   *                         will be 4x the encoder spec'd value since all rising and falling edges
+   *                         are counted. If 1X or 2X are selected then a m_counter object will be
+   *                         used and the returned value will either exactly match the spec'd count
+   *                         or be double (2x) the spec'd count.
+   */
+  public Encoder(DigitalSource sourceA, DigitalSource sourceB, boolean reverseDirection,
+                 final EncodingType encodingType) {
+    requireNonNull(sourceA, "Digital Source A was null");
+    requireNonNull(sourceB, "Digital Source B was null");
+    requireNonNull(encodingType, "Given encoding type was null");
+
+    m_allocatedA = false;
+    m_allocatedB = false;
+    m_allocatedI = false;
+    m_aSource = sourceA;
+    m_bSource = sourceB;
+    initEncoder(reverseDirection, encodingType);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a, b and index channels as digital inputs. This
+   * is used in the case where the digital inputs are shared. The Encoder class will not allocate
+   * the digital inputs and assume that they already are counted.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param sourceA          The source that should be used for the a channel.
+   * @param sourceB          the source that should be used for the b channel.
+   * @param indexSource      the source that should be used for the index channel.
+   * @param reverseDirection represents the orientation of the encoder and inverts the output values
+   *                         if necessary so forward represents positive values.
+   */
+  public Encoder(DigitalSource sourceA, DigitalSource sourceB, DigitalSource indexSource,
+                 boolean reverseDirection) {
+    this(sourceA, sourceB, reverseDirection);
+    m_allocatedI = false;
+    m_indexSource = indexSource;
+    setIndexSource(indexSource);
+  }
+
+  /**
+   * Encoder constructor. Construct a Encoder given a, b and index channels as digital inputs. This
+   * is used in the case where the digital inputs are shared. The Encoder class will not allocate
+   * the digital inputs and assume that they already are counted.
+   *
+   * <p>The encoder will start counting immediately.
+   *
+   * @param sourceA     The source that should be used for the a channel.
+   * @param sourceB     the source that should be used for the b channel.
+   * @param indexSource the source that should be used for the index channel.
+   */
+  public Encoder(DigitalSource sourceA, DigitalSource sourceB, DigitalSource indexSource) {
+    this(sourceA, sourceB, indexSource, false);
+  }
+
+  /**
+   * Get the FPGA index of the encoder.
+   *
+   * @return The Encoder's FPGA index.
+   */
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public int getFPGAIndex() {
+    return EncoderJNI.getEncoderFPGAIndex(m_encoder);
+  }
+
+  /**
+   * Used to divide raw edge counts down to spec'd counts.
+   *
+   * @return The encoding scale factor 1x, 2x, or 4x, per the requested encoding type.
+   */
+  public int getEncodingScale() {
+    return EncoderJNI.getEncoderEncodingScale(m_encoder);
+  }
+
+  /**
+   * Free the resources used by this object.
+   */
+  @Override
+  public void free() {
+    super.free();
+    if (m_aSource != null && m_allocatedA) {
+      m_aSource.free();
+      m_allocatedA = false;
+    }
+    if (m_bSource != null && m_allocatedB) {
+      m_bSource.free();
+      m_allocatedB = false;
+    }
+    if (m_indexSource != null && m_allocatedI) {
+      m_indexSource.free();
+      m_allocatedI = false;
+    }
+
+    m_aSource = null;
+    m_bSource = null;
+    m_indexSource = null;
+    EncoderJNI.freeEncoder(m_encoder);
+    m_encoder = 0;
+  }
+
+  /**
+   * Gets the raw value from the encoder. The raw value is the actual count unscaled by the 1x, 2x,
+   * or 4x scale factor.
+   *
+   * @return Current raw count from the encoder
+   */
+  public int getRaw() {
+    return EncoderJNI.getEncoderRaw(m_encoder);
+  }
+
+  /**
+   * Gets the current count. Returns the current count on the Encoder. This method compensates for
+   * the decoding type.
+   *
+   * @return Current count from the Encoder adjusted for the 1x, 2x, or 4x scale factor.
+   */
+  public int get() {
+    return EncoderJNI.getEncoder(m_encoder);
+  }
+
+  /**
+   * Reset the Encoder distance to zero. Resets the current count to zero on the encoder.
+   */
+  public void reset() {
+    EncoderJNI.resetEncoder(m_encoder);
+  }
+
+  /**
+   * Returns the period of the most recent pulse. Returns the period of the most recent Encoder
+   * pulse in seconds. This method compensates for the decoding type.
+   *
+   * <p><b>Warning:</b> This returns unscaled periods. Use getRate() for rates that are scaled using
+   * the value from setDistancePerPulse().
+   *
+   * @return Period in seconds of the most recent pulse.
+   * @deprecated Use getRate() in favor of this method.
+   */
+  @Deprecated
+  public double getPeriod() {
+    return EncoderJNI.getEncoderPeriod(m_encoder);
+  }
+
+  /**
+   * 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.
+   *
+   * @param maxPeriod The maximum time between rising and falling edges before the FPGA will report
+   *                  the device stopped. This is expressed in seconds.
+   */
+  public void setMaxPeriod(double maxPeriod) {
+    EncoderJNI.setEncoderMaxPeriod(m_encoder, maxPeriod);
+  }
+
+  /**
+   * 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.
+   */
+  public boolean getStopped() {
+    return EncoderJNI.getEncoderStopped(m_encoder);
+  }
+
+  /**
+   * The last direction the encoder value changed.
+   *
+   * @return The last direction the encoder value changed.
+   */
+  public boolean getDirection() {
+    return EncoderJNI.getEncoderDirection(m_encoder);
+  }
+
+  /**
+   * Get the distance the robot has driven since the last reset as scaled by the value from {@link
+   * #setDistancePerPulse(double)}.
+   *
+   * @return The distance driven since the last reset
+   */
+  public double getDistance() {
+    return EncoderJNI.getEncoderDistance(m_encoder);
+  }
+
+  /**
+   * Get the current rate of the encoder. Units are distance per second as scaled by the value from
+   * setDistancePerPulse().
+   *
+   * @return The current rate of the encoder.
+   */
+  public double getRate() {
+    return EncoderJNI.getEncoderRate(m_encoder);
+  }
+
+  /**
+   * Set the minimum rate of the device before the hardware reports it stopped.
+   *
+   * @param minRate The minimum rate. The units are in distance per second as scaled by the value
+   *                from setDistancePerPulse().
+   */
+  public void setMinRate(double minRate) {
+    EncoderJNI.setEncoderMinRate(m_encoder, minRate);
+  }
+
+  /**
+   * Set the distance per pulse for this encoder. This sets the multiplier used to determine the
+   * distance driven based on the count value from the encoder. Do not include the decoding type in
+   * this scale. The library already compensates for the decoding type. Set this value based on the
+   * encoder's rated Pulses per Revolution and factor in gearing reductions following the encoder
+   * shaft. This distance can be in any units you like, linear or angular.
+   *
+   * @param distancePerPulse The scale factor that will be used to convert pulses to useful units.
+   */
+  public void setDistancePerPulse(double distancePerPulse) {
+    EncoderJNI.setEncoderDistancePerPulse(m_encoder, distancePerPulse);
+  }
+
+  /**
+   * Get the distance per pulse for this encoder.
+   *
+   * @return The scale factor that will be used to convert pulses to useful units.
+   */
+  public double getDistancePerPulse() {
+    return EncoderJNI.getEncoderDistancePerPulse(m_encoder);
+  }
+
+  /**
+   * 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
+   */
+  public void setReverseDirection(boolean reverseDirection) {
+    EncoderJNI.setEncoderReverseDirection(m_encoder, reverseDirection);
+  }
+
+  /**
+   * 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.
+   */
+  public void setSamplesToAverage(int samplesToAverage) {
+    EncoderJNI.setEncoderSamplesToAverage(m_encoder, samplesToAverage);
+  }
+
+  /**
+   * 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)
+   */
+  public int getSamplesToAverage() {
+    return EncoderJNI.getEncoderSamplesToAverage(m_encoder);
+  }
+
+  /**
+   * Set which parameter of the encoder you are using as a process control variable. The encoder
+   * class supports the rate and distance parameters.
+   *
+   * @param pidSource An enum to select the parameter.
+   */
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    m_pidSource = pidSource;
+  }
+
+  @Override
+  public PIDSourceType getPIDSourceType() {
+    return m_pidSource;
+  }
+
+  /**
+   * Implement the PIDSource interface.
+   *
+   * @return The current value of the selected source parameter.
+   */
+  public double pidGet() {
+    switch (m_pidSource) {
+      case kDisplacement:
+        return getDistance();
+      case kRate:
+        return getRate();
+      default:
+        return 0.0;
+    }
+  }
+
+  /**
+   * Set the index source for the encoder. When this source is activated, the encoder count
+   * automatically resets.
+   *
+   * @param channel A DIO channel to set as the encoder index
+   */
+  public void setIndexSource(int channel) {
+    setIndexSource(channel, IndexingType.kResetOnRisingEdge);
+  }
+
+  /**
+   * Set the index source for the encoder. When this source is activated, the encoder count
+   * automatically resets.
+   *
+   * @param source A digital source to set as the encoder index
+   */
+  public void setIndexSource(DigitalSource source) {
+    setIndexSource(source, IndexingType.kResetOnRisingEdge);
+  }
+
+  /**
+   * Set the index source for the encoder. When this source rises, the encoder count automatically
+   * resets.
+   *
+   * @param channel A DIO channel to set as the encoder index
+   * @param type    The state that will cause the encoder to reset
+   */
+  public void setIndexSource(int channel, IndexingType type) {
+    if (m_allocatedI) {
+      throw new AllocationException("Digital Input for Indexing already allocated");
+    }
+    m_indexSource = new DigitalInput(channel);
+    m_allocatedI = true;
+    addChild(m_indexSource);
+    setIndexSource(m_indexSource, type);
+  }
+
+  /**
+   * Set the index source for the encoder. When this source rises, the encoder count automatically
+   * resets.
+   *
+   * @param source A digital source to set as the encoder index
+   * @param type   The state that will cause the encoder to reset
+   */
+  public void setIndexSource(DigitalSource source, IndexingType type) {
+    EncoderJNI.setEncoderIndexSource(m_encoder, source.getPortHandleForRouting(),
+        source.getAnalogTriggerTypeForRouting(), type.value);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    if (EncoderJNI.getEncoderEncodingType(m_encoder) == EncodingType.k4X.value) {
+      builder.setSmartDashboardType("Quadrature Encoder");
+    } else {
+      builder.setSmartDashboardType("Encoder");
+    }
+
+    builder.addDoubleProperty("Speed", this::getRate, null);
+    builder.addDoubleProperty("Distance", this::getDistance, null);
+    builder.addDoubleProperty("Distance per Tick", this::getDistancePerPulse, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GamepadBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GamepadBase.java
new file mode 100644
index 0000000..0d3387d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GamepadBase.java
@@ -0,0 +1,61 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * Gamepad Interface.
+ *
+ * @deprecated Inherit directly from GenericHID instead.
+ */
+@Deprecated
+public abstract class GamepadBase extends GenericHID {
+  public GamepadBase(int port) {
+    super(port);
+  }
+
+  public abstract double getRawAxis(int axis);
+
+  /**
+   * Is the bumper pressed.
+   *
+   * @param hand which hand
+   * @return true if the bumper is pressed
+   */
+  public abstract boolean getBumper(Hand hand);
+
+  /**
+   * Is the bumper pressed.
+   *
+   * @return true if the bumper is pressed
+   */
+  public boolean getBumper() {
+    return getBumper(Hand.kRight);
+  }
+
+  public abstract boolean getStickButton(Hand hand);
+
+  public boolean getStickButton() {
+    return getStickButton(Hand.kRight);
+  }
+
+  public abstract boolean getRawButton(int button);
+
+  public abstract int getPOV(int pov);
+
+  public abstract int getPOVCount();
+
+  public abstract HIDType getType();
+
+  public abstract String getName();
+
+  public abstract void setOutput(int outputNumber, boolean value);
+
+  public abstract void setOutputs(int value);
+
+  public abstract void setRumble(RumbleType type, double value);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GearTooth.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GearTooth.java
new file mode 100644
index 0000000..d0ccef7
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GearTooth.java
@@ -0,0 +1,97 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Alias for counter class. Implement the gear tooth sensor supplied by FIRST. Currently there is no
+ * reverse sensing on the gear tooth sensor, but in future versions we might implement the necessary
+ * timing in the FPGA to sense direction.
+ */
+public class GearTooth extends Counter {
+  private static final double kGearToothThreshold = 55e-6;
+
+  /**
+   * Common code called by the constructors.
+   */
+  public void enableDirectionSensing(boolean directionSensitive) {
+    if (directionSensitive) {
+      setPulseLengthMode(kGearToothThreshold);
+    }
+  }
+
+  /**
+   * Construct a GearTooth sensor given a channel.
+   *
+   * <p>No direction sensing is assumed.
+   *
+   * @param channel The GPIO channel that the sensor is connected to.
+   */
+  public GearTooth(final int channel) {
+    this(channel, false);
+  }
+
+  /**
+   * Construct a GearTooth sensor given a channel.
+   *
+   * @param channel            The DIO channel that the sensor is connected to. 0-9 are on-board,
+   *                           10-25 are on the MXP port
+   * @param directionSensitive True to enable the pulse length decoding in hardware to specify count
+   *                           direction.
+   */
+  public GearTooth(final int channel, boolean directionSensitive) {
+    super(channel);
+    enableDirectionSensing(directionSensitive);
+    if (directionSensitive) {
+      HAL.report(tResourceType.kResourceType_GearTooth, channel, 0, "D");
+    } else {
+      HAL.report(tResourceType.kResourceType_GearTooth, channel, 0);
+    }
+    setName("GearTooth", channel);
+  }
+
+  /**
+   * Construct a GearTooth sensor given a digital input. This should be used when sharing digital
+   * inputs.
+   *
+   * @param source             An existing DigitalSource object (such as a DigitalInput)
+   * @param directionSensitive True to enable the pulse length decoding in hardware to specify count
+   *                           direction.
+   */
+  public GearTooth(DigitalSource source, boolean directionSensitive) {
+    super(source);
+    enableDirectionSensing(directionSensitive);
+    if (directionSensitive) {
+      HAL.report(tResourceType.kResourceType_GearTooth, source.getChannel(), 0, "D");
+    } else {
+      HAL.report(tResourceType.kResourceType_GearTooth, source.getChannel(), 0);
+    }
+    setName("GearTooth", source.getChannel());
+  }
+
+  /**
+   * Construct a GearTooth sensor given a digital input. This should be used when sharing digital
+   * inputs.
+   *
+   * <p>No direction sensing is assumed.
+   *
+   * @param source An object that fully describes the input that the sensor is connected to.
+   */
+  public GearTooth(DigitalSource source) {
+    this(source, false);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    super.initSendable(builder);
+    builder.setSmartDashboardType("Gear Tooth");
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GenericHID.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GenericHID.java
new file mode 100644
index 0000000..11293c3
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GenericHID.java
@@ -0,0 +1,271 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * GenericHID Interface.
+ */
+public abstract class GenericHID {
+  /**
+   * Represents a rumble output on the JoyStick.
+   */
+  public enum RumbleType {
+    kLeftRumble, kRightRumble
+  }
+
+  public enum HIDType {
+    kUnknown(-1),
+    kXInputUnknown(0),
+    kXInputGamepad(1),
+    kXInputWheel(2),
+    kXInputArcadeStick(3),
+    kXInputFlightStick(4),
+    kXInputDancePad(5),
+    kXInputGuitar(6),
+    kXInputGuitar2(7),
+    kXInputDrumKit(8),
+    kXInputGuitar3(11),
+    kXInputArcadePad(19),
+    kHIDJoystick(20),
+    kHIDGamepad(21),
+    kHIDDriving(22),
+    kHIDFlight(23),
+    kHID1stPerson(24);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    HIDType(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Which hand the Human Interface Device is associated with.
+   */
+  public enum Hand {
+    kLeft(0), kRight(1);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    Hand(int value) {
+      this.value = value;
+    }
+  }
+
+  private DriverStation m_ds;
+  private final int m_port;
+  private int m_outputs;
+  private short m_leftRumble;
+  private short m_rightRumble;
+
+  public GenericHID(int port) {
+    m_ds = DriverStation.getInstance();
+    m_port = port;
+  }
+
+  /**
+   * Get the x position of the HID.
+   *
+   * @return the x position of the HID
+   */
+  public final double getX() {
+    return getX(Hand.kRight);
+  }
+
+  /**
+   * Get the x position of HID.
+   *
+   * @param hand which hand, left or right
+   * @return the x position
+   */
+  public abstract double getX(Hand hand);
+
+  /**
+   * Get the y position of the HID.
+   *
+   * @return the y position
+   */
+  public final double getY() {
+    return getY(Hand.kRight);
+  }
+
+  /**
+   * Get the y position of the HID.
+   *
+   * @param hand which hand, left or right
+   * @return the y position
+   */
+  public abstract double getY(Hand hand);
+
+  /**
+   * Get the button value (starting at button 1).
+   *
+   * <p>The buttons are returned in a single 16 bit value with one bit representing the state of
+   * each button. The appropriate button is returned as a boolean value.
+   *
+   * @param button The button number to be read (starting at 1)
+   * @return The state of the button.
+   */
+  public boolean getRawButton(int button) {
+    return m_ds.getStickButton(m_port, (byte) button);
+  }
+
+  /**
+   * Whether the button was pressed since the last check. Button indexes begin at
+   * 1.
+   *
+   * @param button The button index, beginning at 1.
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getRawButtonPressed(int button) {
+    return m_ds.getStickButtonPressed(m_port, (byte) button);
+  }
+
+  /**
+   * Whether the button was released since the last check. Button indexes begin at
+   * 1.
+   *
+   * @param button The button index, beginning at 1.
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getRawButtonReleased(int button) {
+    return m_ds.getStickButtonReleased(m_port, button);
+  }
+
+  /**
+   * Get the value of the axis.
+   *
+   * @param axis The axis to read, starting at 0.
+   * @return The value of the axis.
+   */
+  public double getRawAxis(int axis) {
+    return m_ds.getStickAxis(m_port, axis);
+  }
+
+  /**
+   * Get the angle in degrees of a POV on the HID.
+   *
+   * <p>The POV angles start at 0 in the up direction, and increase clockwise (eg right is 90,
+   * upper-left is 315).
+   *
+   * @param pov The index of the POV to read (starting at 0)
+   * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
+   */
+  public int getPOV(int pov) {
+    return m_ds.getStickPOV(m_port, pov);
+  }
+
+  public int getPOV() {
+    return getPOV(0);
+  }
+
+  /**
+   * Get the number of axes for the HID.
+   *
+   * @return the number of axis for the current HID
+   */
+  public int getAxisCount() {
+    return m_ds.getStickAxisCount(m_port);
+  }
+
+  /**
+   * For the current HID, return the number of POVs.
+   */
+  public int getPOVCount() {
+    return m_ds.getStickPOVCount(m_port);
+  }
+
+  /**
+   * For the current HID, return the number of buttons.
+   */
+  public int getButtonCount() {
+    return m_ds.getStickButtonCount(m_port);
+  }
+
+  /**
+   * Get the type of the HID.
+   *
+   * @return the type of the HID.
+   */
+  public HIDType getType() {
+    return HIDType.values()[m_ds.getJoystickType(m_port)];
+  }
+
+  /**
+   * Get the name of the HID.
+   *
+   * @return the name of the HID.
+   */
+  public String getName() {
+    return m_ds.getJoystickName(m_port);
+  }
+
+  /**
+   * Get the axis type of a joystick axis.
+   *
+   * @return the axis type of a joystick axis.
+   */
+  public int getAxisType(int axis) {
+    return m_ds.getJoystickAxisType(m_port, axis);
+  }
+
+  /**
+   * Get the port number of the HID.
+   *
+   * @return The port number of the HID.
+   */
+  public int getPort() {
+    return m_port;
+  }
+
+  /**
+   * Set a single HID output value for the HID.
+   *
+   * @param outputNumber The index of the output to set (1-32)
+   * @param value        The value to set the output to
+   */
+  public void setOutput(int outputNumber, boolean value) {
+    m_outputs = (m_outputs & ~(1 << (outputNumber - 1))) | ((value ? 1 : 0) << (outputNumber - 1));
+    HAL.setJoystickOutputs((byte) m_port, m_outputs, m_leftRumble, m_rightRumble);
+  }
+
+  /**
+   * Set all HID output values for the HID.
+   *
+   * @param value The 32 bit output value (1 bit for each output)
+   */
+  public void setOutputs(int value) {
+    m_outputs = value;
+    HAL.setJoystickOutputs((byte) m_port, m_outputs, m_leftRumble, m_rightRumble);
+  }
+
+  /**
+   * Set the rumble output for the HID. The DS currently supports 2 rumble values, left rumble and
+   * right rumble.
+   *
+   * @param type  Which rumble value to set
+   * @param value The normalized value (0 to 1) to set the rumble to
+   */
+  public void setRumble(RumbleType type, double value) {
+    if (value < 0) {
+      value = 0;
+    } else if (value > 1) {
+      value = 1;
+    }
+    if (type == RumbleType.kLeftRumble) {
+      m_leftRumble = (short) (value * 65535);
+    } else {
+      m_rightRumble = (short) (value * 65535);
+    }
+    HAL.setJoystickOutputs((byte) m_port, m_outputs, m_leftRumble, m_rightRumble);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GyroBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GyroBase.java
new file mode 100644
index 0000000..9647df7
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/GyroBase.java
@@ -0,0 +1,58 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.interfaces.Gyro;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * GyroBase is the common base class for Gyro implementations such as AnalogGyro.
+ */
+public abstract class GyroBase extends SensorBase implements Gyro, PIDSource, Sendable {
+  private PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
+
+  /**
+   * Set which parameter of the gyro you are using as a process control variable. The Gyro class
+   * supports the rate and displacement parameters
+   *
+   * @param pidSource An enum to select the parameter.
+   */
+  @Override
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    m_pidSource = pidSource;
+  }
+
+  @Override
+  public PIDSourceType getPIDSourceType() {
+    return m_pidSource;
+  }
+
+  /**
+   * Get the output of the gyro for use with PIDControllers. May be the angle or rate depending on
+   * the set PIDSourceType
+   *
+   * @return the output according to the gyro
+   */
+  @Override
+  public double pidGet() {
+    switch (m_pidSource) {
+      case kRate:
+        return getRate();
+      case kDisplacement:
+        return getAngle();
+      default:
+        return 0.0;
+    }
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Gyro");
+    builder.addDoubleProperty("Value", this::getAngle, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/HLUsageReporting.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/HLUsageReporting.java
new file mode 100644
index 0000000..3eca63b
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/HLUsageReporting.java
@@ -0,0 +1,67 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.util.BaseSystemNotInitializedException;
+
+/**
+ * Support for high level usage reporting.
+ */
+@SuppressWarnings("JavadocMethod")
+public class HLUsageReporting {
+  private static Interface impl;
+
+  @SuppressWarnings("MethodName")
+  public static void SetImplementation(Interface implementation) {
+    impl = implementation;
+  }
+
+  public static void reportScheduler() {
+    if (impl != null) {
+      impl.reportScheduler();
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, HLUsageReporting.class);
+    }
+  }
+
+  public static void reportPIDController(int num) {
+    if (impl != null) {
+      impl.reportPIDController(num);
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, HLUsageReporting.class);
+    }
+  }
+
+  public static void reportSmartDashboard() {
+    if (impl != null) {
+      impl.reportSmartDashboard();
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, HLUsageReporting.class);
+    }
+  }
+
+  public interface Interface {
+    void reportScheduler();
+
+    void reportPIDController(int num);
+
+    void reportSmartDashboard();
+  }
+
+  public static class Null implements Interface {
+    public void reportScheduler() {
+    }
+
+    @SuppressWarnings("PMD.UnusedFormalParameter")
+    public void reportPIDController(int num) {
+    }
+
+    public void reportSmartDashboard() {
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java
new file mode 100644
index 0000000..7c76ac9
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java
@@ -0,0 +1,370 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.I2CJNI;
+import edu.wpi.first.wpilibj.util.BoundaryException;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * I2C bus interface class.
+ *
+ * <p>This class is intended to be used by sensor (and other I2C device) drivers. It probably should
+ * not be used directly.
+ */
+public class I2C {
+  public enum Port {
+    kOnboard(0), kMXP(1);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    Port(int value) {
+      this.value = value;
+    }
+  }
+
+  private final int m_port;
+  private final int m_deviceAddress;
+
+  /**
+   * Constructor.
+   *
+   * @param port          The I2C port the device is connected to.
+   * @param deviceAddress The address of the device on the I2C bus.
+   */
+  public I2C(Port port, int deviceAddress) {
+    m_port = port.value;
+    m_deviceAddress = deviceAddress;
+
+    I2CJNI.i2CInitialize((byte) port.value);
+
+    HAL.report(tResourceType.kResourceType_I2C, deviceAddress);
+  }
+
+  /**
+   * Destructor.
+   */
+  public void free() {
+    I2CJNI.i2CClose(m_port);
+  }
+
+  /**
+   * Generic transaction.
+   *
+   * <p>This is a lower-level interface to the I2C hardware giving you more control over each
+   * transaction.
+   *
+   * @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 Transfer Aborted... false for success, true for aborted.
+   */
+  public synchronized boolean transaction(byte[] dataToSend, int sendSize,
+                                          byte[] dataReceived, int receiveSize) {
+    if (dataToSend.length < sendSize) {
+      throw new IllegalArgumentException("dataToSend is too small, must be at least " + sendSize);
+    }
+    if (dataReceived.length < receiveSize) {
+      throw new IllegalArgumentException(
+          "dataReceived is too small, must be at least " + receiveSize);
+    }
+    return I2CJNI.i2CTransactionB(m_port, (byte) m_deviceAddress, dataToSend,
+                                  (byte) sendSize, dataReceived, (byte) receiveSize) < 0;
+  }
+
+  /**
+   * Generic transaction.
+   *
+   * <p>This is a lower-level interface to the I2C hardware giving you more control over each
+   * transaction.
+   *
+   * @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 Transfer Aborted... false for success, true for aborted.
+   */
+  public synchronized boolean transaction(ByteBuffer dataToSend, int sendSize,
+                                          ByteBuffer dataReceived, int receiveSize) {
+    if (dataToSend.hasArray() && dataReceived.hasArray()) {
+      return transaction(dataToSend.array(), sendSize, dataReceived.array(), receiveSize);
+    }
+    if (!dataToSend.isDirect()) {
+      throw new IllegalArgumentException("dataToSend must be a direct buffer");
+    }
+    if (dataToSend.capacity() < sendSize) {
+      throw new IllegalArgumentException("dataToSend is too small, must be at least " + sendSize);
+    }
+    if (!dataReceived.isDirect()) {
+      throw new IllegalArgumentException("dataReceived must be a direct buffer");
+    }
+    if (dataReceived.capacity() < receiveSize) {
+      throw new IllegalArgumentException(
+          "dataReceived is too small, must be at least " + receiveSize);
+    }
+
+    return I2CJNI.i2CTransaction(m_port, (byte) m_deviceAddress, dataToSend,
+                                 (byte) sendSize, dataReceived, (byte) receiveSize) < 0;
+  }
+
+  /**
+   * Attempt to address a device on the I2C bus.
+   *
+   * <p>This allows you to figure out if there is a device on the I2C bus that responds to the
+   * address specified in the constructor.
+   *
+   * @return Transfer Aborted... false for success, true for aborted.
+   */
+  public boolean addressOnly() {
+    return transaction(new byte[0], (byte) 0, new byte[0], (byte) 0);
+  }
+
+  /**
+   * Execute a write transaction with the device.
+   *
+   * <p>Write a single byte to a register on a device and wait until the transaction is complete.
+   *
+   * @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 Transfer Aborted... false for success, true for aborted.
+   */
+  public synchronized boolean write(int registerAddress, int data) {
+    byte[] buffer = new byte[2];
+    buffer[0] = (byte) registerAddress;
+    buffer[1] = (byte) data;
+    return I2CJNI.i2CWriteB(m_port, (byte) m_deviceAddress, buffer,
+                            (byte) buffer.length) < 0;
+  }
+
+  /**
+   * Execute a write transaction with the device.
+   *
+   * <p>Write multiple bytes to a register on a device and wait until the transaction is complete.
+   *
+   * @param data The data to write to the device.
+   * @return Transfer Aborted... false for success, true for aborted.
+   */
+  public synchronized boolean writeBulk(byte[] data) {
+    return writeBulk(data, data.length);
+  }
+
+  /**
+   * Execute a write transaction with the device.
+   *
+   * <p>Write multiple bytes to a register on a device and wait until the transaction is complete.
+   *
+   * @param data The data to write to the device.
+   * @param size The number of data bytes to write.
+   * @return Transfer Aborted... false for success, true for aborted.
+   */
+  public synchronized boolean writeBulk(byte[] data, int size) {
+    if (data.length < size) {
+      throw new IllegalArgumentException(
+          "buffer is too small, must be at least " + size);
+    }
+    return I2CJNI.i2CWriteB(m_port, (byte) m_deviceAddress, data, (byte) size) < 0;
+  }
+
+  /**
+   * Execute a write transaction with the device.
+   *
+   * <p>Write multiple bytes to a register on a device and wait until the transaction is complete.
+   *
+   * @param data The data to write to the device.
+   * @param size The number of data bytes to write.
+   * @return Transfer Aborted... false for success, true for aborted.
+   */
+  public synchronized boolean writeBulk(ByteBuffer data, int size) {
+    if (data.hasArray()) {
+      return writeBulk(data.array(), size);
+    }
+    if (!data.isDirect()) {
+      throw new IllegalArgumentException("must be a direct buffer");
+    }
+    if (data.capacity() < size) {
+      throw new IllegalArgumentException(
+          "buffer is too small, must be at least " + size);
+    }
+
+    return I2CJNI.i2CWrite(m_port, (byte) m_deviceAddress, data, (byte) size) < 0;
+  }
+
+  /**
+   * Execute a read transaction with the device.
+   *
+   * <p>Read 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 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 Transfer Aborted... false for success, true for aborted.
+   */
+  public boolean read(int registerAddress, int count, byte[] buffer) {
+    requireNonNull(buffer, "Null return buffer was given");
+
+    if (count < 1) {
+      throw new BoundaryException("Value must be at least 1, " + count + " given");
+    }
+    if (buffer.length < count) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + count);
+    }
+
+    byte[] registerAddressArray = new byte[1];
+    registerAddressArray[0] = (byte) registerAddress;
+
+    return transaction(registerAddressArray, registerAddressArray.length, buffer, count);
+  }
+
+  private ByteBuffer m_readDataToSendBuffer = null;
+
+  /**
+   * Execute a read transaction with the device.
+   *
+   * <p>Read 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 registerAddress The register to read first in the transaction.
+   * @param count           The number of bytes to read in the transaction.
+   * @param buffer          A buffer to store the data read from the device.
+   * @return Transfer Aborted... false for success, true for aborted.
+   */
+  public boolean read(int registerAddress, int count, ByteBuffer buffer) {
+    if (count < 1) {
+      throw new BoundaryException("Value must be at least 1, " + count + " given");
+    }
+
+    if (buffer.hasArray()) {
+      return read(registerAddress, count, buffer.array());
+    }
+
+    if (!buffer.isDirect()) {
+      throw new IllegalArgumentException("must be a direct buffer");
+    }
+    if (buffer.capacity() < count) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + count);
+    }
+
+    synchronized (this) {
+      if (m_readDataToSendBuffer == null) {
+        m_readDataToSendBuffer = ByteBuffer.allocateDirect(1);
+      }
+      m_readDataToSendBuffer.put(0, (byte) registerAddress);
+
+      return transaction(m_readDataToSendBuffer, 1, buffer, count);
+    }
+  }
+
+  /**
+   * Execute a read only transaction with the device.
+   *
+   * <p>Read bytes from a device. This method does not write any data to prompt the device.
+   *
+   * @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.
+   * @return Transfer Aborted... false for success, true for aborted.
+   */
+  public boolean readOnly(byte[] buffer, int count) {
+    requireNonNull(buffer, "Null return buffer was given");
+    if (count < 1) {
+      throw new BoundaryException("Value must be at least 1, " + count + " given");
+    }
+    if (buffer.length < count) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + count);
+    }
+
+    return I2CJNI.i2CReadB(m_port, (byte) m_deviceAddress, buffer,
+                           (byte) count) < 0;
+  }
+
+  /**
+   * Execute a read only transaction with the device.
+   *
+   * <p>Read bytes from a device. This method does not write any data to prompt the device.
+   *
+   * @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.
+   * @return Transfer Aborted... false for success, true for aborted.
+   */
+  public boolean readOnly(ByteBuffer buffer, int count) {
+    if (count < 1) {
+      throw new BoundaryException("Value must be at least 1, " + count
+          + " given");
+    }
+
+    if (buffer.hasArray()) {
+      return readOnly(buffer.array(), count);
+    }
+
+    if (!buffer.isDirect()) {
+      throw new IllegalArgumentException("must be a direct buffer");
+    }
+    if (buffer.capacity() < count) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + count);
+    }
+
+    return I2CJNI.i2CRead(m_port, (byte) m_deviceAddress, buffer, (byte) count)
+        < 0;
+  }
+
+  /*
+   * Send a broadcast write to all devices on the I2C bus.
+   *
+   * <p>This is not currently implemented!
+   *
+   * @param registerAddress The register to write on all devices on the bus.
+   * @param data            The value to write to the devices.
+   */
+  // public void broadcast(int registerAddress, int data) {
+  // }
+
+  /**
+   * Verify that a device's registers contain expected values.
+   *
+   * <p>Most devices will have a set of registers that contain a known value that can be used to
+   * identify them. This allows an I2C device driver to easily verify that the device contains the
+   * expected value.
+   *
+   * @param registerAddress The base register to start reading from the device.
+   * @param count           The size of the field to be verified.
+   * @param expected        A buffer containing the values expected from the device.
+   * @return true if the sensor was verified to be connected
+   * @pre The device must support and be configured to use register auto-increment.
+   */
+  public boolean verifySensor(int registerAddress, int count,
+                              byte[] expected) {
+    // TODO: Make use of all 7 read bytes
+    byte[] dataToSend = new byte[1];
+
+    byte[] deviceData = new byte[4];
+    for (int i = 0, curRegisterAddress = registerAddress;
+         i < count; i += 4, curRegisterAddress += 4) {
+      int toRead = count - i < 4 ? count - i : 4;
+      // Read the chunk of data. Return false if the sensor does not
+      // respond.
+      dataToSend[0] = (byte) curRegisterAddress;
+      if (transaction(dataToSend, 1, deviceData, toRead)) {
+        return false;
+      }
+
+      for (byte j = 0; j < toRead; j++) {
+        if (deviceData[j] != expected[i + j]) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptHandlerFunction.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptHandlerFunction.java
new file mode 100644
index 0000000..ed9048e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptHandlerFunction.java
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.InterruptJNI.InterruptJNIHandlerFunction;
+
+
+/**
+ * It is recommended that you use this class in conjunction with classes from {@link
+ * java.util.concurrent.atomic} as these objects are all thread safe.
+ *
+ * @param <T> The type of the parameter that should be returned to the the method {@link
+ *            #interruptFired(int, Object)}
+ */
+public abstract class InterruptHandlerFunction<T> {
+  /**
+   * The entry point for the interrupt. When the interrupt fires the {@link #apply(int, Object)}
+   * method is called. The outer class is provided as an interface to allow the implementer to pass
+   * a generic object to the interrupt fired method.
+   */
+  private class Function implements InterruptJNIHandlerFunction {
+    @SuppressWarnings("unchecked")
+    @Override
+    public void apply(int interruptAssertedMask, Object param) {
+      interruptFired(interruptAssertedMask, (T) param);
+    }
+  }
+
+  final Function m_function = new Function();
+
+  /**
+   * This method is run every time an interrupt is fired.
+   *
+   * @param interruptAssertedMask Interrupt Mask
+   * @param param                 The parameter provided by overriding the {@link
+   *                              #overridableParameter()} method.
+   */
+  public abstract void interruptFired(int interruptAssertedMask, T param);
+
+
+  /**
+   * Override this method if you would like to pass a specific parameter to the {@link
+   * #interruptFired(int, Object)} when it is fired by the interrupt. This method is called once
+   * when {@link InterruptableSensorBase#requestInterrupts(InterruptHandlerFunction)} is run.
+   *
+   * @return The object that should be passed to the interrupt when it runs
+   */
+  public T overridableParameter() {
+    return null;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptableSensorBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptableSensorBase.java
new file mode 100644
index 0000000..f690d3a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptableSensorBase.java
@@ -0,0 +1,251 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.InterruptJNI;
+import edu.wpi.first.wpilibj.util.AllocationException;
+
+
+/**
+ * Base for sensors to be used with interrupts.
+ */
+public abstract class InterruptableSensorBase extends SensorBase {
+  @SuppressWarnings("JavadocMethod")
+  public enum WaitResult {
+    kTimeout(0x0), kRisingEdge(0x1), kFallingEdge(0x100), kBoth(0x101);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    WaitResult(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * The interrupt resource.
+   */
+  protected int m_interrupt = InterruptJNI.HalInvalidHandle;
+
+  /**
+   * Flags if the interrupt being allocated is synchronous.
+   */
+  protected boolean m_isSynchronousInterrupt = false;
+
+  /**
+   * Create a new InterrupatableSensorBase.
+   */
+  public InterruptableSensorBase() {
+    m_interrupt = 0;
+  }
+
+  /**
+   * Frees the resources for this output.
+   */
+  @Override
+  public void free() {
+    super.free();
+    if (m_interrupt != 0) {
+      cancelInterrupts();
+    }
+  }
+
+  /**
+   * If this is an analog trigger.
+   *
+   * @return true if this is an analog trigger.
+   */
+  public abstract int getAnalogTriggerTypeForRouting();
+
+  /**
+   * The channel routing number.
+   *
+   * @return channel routing number
+   */
+  public abstract int getPortHandleForRouting();
+
+  /**
+   * Request one of the 8 interrupts asynchronously on this digital input.
+   *
+   * @param handler The {@link InterruptHandlerFunction} that contains the method {@link
+   *                InterruptHandlerFunction#interruptFired(int, Object)} that will be called
+   *                whenever there is an interrupt on this device. Request interrupts in synchronous
+   *                mode where the user program interrupt handler will be called when an interrupt
+   *                occurs. The default is interrupt on rising edges only.
+   */
+  public void requestInterrupts(InterruptHandlerFunction<?> handler) {
+    if (m_interrupt != 0) {
+      throw new AllocationException("The interrupt has already been allocated");
+    }
+
+    allocateInterrupts(false);
+
+    assert m_interrupt != 0;
+
+    InterruptJNI.requestInterrupts(m_interrupt, getPortHandleForRouting(),
+        getAnalogTriggerTypeForRouting());
+    setUpSourceEdge(true, false);
+    InterruptJNI.attachInterruptHandler(m_interrupt, handler.m_function,
+        handler.overridableParameter());
+  }
+
+  /**
+   * Request one of the 8 interrupts synchronously on this digital input. Request interrupts in
+   * synchronous mode where the user program will have to explicitly wait for the interrupt to occur
+   * using {@link #waitForInterrupt}. The default is interrupt on rising edges only.
+   */
+  public void requestInterrupts() {
+    if (m_interrupt != 0) {
+      throw new AllocationException("The interrupt has already been allocated");
+    }
+
+    allocateInterrupts(true);
+
+    assert m_interrupt != 0;
+
+    InterruptJNI.requestInterrupts(m_interrupt, getPortHandleForRouting(),
+        getAnalogTriggerTypeForRouting());
+    setUpSourceEdge(true, false);
+
+  }
+
+  /**
+   * Allocate the interrupt.
+   *
+   * @param watcher true if the interrupt should be in synchronous mode where the user program will
+   *                have to explicitly wait for the interrupt to occur.
+   */
+  protected void allocateInterrupts(boolean watcher) {
+    m_isSynchronousInterrupt = watcher;
+
+    m_interrupt = InterruptJNI.initializeInterrupts(watcher);
+  }
+
+  /**
+   * Cancel interrupts on this device. This deallocates all the chipobject structures and disables
+   * any interrupts.
+   */
+  public void cancelInterrupts() {
+    if (m_interrupt == 0) {
+      throw new IllegalStateException("The interrupt is not allocated.");
+    }
+    InterruptJNI.cleanInterrupts(m_interrupt);
+    m_interrupt = 0;
+  }
+
+  /**
+   * In synchronous mode, wait for the defined interrupt to occur.
+   *
+   * @param timeout        Timeout in seconds
+   * @param ignorePrevious If true, ignore interrupts that happened before waitForInterrupt was
+   *                       called.
+   * @return Result of the wait.
+   */
+  public WaitResult waitForInterrupt(double timeout, boolean ignorePrevious) {
+    if (m_interrupt == 0) {
+      throw new IllegalStateException("The interrupt is not allocated.");
+    }
+    int result = InterruptJNI.waitForInterrupt(m_interrupt, timeout, ignorePrevious);
+
+    // Rising edge result is the interrupt bit set in the byte 0xFF
+    // Falling edge result is the interrupt bit set in the byte 0xFF00
+    // Set any bit set to be true for that edge, and AND the 2 results
+    // together to match the existing enum for all interrupts
+    int rising = ((result & 0xFF) != 0) ? 0x1 : 0x0;
+    int falling = ((result & 0xFF00) != 0) ? 0x0100 : 0x0;
+    result = rising | falling;
+
+    for (WaitResult mode : WaitResult.values()) {
+      if (mode.value == result) {
+        return mode;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * In synchronous mode, wait for the defined interrupt to occur.
+   *
+   * @param timeout Timeout in seconds
+   * @return Result of the wait.
+   */
+  public WaitResult waitForInterrupt(double timeout) {
+    return waitForInterrupt(timeout, true);
+  }
+
+  /**
+   * Enable 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.
+   */
+  public void enableInterrupts() {
+    if (m_interrupt == 0) {
+      throw new IllegalStateException("The interrupt is not allocated.");
+    }
+    if (m_isSynchronousInterrupt) {
+      throw new IllegalStateException("You do not need to enable synchronous interrupts");
+    }
+    InterruptJNI.enableInterrupts(m_interrupt);
+  }
+
+  /**
+   * Disable Interrupts without without deallocating structures.
+   */
+  public void disableInterrupts() {
+    if (m_interrupt == 0) {
+      throw new IllegalStateException("The interrupt is not allocated.");
+    }
+    if (m_isSynchronousInterrupt) {
+      throw new IllegalStateException("You can not disable synchronous interrupts");
+    }
+    InterruptJNI.disableInterrupts(m_interrupt);
+  }
+
+  /**
+   * Return the timestamp for the rising interrupt that occurred most recently. This is in the same
+   * time domain as getClock(). The rising-edge interrupt should be enabled with {@link
+   * #setUpSourceEdge}.
+   *
+   * @return Timestamp in seconds since boot.
+   */
+  public double readRisingTimestamp() {
+    if (m_interrupt == 0) {
+      throw new IllegalStateException("The interrupt is not allocated.");
+    }
+    return InterruptJNI.readInterruptRisingTimestamp(m_interrupt);
+  }
+
+  /**
+   * Return the timestamp for the falling interrupt that occurred most recently. This is in the same
+   * time domain as getClock(). The falling-edge interrupt should be enabled with {@link
+   * #setUpSourceEdge}.
+   *
+   * @return Timestamp in seconds since boot.
+   */
+  public double readFallingTimestamp() {
+    if (m_interrupt == 0) {
+      throw new IllegalStateException("The interrupt is not allocated.");
+    }
+    return InterruptJNI.readInterruptFallingTimestamp(m_interrupt);
+  }
+
+  /**
+   * Set which edge to trigger interrupts on.
+   *
+   * @param risingEdge  true to interrupt on rising edge
+   * @param fallingEdge true to interrupt on falling edge
+   */
+  public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
+    if (m_interrupt != 0) {
+      InterruptJNI.setInterruptUpSourceEdge(m_interrupt, risingEdge,
+          fallingEdge);
+    } else {
+      throw new IllegalArgumentException("You must call RequestInterrupts before setUpSourceEdge");
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobot.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobot.java
new file mode 100644
index 0000000..10ddd4b
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobot.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * IterativeRobot implements the IterativeRobotBase robot program framework.
+ *
+ * <p>The IterativeRobot class is intended to be subclassed by a user creating a robot program.
+ *
+ * <p>periodic() functions from the base class are called each time a new packet is received from
+ * the driver station.
+ */
+public class IterativeRobot extends IterativeRobotBase {
+  public IterativeRobot() {
+    HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Iterative);
+  }
+
+  /**
+   * Provide an alternate "main loop" via startCompetition().
+   */
+  public void startCompetition() {
+    robotInit();
+
+    // Tell the DS that the robot is ready to be enabled
+    HAL.observeUserProgramStarting();
+
+    // Loop forever, calling the appropriate mode-dependent function
+    while (true) {
+      // Wait for new data to arrive
+      m_ds.waitForData();
+
+      loopFunc();
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java
new file mode 100644
index 0000000..16d5b13
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java
@@ -0,0 +1,229 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.livewindow.LiveWindow;
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
+
+/**
+ * IterativeRobotBase implements a specific type of robot program framework, extending the RobotBase
+ * class.
+ *
+ * <p>The IterativeRobotBase class does not implement startCompetition(), so it should not be used
+ * by teams directly.
+ *
+ * <p>This class provides the following functions which are called by the main loop,
+ * startCompetition(), at the appropriate times:
+ *
+ * <p>robotInit() -- provide for initialization at robot power-on
+ *
+ * <p>init() functions -- each of the following functions is called once when the
+ * appropriate mode is entered:
+ *   - disabledInit()   -- called only when first disabled
+ *   - autonomousInit() -- called each and every time autonomous is entered from
+ *                         another mode
+ *   - teleopInit()     -- called each and every time teleop is entered from
+ *                         another mode
+ *   - testInit()       -- called each and every time test is entered from
+ *                         another mode
+ *
+ * <p>periodic() functions -- each of these functions is called on an interval:
+ *   - robotPeriodic()
+ *   - disabledPeriodic()
+ *   - autonomousPeriodic()
+ *   - teleopPeriodic()
+ *   - testPeriodic()
+ */
+public abstract class IterativeRobotBase extends RobotBase {
+  private enum Mode {
+    kNone,
+    kDisabled,
+    kAutonomous,
+    kTeleop,
+    kTest
+  }
+
+  private Mode m_lastMode = Mode.kNone;
+
+  /**
+   * Provide an alternate "main loop" via startCompetition().
+   */
+  public abstract void startCompetition();
+
+  /* ----------- Overridable initialization code ----------------- */
+
+  /**
+   * Robot-wide initialization code should go here.
+   *
+   * <p>Users should override this method for default Robot-wide initialization which will be called
+   * when the robot is first powered on. It will be called exactly one time.
+   *
+   * <p>Warning: the Driver Station "Robot Code" light and FMS "Robot Ready" indicators will be off
+   * until RobotInit() exits. Code in RobotInit() that waits for enable will cause the robot to
+   * never indicate that the code is ready, causing the robot to be bypassed in a match.
+   */
+  public void robotInit() {
+    System.out.println("Default robotInit() method... Overload me!");
+  }
+
+  /**
+   * Initialization code for disabled mode should go here.
+   *
+   * <p>Users should override this method for initialization code which will be called each time the
+   * robot enters disabled mode.
+   */
+  public void disabledInit() {
+    System.out.println("Default disabledInit() method... Overload me!");
+  }
+
+  /**
+   * Initialization code for autonomous mode should go here.
+   *
+   * <p>Users should override this method for initialization code which will be called each time the
+   * robot enters autonomous mode.
+   */
+  public void autonomousInit() {
+    System.out.println("Default autonomousInit() method... Overload me!");
+  }
+
+  /**
+   * Initialization code for teleop mode should go here.
+   *
+   * <p>Users should override this method for initialization code which will be called each time the
+   * robot enters teleop mode.
+   */
+  public void teleopInit() {
+    System.out.println("Default teleopInit() method... Overload me!");
+  }
+
+  /**
+   * Initialization code for test mode should go here.
+   *
+   * <p>Users should override this method for initialization code which will be called each time the
+   * robot enters test mode.
+   */
+  @SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
+  public void testInit() {
+    System.out.println("Default testInit() method... Overload me!");
+  }
+
+  /* ----------- Overridable periodic code ----------------- */
+
+  private boolean m_rpFirstRun = true;
+
+  /**
+   * Periodic code for all robot modes should go here.
+   */
+  public void robotPeriodic() {
+    if (m_rpFirstRun) {
+      System.out.println("Default robotPeriodic() method... Overload me!");
+      m_rpFirstRun = false;
+    }
+  }
+
+  private boolean m_dpFirstRun = true;
+
+  /**
+   * Periodic code for disabled mode should go here.
+   */
+  public void disabledPeriodic() {
+    if (m_dpFirstRun) {
+      System.out.println("Default disabledPeriodic() method... Overload me!");
+      m_dpFirstRun = false;
+    }
+  }
+
+  private boolean m_apFirstRun = true;
+
+  /**
+   * Periodic code for autonomous mode should go here.
+   */
+  public void autonomousPeriodic() {
+    if (m_apFirstRun) {
+      System.out.println("Default autonomousPeriodic() method... Overload me!");
+      m_apFirstRun = false;
+    }
+  }
+
+  private boolean m_tpFirstRun = true;
+
+  /**
+   * Periodic code for teleop mode should go here.
+   */
+  public void teleopPeriodic() {
+    if (m_tpFirstRun) {
+      System.out.println("Default teleopPeriodic() method... Overload me!");
+      m_tpFirstRun = false;
+    }
+  }
+
+  private boolean m_tmpFirstRun = true;
+
+  /**
+   * Periodic code for test mode should go here.
+   */
+  @SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
+  public void testPeriodic() {
+    if (m_tmpFirstRun) {
+      System.out.println("Default testPeriodic() method... Overload me!");
+      m_tmpFirstRun = false;
+    }
+  }
+
+  protected void loopFunc() {
+    // Call the appropriate function depending upon the current robot mode
+    if (isDisabled()) {
+      // call DisabledInit() if we are now just entering disabled mode from
+      // either a different mode or from power-on
+      if (m_lastMode != Mode.kDisabled) {
+        LiveWindow.setEnabled(false);
+        disabledInit();
+        m_lastMode = Mode.kDisabled;
+      }
+      HAL.observeUserProgramDisabled();
+      disabledPeriodic();
+    } else if (isAutonomous()) {
+      // call Autonomous_Init() if this is the first time
+      // we've entered autonomous_mode
+      if (m_lastMode != Mode.kAutonomous) {
+        LiveWindow.setEnabled(false);
+        // KBS NOTE: old code reset all PWMs and relays to "safe values"
+        // whenever entering autonomous mode, before calling
+        // "Autonomous_Init()"
+        autonomousInit();
+        m_lastMode = Mode.kAutonomous;
+      }
+      HAL.observeUserProgramAutonomous();
+      autonomousPeriodic();
+    } else if (isOperatorControl()) {
+      // call Teleop_Init() if this is the first time
+      // we've entered teleop_mode
+      if (m_lastMode != Mode.kTeleop) {
+        LiveWindow.setEnabled(false);
+        teleopInit();
+        m_lastMode = Mode.kTeleop;
+      }
+      HAL.observeUserProgramTeleop();
+      teleopPeriodic();
+    } else {
+      // call TestInit() if we are now just entering test mode from either
+      // a different mode or from power-on
+      if (m_lastMode != Mode.kTest) {
+        LiveWindow.setEnabled(true);
+        testInit();
+        m_lastMode = Mode.kTest;
+      }
+      HAL.observeUserProgramTest();
+      testPeriodic();
+    }
+    robotPeriodic();
+    SmartDashboard.updateValues();
+    LiveWindow.updateValues();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Jaguar.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Jaguar.java
new file mode 100644
index 0000000..c83cf01
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Jaguar.java
@@ -0,0 +1,42 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Texas Instruments / Vex Robotics Jaguar Speed Controller as a PWM device.
+ */
+public class Jaguar extends PWMSpeedController {
+  /**
+   * Constructor.
+   *
+   * @param channel The PWM channel that the Jaguar is attached to. 0-9 are on-board, 10-19 are on
+   *                the MXP port
+   */
+  public Jaguar(final int channel) {
+    super(channel);
+
+    /*
+     * Input profile defined by Luminary Micro.
+     *
+     * Full reverse ranges from 0.671325ms to 0.6972211ms Proportional reverse
+     * ranges from 0.6972211ms to 1.4482078ms Neutral ranges from 1.4482078ms to
+     * 1.5517922ms Proportional forward ranges from 1.5517922ms to 2.3027789ms
+     * Full forward ranges from 2.3027789ms to 2.328675ms
+     */
+    setBounds(2.31, 1.55, 1.507, 1.454, .697);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    HAL.report(tResourceType.kResourceType_Jaguar, getChannel());
+    setName("Jaguar", getChannel());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java
new file mode 100644
index 0000000..de302ad
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java
@@ -0,0 +1,393 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Handle input from standard Joysticks connected to the Driver Station.
+ *
+ * <p>This class handles standard input that comes from the Driver Station. Each time a value is
+ * requested the most recent value is returned. There is a single class instance for each joystick
+ * and the mapping of ports to hardware buttons depends on the code in the Driver Station.
+ */
+public class Joystick extends GenericHID {
+  static final byte kDefaultXAxis = 0;
+  static final byte kDefaultYAxis = 1;
+  static final byte kDefaultZAxis = 2;
+  static final byte kDefaultTwistAxis = 2;
+  static final byte kDefaultThrottleAxis = 3;
+
+  /**
+   * Represents an analog axis on a joystick.
+   */
+  public enum AxisType {
+    kX(0), kY(1), kZ(2), kTwist(3), kThrottle(4);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    AxisType(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Represents a digital button on a joystick.
+   */
+  public enum ButtonType {
+    kTrigger(1), kTop(2);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    ButtonType(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Represents a digital button on a joystick.
+   */
+  private enum Button {
+    kTrigger(1), kTop(2);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    Button(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Represents an analog axis on a joystick.
+   */
+  private enum Axis {
+    kX(0), kY(1), kZ(2), kTwist(3), kThrottle(4), kNumAxes(5);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    Axis(int value) {
+      this.value = value;
+    }
+  }
+
+  private final byte[] m_axes = new byte[Axis.kNumAxes.value];
+
+  /**
+   * Construct an instance of a joystick. The joystick index is the USB port on the drivers
+   * station.
+   *
+   * @param port The port on the Driver Station that the joystick is plugged into.
+   */
+  public Joystick(final int port) {
+    super(port);
+
+    m_axes[Axis.kX.value] = kDefaultXAxis;
+    m_axes[Axis.kY.value] = kDefaultYAxis;
+    m_axes[Axis.kZ.value] = kDefaultZAxis;
+    m_axes[Axis.kTwist.value] = kDefaultTwistAxis;
+    m_axes[Axis.kThrottle.value] = kDefaultThrottleAxis;
+
+    HAL.report(tResourceType.kResourceType_Joystick, port);
+  }
+
+  /**
+   * Set the channel associated with the X axis.
+   *
+   * @param channel The channel to set the axis to.
+   */
+  public void setXChannel(int channel) {
+    m_axes[Axis.kX.value] = (byte) channel;
+  }
+
+  /**
+   * Set the channel associated with the Y axis.
+   *
+   * @param channel The channel to set the axis to.
+   */
+  public void setYChannel(int channel) {
+    m_axes[Axis.kY.value] = (byte) channel;
+  }
+
+  /**
+   * Set the channel associated with the Z axis.
+   *
+   * @param channel The channel to set the axis to.
+   */
+  public void setZChannel(int channel) {
+    m_axes[Axis.kZ.value] = (byte) channel;
+  }
+
+  /**
+   * Set the channel associated with the throttle axis.
+   *
+   * @param channel The channel to set the axis to.
+   */
+  public void setThrottleChannel(int channel) {
+    m_axes[Axis.kThrottle.value] = (byte) channel;
+  }
+
+  /**
+   * Set the channel associated with the twist axis.
+   *
+   * @param channel The channel to set the axis to.
+   */
+  public void setTwistChannel(int channel) {
+    m_axes[Axis.kTwist.value] = (byte) channel;
+  }
+
+  /**
+   * Set the channel associated with a specified axis.
+   *
+   * @deprecated    Use the more specific axis channel setter functions.
+   * @param axis    The axis to set the channel for.
+   * @param channel The channel to set the axis to.
+   */
+  @Deprecated
+  public void setAxisChannel(AxisType axis, int channel) {
+    m_axes[axis.value] = (byte) channel;
+  }
+
+  /**
+   * Get the channel currently associated with the X axis.
+   *
+   * @return The channel for the axis.
+   */
+  public int getXChannel() {
+    return m_axes[Axis.kX.value];
+  }
+
+  /**
+   * Get the channel currently associated with the Y axis.
+   *
+   * @return The channel for the axis.
+   */
+  public int getYChannel() {
+    return m_axes[Axis.kY.value];
+  }
+
+  /**
+   * Get the channel currently associated with the Z axis.
+   *
+   * @return The channel for the axis.
+   */
+  public int getZChannel() {
+    return m_axes[Axis.kZ.value];
+  }
+
+  /**
+   * Get the channel currently associated with the twist axis.
+   *
+   * @return The channel for the axis.
+   */
+  public int getTwistChannel() {
+    return m_axes[Axis.kTwist.value];
+  }
+
+  /**
+   * Get the channel currently associated with the throttle axis.
+   *
+   * @return The channel for the axis.
+   */
+  public int getThrottleChannel() {
+    return m_axes[Axis.kThrottle.value];
+  }
+
+  /**
+   * Get the channel currently associated with the specified axis.
+   *
+   * @deprecated Use the more specific axis channel getter functions.
+   * @param axis The axis to look up the channel for.
+   * @return The channel for the axis.
+   */
+  @Deprecated
+  public int getAxisChannel(AxisType axis) {
+    return m_axes[axis.value];
+  }
+
+  /**
+   * Get the X value of the joystick. This depends on the mapping of the joystick connected to the
+   * current port.
+   *
+   * @param hand Unused
+   * @return The X value of the joystick.
+   */
+  @Override
+  public final double getX(Hand hand) {
+    return getRawAxis(m_axes[Axis.kX.value]);
+  }
+
+  /**
+   * Get the Y value of the joystick. This depends on the mapping of the joystick connected to the
+   * current port.
+   *
+   * @param hand Unused
+   * @return The Y value of the joystick.
+   */
+  @Override
+  public final double getY(Hand hand) {
+    return getRawAxis(m_axes[Axis.kY.value]);
+  }
+
+  /**
+   * Get the z position of the HID.
+   *
+   * @return the z position
+   */
+  public double getZ() {
+    return getRawAxis(m_axes[Axis.kZ.value]);
+  }
+
+  /**
+   * Get the twist value of the current joystick. This depends on the mapping of the joystick
+   * connected to the current port.
+   *
+   * @return The Twist value of the joystick.
+   */
+  public double getTwist() {
+    return getRawAxis(m_axes[Axis.kTwist.value]);
+  }
+
+  /**
+   * Get the throttle value of the current joystick. This depends on the mapping of the joystick
+   * connected to the current port.
+   *
+   * @return The Throttle value of the joystick.
+   */
+  public double getThrottle() {
+    return getRawAxis(m_axes[Axis.kThrottle.value]);
+  }
+
+  /**
+   * For the current joystick, return the axis determined by the argument.
+   *
+   * <p>This is for cases where the joystick axis is returned programmatically, otherwise one of the
+   * previous functions would be preferable (for example getX()).
+   *
+   * @deprecated Use the more specific axis getter functions.
+   * @param axis The axis to read.
+   * @return The value of the axis.
+   */
+  @Deprecated
+  public double getAxis(final AxisType axis) {
+    switch (axis) {
+      case kX:
+        return getX();
+      case kY:
+        return getY();
+      case kZ:
+        return getZ();
+      case kTwist:
+        return getTwist();
+      case kThrottle:
+        return getThrottle();
+      default:
+        return 0.0;
+    }
+  }
+
+  /**
+   * Read the state of the trigger on the joystick.
+   *
+   * @return The state of the trigger.
+   */
+  public boolean getTrigger() {
+    return getRawButton(Button.kTrigger.value);
+  }
+
+  /**
+   * Whether the trigger was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getTriggerPressed() {
+    return getRawButtonPressed(Button.kTrigger.value);
+  }
+
+  /**
+   * Whether the trigger was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getTriggerReleased() {
+    return getRawButtonReleased(Button.kTrigger.value);
+  }
+
+  /**
+   * Read the state of the top button on the joystick.
+   *
+   * @return The state of the top button.
+   */
+  public boolean getTop() {
+    return getRawButton(Button.kTop.value);
+  }
+
+  /**
+   * Whether the top button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getTopPressed() {
+    return getRawButtonPressed(Button.kTop.value);
+  }
+
+  /**
+   * Whether the top button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getTopReleased() {
+    return getRawButtonReleased(Button.kTop.value);
+  }
+
+  /**
+   * Get buttons based on an enumerated type.
+   *
+   * <p>The button type will be looked up in the list of buttons and then read.
+   *
+   * @deprecated Use Button enum values instead of ButtonType.
+   * @param button The type of button to read.
+   * @return The state of the button.
+   */
+  @Deprecated
+  public boolean getButton(ButtonType button) {
+    return getRawButton(button.value);
+  }
+
+  /**
+   * Get the magnitude of the direction vector formed by the joystick's current position relative to
+   * its origin.
+   *
+   * @return The magnitude of the direction vector
+   */
+  public double getMagnitude() {
+    return Math.sqrt(Math.pow(getX(), 2) + Math.pow(getY(), 2));
+  }
+
+  /**
+   * Get the direction of the vector formed by the joystick and its origin in radians.
+   *
+   * @return The direction of the vector in radians
+   */
+  public double getDirectionRadians() {
+    return Math.atan2(getX(), -getY());
+  }
+
+  /**
+   * Get the direction of the vector formed by the joystick and its origin in degrees.
+   *
+   * @return The direction of the vector in degrees
+   */
+  public double getDirectionDegrees() {
+    return Math.toDegrees(getDirectionRadians());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/JoystickBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/JoystickBase.java
new file mode 100644
index 0000000..56d4eba
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/JoystickBase.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.wpilibj;
+
+/**
+ * JoystickBase Interface.
+ *
+ * @deprecated Inherit directly from GenericHID instead.
+ */
+@Deprecated
+public abstract class JoystickBase extends GenericHID {
+  public JoystickBase(int port) {
+    super(port);
+  }
+
+  /**
+   * Get the z position of the HID.
+   *
+   * @param hand which hand, left or right
+   * @return the z position
+   */
+  public abstract double getZ(Hand hand);
+
+  public double getZ() {
+    return getZ(Hand.kRight);
+  }
+
+  /**
+   * Get the twist value.
+   *
+   * @return the twist value
+   */
+  public abstract double getTwist();
+
+  /**
+   * Get the throttle.
+   *
+   * @return the throttle value
+   */
+  public abstract double getThrottle();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafety.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafety.java
new file mode 100644
index 0000000..80b86ff
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafety.java
@@ -0,0 +1,29 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * Shuts off motors when their outputs aren't updated often enough.
+ */
+public interface MotorSafety {
+  double DEFAULT_SAFETY_EXPIRATION = 0.1;
+
+  void setExpiration(double timeout);
+
+  double getExpiration();
+
+  boolean isAlive();
+
+  void stopMotor();
+
+  void setSafetyEnabled(boolean enabled);
+
+  boolean isSafetyEnabled();
+
+  String getDescription();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafetyHelper.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafetyHelper.java
new file mode 100644
index 0000000..f9c6645
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafetyHelper.java
@@ -0,0 +1,150 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * The MotorSafetyHelper object is constructed for every object that wants to implement the Motor
+ * Safety protocol. The helper object has the code to actually do the timing and call the motors
+ * Stop() method when the timeout expires. The motor object is expected to call the Feed() method
+ * whenever the motors value is updated.
+ */
+public final class MotorSafetyHelper {
+  private double m_expiration;
+  private boolean m_enabled;
+  private double m_stopTime;
+  private final Object m_thisMutex = new Object();
+  private final MotorSafety m_safeObject;
+  private static final Set<MotorSafetyHelper> m_helperList = new LinkedHashSet<>();
+  private static final Object m_listMutex = new Object();
+
+  /**
+   * The constructor for a MotorSafetyHelper object. The helper object is constructed for every
+   * object that wants to implement the Motor Safety protocol. The helper object has the code to
+   * actually do the timing and call the motors Stop() method when the timeout expires. The motor
+   * object is expected to call the Feed() method whenever the motors value is updated.
+   *
+   * @param safeObject a pointer to the motor object implementing MotorSafety. This is used to call
+   *                   the Stop() method on the motor.
+   */
+  public MotorSafetyHelper(MotorSafety safeObject) {
+    m_safeObject = safeObject;
+    m_enabled = false;
+    m_expiration = MotorSafety.DEFAULT_SAFETY_EXPIRATION;
+    m_stopTime = Timer.getFPGATimestamp();
+
+    synchronized (m_listMutex) {
+      m_helperList.add(this);
+    }
+  }
+
+  /**
+   * Feed the motor safety object. Resets the timer on this object that is used to do the timeouts.
+   */
+  public void feed() {
+    synchronized (m_thisMutex) {
+      m_stopTime = Timer.getFPGATimestamp() + m_expiration;
+    }
+  }
+
+  /**
+   * Set the expiration time for the corresponding motor safety object.
+   *
+   * @param expirationTime The timeout value in seconds.
+   */
+  public void setExpiration(double expirationTime) {
+    synchronized (m_thisMutex) {
+      m_expiration = expirationTime;
+    }
+  }
+
+  /**
+   * Retrieve the timeout value for the corresponding motor safety object.
+   *
+   * @return the timeout value in seconds.
+   */
+  public double getExpiration() {
+    synchronized (m_thisMutex) {
+      return m_expiration;
+    }
+  }
+
+  /**
+   * Determine of the motor is still operating or has timed out.
+   *
+   * @return a true value if the motor is still operating normally and hasn't timed out.
+   */
+  public boolean isAlive() {
+    synchronized (m_thisMutex) {
+      return !m_enabled || m_stopTime > Timer.getFPGATimestamp();
+    }
+  }
+
+  /**
+   * Check if this motor has exceeded its timeout. This method is called periodically to determine
+   * if this motor has exceeded its timeout value. If it has, the stop method is called, and the
+   * motor is shut down until its value is updated again.
+   */
+  public void check() {
+    boolean enabled;
+    double stopTime;
+
+    synchronized (m_thisMutex) {
+      enabled = m_enabled;
+      stopTime = m_stopTime;
+    }
+
+    if (!enabled || RobotState.isDisabled() || RobotState.isTest()) {
+      return;
+    }
+    if (stopTime < Timer.getFPGATimestamp()) {
+      DriverStation.reportError(m_safeObject.getDescription() + "... Output not updated often "
+          + "enough.", false);
+
+      m_safeObject.stopMotor();
+    }
+  }
+
+  /**
+   * Enable/disable motor safety for this device Turn on and off the motor safety option for this
+   * PWM object.
+   *
+   * @param enabled True if motor safety is enforced for this object
+   */
+  public void setSafetyEnabled(boolean enabled) {
+    synchronized (m_thisMutex) {
+      m_enabled = enabled;
+    }
+  }
+
+  /**
+   * Return the state of the motor safety enabled flag Return if the motor safety is currently
+   * enabled for this device.
+   *
+   * @return True if motor safety is enforced for this device
+   */
+  public boolean isSafetyEnabled() {
+    synchronized (m_thisMutex) {
+      return m_enabled;
+    }
+  }
+
+  /**
+   * Check the motors to see if any have timed out. This static method is called periodically to
+   * poll all the motors and stop any that have timed out.
+   */
+  public static void checkMotors() {
+    synchronized (m_listMutex) {
+      for (MotorSafetyHelper elem : m_helperList) {
+        elem.check();
+      }
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/NamedSendable.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/NamedSendable.java
new file mode 100644
index 0000000..0d88114
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/NamedSendable.java
@@ -0,0 +1,43 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * The interface for sendable objects that gives the sendable a default name in the Smart
+ * Dashboard.
+ * @deprecated Use Sendable directly instead
+ */
+@Deprecated
+public interface NamedSendable extends Sendable {
+
+  /**
+   * The name of the subtable.
+   *
+   * @return the name of the subtable of SmartDashboard that the Sendable object will use.
+   */
+  String getName();
+
+  @Override
+  default void setName(String name) {
+  }
+
+  @Override
+  default String getSubsystem() {
+    return "";
+  }
+
+  @Override
+  default void setSubsystem(String subsystem) {
+  }
+
+  @Override
+  default void initSendable(SendableBuilder builder) {
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java
new file mode 100644
index 0000000..427cb59
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java
@@ -0,0 +1,205 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Nidec Brushless Motor.
+ */
+public class NidecBrushless extends SendableBase implements SpeedController, MotorSafety, Sendable {
+  private final MotorSafetyHelper m_safetyHelper;
+  private boolean m_isInverted = false;
+  private DigitalOutput m_dio;
+  private PWM m_pwm;
+  private volatile double m_speed = 0.0;
+  private volatile boolean m_disabled = false;
+
+  /**
+   * Constructor.
+   *
+   * @param pwmChannel The PWM channel that the Nidec Brushless controller is attached to.
+   *                   0-9 are on-board, 10-19 are on the MXP port
+   * @param dioChannel The DIO channel that the Nidec Brushless controller is attached to.
+   *                   0-9 are on-board, 10-25 are on the MXP port
+   */
+  public NidecBrushless(final int pwmChannel, final int dioChannel) {
+    m_safetyHelper = new MotorSafetyHelper(this);
+    m_safetyHelper.setExpiration(0.0);
+    m_safetyHelper.setSafetyEnabled(false);
+
+    // the dio controls the output (in PWM mode)
+    m_dio = new DigitalOutput(dioChannel);
+    addChild(m_dio);
+    m_dio.setPWMRate(15625);
+    m_dio.enablePWM(0.5);
+
+    // the pwm enables the controller
+    m_pwm = new PWM(pwmChannel);
+    addChild(m_pwm);
+
+    HAL.report(tResourceType.kResourceType_NidecBrushless, pwmChannel);
+    setName("Nidec Brushless", pwmChannel);
+  }
+
+  /**
+   * Free the resources used by this object.
+   */
+  @Override
+  public void free() {
+    super.free();
+    m_dio.free();
+    m_pwm.free();
+  }
+
+  /**
+   * Set the PWM value.
+   *
+   * <p>The PWM value is set using a range of -1.0 to 1.0, appropriately scaling the value for the
+   * FPGA.
+   *
+   * @param speed The speed value between -1.0 and 1.0 to set.
+   */
+  @Override
+  public void set(double speed) {
+    if (!m_disabled) {
+      m_speed = speed;
+      m_dio.updateDutyCycle(0.5 + 0.5 * (m_isInverted ? -speed : speed));
+      m_pwm.setRaw(0xffff);
+    }
+    m_safetyHelper.feed();
+  }
+
+  /**
+   * Get the recently set value of the PWM.
+   *
+   * @return The most recently set value for the PWM between -1.0 and 1.0.
+   */
+  @Override
+  public double get() {
+    return m_speed;
+  }
+
+  @Override
+  public void setInverted(boolean isInverted) {
+    m_isInverted = isInverted;
+  }
+
+  @Override
+  public boolean getInverted() {
+    return m_isInverted;
+  }
+
+  /**
+   * Write out the PID value as seen in the PIDOutput base object.
+   *
+   * @param output Write out the PWM value as was found in the PIDController
+   */
+  @Override
+  public void pidWrite(double output) {
+    set(output);
+  }
+
+  /**
+   * Set the safety expiration time.
+   *
+   * @param timeout The timeout (in seconds) for this motor object
+   */
+  @Override
+  public void setExpiration(double timeout) {
+    m_safetyHelper.setExpiration(timeout);
+  }
+
+  /**
+   * Return the safety expiration time.
+   *
+   * @return The expiration time value.
+   */
+  @Override
+  public double getExpiration() {
+    return m_safetyHelper.getExpiration();
+  }
+
+  /**
+   * Check if the motor is currently alive or stopped due to a timeout.
+   *
+   * @return a bool value that is true if the motor has NOT timed out and should still be running.
+   */
+  @Override
+  public boolean isAlive() {
+    return m_safetyHelper.isAlive();
+  }
+
+  /**
+   * Stop the motor. This is called by the MotorSafetyHelper object
+   * when it has a timeout for this PWM and needs to stop it from running.
+   * Calling set() will re-enable the motor.
+   */
+  @Override
+  public void stopMotor() {
+    m_dio.updateDutyCycle(0.5);
+    m_pwm.setDisabled();
+  }
+
+  /**
+   * Check if motor safety is enabled.
+   *
+   * @return True if motor safety is enforced for this object
+   */
+  @Override
+  public boolean isSafetyEnabled() {
+    return m_safetyHelper.isSafetyEnabled();
+  }
+
+  @Override
+  public void setSafetyEnabled(boolean enabled) {
+    m_safetyHelper.setSafetyEnabled(enabled);
+  }
+
+  @Override
+  public String getDescription() {
+    return "Nidec " + getChannel();
+  }
+
+  /**
+   * Disable the motor.  The enable() function must be called to re-enable
+   * the motor.
+   */
+  @Override
+  public void disable() {
+    m_disabled = true;
+    m_dio.updateDutyCycle(0.5);
+    m_pwm.setDisabled();
+  }
+
+  /**
+   * Re-enable the motor after disable() has been called.  The set()
+   * function must be called to set a new motor speed.
+   */
+  public void enable() {
+    m_disabled = false;
+  }
+
+  /**
+   * Gets the channel number associated with the object.
+   *
+   * @return The channel number.
+   */
+  public int getChannel() {
+    return m_pwm.getChannel();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Nidec Brushless");
+    builder.setSafeState(this::stopMotor);
+    builder.addDoubleProperty("Value", this::get, this::set);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Notifier.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Notifier.java
new file mode 100644
index 0000000..89ee185
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Notifier.java
@@ -0,0 +1,165 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+import edu.wpi.first.wpilibj.hal.NotifierJNI;
+
+public class Notifier {
+  // The thread waiting on the HAL alarm.
+  private final Thread m_thread;
+  // The lock for the process information.
+  private final ReentrantLock m_processLock = new ReentrantLock();
+  // The C pointer to the notifier object. We don't use it directly, it is
+  // just passed to the JNI bindings.
+  private final AtomicInteger m_notifier = new AtomicInteger();
+  // The time, in microseconds, at which the corresponding handler should be
+  // called. Has the same zero as Utility.getFPGATime().
+  private double m_expirationTime = 0;
+  // The handler passed in by the user which should be called at the
+  // appropriate interval.
+  private Runnable m_handler;
+  // Whether we are calling the handler just once or periodically.
+  private boolean m_periodic = false;
+  // If periodic, the period of the calling; if just once, stores how long it
+  // is until we call the handler.
+  private double m_period = 0;
+
+  @Override
+  @SuppressWarnings("NoFinalizer")
+  protected void finalize() {
+    int handle = m_notifier.getAndSet(0);
+    NotifierJNI.stopNotifier(handle);
+    // Join the thread to ensure the handler has exited.
+    if (m_thread.isAlive()) {
+      try {
+        m_thread.interrupt();
+        m_thread.join();
+      } catch (InterruptedException ex) {
+        Thread.currentThread().interrupt();
+      }
+    }
+    NotifierJNI.cleanNotifier(handle);
+  }
+
+  /**
+   * Update the alarm hardware to reflect the next alarm.
+   */
+  private void updateAlarm() {
+    int notifier = m_notifier.get();
+    if (notifier == 0) {
+      return;
+    }
+    NotifierJNI.updateNotifierAlarm(notifier, (long) (m_expirationTime * 1e6));
+  }
+
+  /**
+   * Create a Notifier for timer event notification.
+   *
+   * @param run The handler that is called at the notification time which is set using StartSingle
+   *            or StartPeriodic.
+   */
+  public Notifier(Runnable run) {
+    m_handler = run;
+    m_notifier.set(NotifierJNI.initializeNotifier());
+
+    m_thread = new Thread(() -> {
+      while (!Thread.interrupted()) {
+        int notifier = m_notifier.get();
+        if (notifier == 0) {
+          break;
+        }
+        long curTime = NotifierJNI.waitForNotifierAlarm(notifier);
+        if (curTime == 0) {
+          break;
+        }
+
+        Runnable handler = null;
+        m_processLock.lock();
+        try {
+          handler = m_handler;
+          if (m_periodic) {
+            m_expirationTime += m_period;
+            updateAlarm();
+          }
+        } finally {
+          m_processLock.unlock();
+        }
+
+        if (handler != null) {
+          handler.run();
+        }
+      }
+    });
+    m_thread.setDaemon(true);
+    m_thread.start();
+  }
+
+  /**
+   * Change the handler function.
+   *
+   * @param handler Handler
+   */
+  public void setHandler(Runnable handler) {
+    m_processLock.lock();
+    try {
+      m_handler = handler;
+    } finally {
+      m_processLock.unlock();
+    }
+  }
+
+  /**
+   * Register for single event notification. A timer event is queued for a single event after the
+   * specified delay.
+   *
+   * @param delay Seconds to wait before the handler is called.
+   */
+  public void startSingle(double delay) {
+    m_processLock.lock();
+    try {
+      m_periodic = false;
+      m_period = delay;
+      m_expirationTime = RobotController.getFPGATime() * 1e-6 + delay;
+      updateAlarm();
+    } finally {
+      m_processLock.unlock();
+    }
+  }
+
+  /**
+   * Register for periodic event notification. A timer event is queued for periodic event
+   * notification. Each time the interrupt occurs, the event will be immediately requeued for the
+   * same time interval.
+   *
+   * @param period Period in seconds to call the handler starting one period after the call to this
+   *               method.
+   */
+  public void startPeriodic(double period) {
+    m_processLock.lock();
+    try {
+      m_periodic = true;
+      m_period = period;
+      m_expirationTime = RobotController.getFPGATime() * 1e-6 + period;
+      updateAlarm();
+    } finally {
+      m_processLock.unlock();
+    }
+  }
+
+  /**
+   * Stop timer events from occurring. Stop any repeating timer events from occurring. This will
+   * also remove any single notification events from the queue. If a timer-based call to the
+   * registered handler is in progress, this function will block until the handler call is complete.
+   */
+  public void stop() {
+    NotifierJNI.cancelNotifierAlarm(m_notifier.get());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDController.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDController.java
new file mode 100644
index 0000000..2782dbb
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDController.java
@@ -0,0 +1,914 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.util.TimerTask;
+import java.util.concurrent.locks.ReentrantLock;
+
+import edu.wpi.first.wpilibj.filters.LinearDigitalFilter;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+import edu.wpi.first.wpilibj.util.BoundaryException;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Class implements a PID Control Loop.
+ *
+ * <p>Creates a separate thread which reads the given PIDSource and takes care of the integral
+ * calculations, as well as writing the given PIDOutput.
+ *
+ * <p>This feedback controller runs in discrete time, so time deltas are not used in the integral
+ * and derivative calculations. Therefore, the sample rate affects the controller's behavior for a
+ * given set of PID constants.
+ */
+public class PIDController extends SendableBase implements PIDInterface, Sendable, Controller {
+  public static final double kDefaultPeriod = .05;
+  private static int instances = 0;
+  @SuppressWarnings("MemberName")
+  private double m_P; // factor for "proportional" control
+  @SuppressWarnings("MemberName")
+  private double m_I; // factor for "integral" control
+  @SuppressWarnings("MemberName")
+  private double m_D; // factor for "derivative" control
+  @SuppressWarnings("MemberName")
+  private double m_F; // factor for feedforward term
+  private double m_maximumOutput = 1.0; // |maximum output|
+  private double m_minimumOutput = -1.0; // |minimum output|
+  private double m_maximumInput = 0.0; // maximum input - limit setpoint to this
+  private double m_minimumInput = 0.0; // minimum input - limit setpoint to this
+  private double m_inputRange = 0.0; // input range - difference between maximum and minimum
+  // do the endpoints wrap around? eg. Absolute encoder
+  private boolean m_continuous = false;
+  private boolean m_enabled = false; // is the pid controller enabled
+  // the prior error (used to compute velocity)
+  private double m_prevError = 0.0;
+  // the sum of the errors for use in the integral calc
+  private double m_totalError = 0.0;
+  // the tolerance object used to check if on target
+  private Tolerance m_tolerance;
+  private double m_setpoint = 0.0;
+  private double m_prevSetpoint = 0.0;
+  @SuppressWarnings("PMD.UnusedPrivateField")
+  private double m_error = 0.0;
+  private double m_result = 0.0;
+  private double m_period = kDefaultPeriod;
+
+  PIDSource m_origSource;
+  LinearDigitalFilter m_filter;
+
+  ReentrantLock m_thisMutex = new ReentrantLock();
+
+  // Ensures when disable() is called, pidWrite() won't run if calculate()
+  // is already running at that time.
+  ReentrantLock m_pidWriteMutex = new ReentrantLock();
+
+  protected PIDSource m_pidInput;
+  protected PIDOutput m_pidOutput;
+  java.util.Timer m_controlLoop;
+  Timer m_setpointTimer;
+
+  /**
+   * Tolerance is the type of tolerance used to specify if the PID controller is on target.
+   *
+   * <p>The various implementations of this class such as PercentageTolerance and AbsoluteTolerance
+   * specify types of tolerance specifications to use.
+   */
+  public interface Tolerance {
+    boolean onTarget();
+  }
+
+  /**
+   * Used internally for when Tolerance hasn't been set.
+   */
+  public class NullTolerance implements Tolerance {
+    @Override
+    public boolean onTarget() {
+      throw new RuntimeException("No tolerance value set when calling onTarget().");
+    }
+  }
+
+  public class PercentageTolerance implements Tolerance {
+    private final double m_percentage;
+
+    PercentageTolerance(double value) {
+      m_percentage = value;
+    }
+
+    @Override
+    public boolean onTarget() {
+      return Math.abs(getError()) < m_percentage / 100 * m_inputRange;
+    }
+  }
+
+  public class AbsoluteTolerance implements Tolerance {
+    private final double m_value;
+
+    AbsoluteTolerance(double value) {
+      m_value = value;
+    }
+
+    @Override
+    public boolean onTarget() {
+      return Math.abs(getError()) < m_value;
+    }
+  }
+
+  private class PIDTask extends TimerTask {
+    private PIDController m_controller;
+
+    PIDTask(PIDController controller) {
+      requireNonNull(controller, "Given PIDController was null");
+
+      m_controller = controller;
+    }
+
+    @Override
+    public void run() {
+      m_controller.calculate();
+    }
+  }
+
+  /**
+   * Allocate a PID object with the given constants for P, I, D, and F.
+   *
+   * @param Kp     the proportional coefficient
+   * @param Ki     the integral coefficient
+   * @param Kd     the derivative coefficient
+   * @param Kf     the feed forward term
+   * @param source The PIDSource object that is used to get values
+   * @param output The PIDOutput object that is set to the output percentage
+   * @param period the loop time for doing calculations. This particularly effects calculations of
+   *               the integral and differential terms. The default is 50ms.
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDController(double Kp, double Ki, double Kd, double Kf, PIDSource source,
+                       PIDOutput output, double period) {
+    super(false);
+    requireNonNull(source, "Null PIDSource was given");
+    requireNonNull(output, "Null PIDOutput was given");
+
+    m_controlLoop = new java.util.Timer();
+    m_setpointTimer = new Timer();
+    m_setpointTimer.start();
+
+    m_P = Kp;
+    m_I = Ki;
+    m_D = Kd;
+    m_F = Kf;
+
+    // Save original source
+    m_origSource = source;
+
+    // Create LinearDigitalFilter with original source as its source argument
+    m_filter = LinearDigitalFilter.movingAverage(m_origSource, 1);
+    m_pidInput = m_filter;
+
+    m_pidOutput = output;
+    m_period = period;
+
+    m_controlLoop.schedule(new PIDTask(this), 0L, (long) (m_period * 1000));
+
+    instances++;
+    HLUsageReporting.reportPIDController(instances);
+    m_tolerance = new NullTolerance();
+    setName("PIDController", instances);
+  }
+
+  /**
+   * Allocate a PID object with the given constants for P, I, D and period.
+   *
+   * @param Kp     the proportional coefficient
+   * @param Ki     the integral coefficient
+   * @param Kd     the derivative coefficient
+   * @param source the PIDSource object that is used to get values
+   * @param output the PIDOutput object that is set to the output percentage
+   * @param period the loop time for doing calculations. This particularly effects calculations of
+   *               the integral and differential terms. The default is 50ms.
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDController(double Kp, double Ki, double Kd, PIDSource source, PIDOutput output,
+                       double period) {
+    this(Kp, Ki, Kd, 0.0, source, output, period);
+  }
+
+  /**
+   * Allocate a PID object with the given constants for P, I, D, using a 50ms period.
+   *
+   * @param Kp     the proportional coefficient
+   * @param Ki     the integral coefficient
+   * @param Kd     the derivative coefficient
+   * @param source The PIDSource object that is used to get values
+   * @param output The PIDOutput object that is set to the output percentage
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDController(double Kp, double Ki, double Kd, PIDSource source, PIDOutput output) {
+    this(Kp, Ki, Kd, source, output, kDefaultPeriod);
+  }
+
+  /**
+   * Allocate a PID object with the given constants for P, I, D, using a 50ms period.
+   *
+   * @param Kp     the proportional coefficient
+   * @param Ki     the integral coefficient
+   * @param Kd     the derivative coefficient
+   * @param Kf     the feed forward term
+   * @param source The PIDSource object that is used to get values
+   * @param output The PIDOutput object that is set to the output percentage
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDController(double Kp, double Ki, double Kd, double Kf, PIDSource source,
+                       PIDOutput output) {
+    this(Kp, Ki, Kd, Kf, source, output, kDefaultPeriod);
+  }
+
+  /**
+   * Free the PID object.
+   */
+  @Override
+  public void free() {
+    super.free();
+    m_controlLoop.cancel();
+    m_thisMutex.lock();
+    try {
+      m_pidOutput = null;
+      m_pidInput = null;
+      m_controlLoop = null;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Read the input, calculate the output accordingly, and write to the output. This should only be
+   * called by the PIDTask and is created during initialization.
+   */
+  @SuppressWarnings("LocalVariableName")
+  protected void calculate() {
+    if (m_origSource == null || m_pidOutput == null) {
+      return;
+    }
+
+    boolean enabled;
+
+    m_thisMutex.lock();
+    try {
+      enabled = m_enabled;
+    } finally {
+      m_thisMutex.unlock();
+    }
+
+    if (enabled) {
+      double input;
+
+      // Storage for function inputs
+      PIDSourceType pidSourceType;
+      double P;
+      double I;
+      double D;
+      double feedForward = calculateFeedForward();
+      double minimumOutput;
+      double maximumOutput;
+
+      // Storage for function input-outputs
+      double prevError;
+      double error;
+      double totalError;
+
+      m_thisMutex.lock();
+      try {
+        input = m_pidInput.pidGet();
+
+        pidSourceType = m_pidInput.getPIDSourceType();
+        P = m_P;
+        I = m_I;
+        D = m_D;
+        minimumOutput = m_minimumOutput;
+        maximumOutput = m_maximumOutput;
+
+        prevError = m_prevError;
+        error = getContinuousError(m_setpoint - input);
+        totalError = m_totalError;
+      } finally {
+        m_thisMutex.unlock();
+      }
+
+      // Storage for function outputs
+      double result;
+
+      if (pidSourceType.equals(PIDSourceType.kRate)) {
+        if (P != 0) {
+          totalError = clamp(totalError + error, minimumOutput / P,
+              maximumOutput / P);
+        }
+
+        result = P * totalError + D * error + feedForward;
+      } else {
+        if (I != 0) {
+          totalError = clamp(totalError + error, minimumOutput / I,
+              maximumOutput / I);
+        }
+
+        result = P * error + I * totalError + D * (error - prevError)
+            + feedForward;
+      }
+
+      result = clamp(result, minimumOutput, maximumOutput);
+
+      // Ensures m_enabled check and pidWrite() call occur atomically
+      m_pidWriteMutex.lock();
+      try {
+        m_thisMutex.lock();
+        try {
+          if (m_enabled) {
+            // Don't block other PIDController operations on pidWrite()
+            m_thisMutex.unlock();
+
+            m_pidOutput.pidWrite(result);
+          }
+        } finally {
+          if (m_thisMutex.isHeldByCurrentThread()) {
+            m_thisMutex.unlock();
+          }
+        }
+      } finally {
+        m_pidWriteMutex.unlock();
+      }
+
+      m_thisMutex.lock();
+      try {
+        m_prevError = error;
+        m_error = error;
+        m_totalError = totalError;
+        m_result = result;
+      } finally {
+        m_thisMutex.unlock();
+      }
+    }
+  }
+
+  /**
+   * Calculate the feed forward term.
+   *
+   * <p>Both of the provided feed forward calculations are velocity feed forwards. If a different
+   * feed forward calculation is desired, the user can override this function and provide his or
+   * her own. This function  does no synchronization because the PIDController class only calls it
+   * in synchronized code, so be careful if calling it oneself.
+   *
+   * <p>If a velocity PID controller is being used, the F term should be set to 1 over the maximum
+   * setpoint for the output. If a position PID controller is being used, the F term should be set
+   * to 1 over the maximum speed for the output measured in setpoint units per this controller's
+   * update period (see the default period in this class's constructor).
+   */
+  protected double calculateFeedForward() {
+    if (m_pidInput.getPIDSourceType().equals(PIDSourceType.kRate)) {
+      return m_F * getSetpoint();
+    } else {
+      double temp = m_F * getDeltaSetpoint();
+      m_prevSetpoint = m_setpoint;
+      m_setpointTimer.reset();
+      return temp;
+    }
+  }
+
+  /**
+   * Set the PID Controller gain parameters. Set the proportional, integral, and differential
+   * coefficients.
+   *
+   * @param p Proportional coefficient
+   * @param i Integral coefficient
+   * @param d Differential coefficient
+   */
+  @SuppressWarnings("ParameterName")
+  public void setPID(double p, double i, double d) {
+    m_thisMutex.lock();
+    try {
+      m_P = p;
+      m_I = i;
+      m_D = d;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the PID Controller gain parameters. Set the proportional, integral, and differential
+   * coefficients.
+   *
+   * @param p Proportional coefficient
+   * @param i Integral coefficient
+   * @param d Differential coefficient
+   * @param f Feed forward coefficient
+   */
+  @SuppressWarnings("ParameterName")
+  public void setPID(double p, double i, double d, double f) {
+    m_thisMutex.lock();
+    try {
+      m_P = p;
+      m_I = i;
+      m_D = d;
+      m_F = f;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the Proportional coefficient of the PID controller gain.
+   *
+   * @param p Proportional coefficient
+   */
+  @SuppressWarnings("ParameterName")
+  public void setP(double p) {
+    m_thisMutex.lock();
+    try {
+      m_P = p;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the Integral coefficient of the PID controller gain.
+   *
+   * @param i Integral coefficient
+   */
+  @SuppressWarnings("ParameterName")
+  public void setI(double i) {
+    m_thisMutex.lock();
+    try {
+      m_I = i;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the Differential coefficient of the PID controller gain.
+   *
+   * @param d differential coefficient
+   */
+  @SuppressWarnings("ParameterName")
+  public void setD(double d) {
+    m_thisMutex.lock();
+    try {
+      m_D = d;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the Feed forward coefficient of the PID controller gain.
+   *
+   * @param f feed forward coefficient
+   */
+  @SuppressWarnings("ParameterName")
+  public void setF(double f) {
+    m_thisMutex.lock();
+    try {
+      m_F = f;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Get the Proportional coefficient.
+   *
+   * @return proportional coefficient
+   */
+  public double getP() {
+    m_thisMutex.lock();
+    try {
+      return m_P;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Get the Integral coefficient.
+   *
+   * @return integral coefficient
+   */
+  public double getI() {
+    m_thisMutex.lock();
+    try {
+      return m_I;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Get the Differential coefficient.
+   *
+   * @return differential coefficient
+   */
+  public double getD() {
+    m_thisMutex.lock();
+    try {
+      return m_D;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Get the Feed forward coefficient.
+   *
+   * @return feed forward coefficient
+   */
+  public double getF() {
+    m_thisMutex.lock();
+    try {
+      return m_F;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Return the current PID result This is always centered on zero and constrained the the max and
+   * min outs.
+   *
+   * @return the latest calculated output
+   */
+  public double get() {
+    m_thisMutex.lock();
+    try {
+      return m_result;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the PID controller to consider the input to be continuous, Rather then using the max and
+   * min input range as constraints, it considers them to be the same point and automatically
+   * calculates the shortest route to the setpoint.
+   *
+   * @param continuous Set to true turns on continuous, false turns off continuous
+   */
+  public void setContinuous(boolean continuous) {
+    if (continuous && m_inputRange <= 0) {
+      throw new RuntimeException("No input range set when calling setContinuous().");
+    }
+    m_thisMutex.lock();
+    try {
+      m_continuous = continuous;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the PID controller to consider the input to be continuous, Rather then using the max and
+   * min input range as constraints, it considers them to be the same point and automatically
+   * calculates the shortest route to the setpoint.
+   */
+  public void setContinuous() {
+    setContinuous(true);
+  }
+
+  /**
+   * Sets the maximum and minimum values expected from the input and setpoint.
+   *
+   * @param minimumInput the minimum value expected from the input
+   * @param maximumInput the maximum value expected from the input
+   */
+  public void setInputRange(double minimumInput, double maximumInput) {
+    m_thisMutex.lock();
+    try {
+      if (minimumInput > maximumInput) {
+        throw new BoundaryException("Lower bound is greater than upper bound");
+      }
+      m_minimumInput = minimumInput;
+      m_maximumInput = maximumInput;
+      m_inputRange = maximumInput - minimumInput;
+    } finally {
+      m_thisMutex.unlock();
+    }
+
+    setSetpoint(m_setpoint);
+  }
+
+  /**
+   * Sets the minimum and maximum values to write.
+   *
+   * @param minimumOutput the minimum percentage to write to the output
+   * @param maximumOutput the maximum percentage to write to the output
+   */
+  public void setOutputRange(double minimumOutput, double maximumOutput) {
+    m_thisMutex.lock();
+    try {
+      if (minimumOutput > maximumOutput) {
+        throw new BoundaryException("Lower bound is greater than upper bound");
+      }
+      m_minimumOutput = minimumOutput;
+      m_maximumOutput = maximumOutput;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the setpoint for the PIDController.
+   *
+   * @param setpoint the desired setpoint
+   */
+  public void setSetpoint(double setpoint) {
+    m_thisMutex.lock();
+    try {
+      if (m_maximumInput > m_minimumInput) {
+        if (setpoint > m_maximumInput) {
+          m_setpoint = m_maximumInput;
+        } else if (setpoint < m_minimumInput) {
+          m_setpoint = m_minimumInput;
+        } else {
+          m_setpoint = setpoint;
+        }
+      } else {
+        m_setpoint = setpoint;
+      }
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Returns the current setpoint of the PIDController.
+   *
+   * @return the current setpoint
+   */
+  public double getSetpoint() {
+    m_thisMutex.lock();
+    try {
+      return m_setpoint;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Returns the change in setpoint over time of the PIDController.
+   *
+   * @return the change in setpoint over time
+   */
+  public double getDeltaSetpoint() {
+    m_thisMutex.lock();
+    try {
+      return (m_setpoint - m_prevSetpoint) / m_setpointTimer.get();
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Returns the current difference of the input from the setpoint.
+   *
+   * @return the current error
+   */
+  public double getError() {
+    m_thisMutex.lock();
+    try {
+      return getContinuousError(getSetpoint() - m_pidInput.pidGet());
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Returns the current difference of the error over the past few iterations. You can specify the
+   * number of iterations to average with setToleranceBuffer() (defaults to 1). getAvgError() is
+   * used for the onTarget() function.
+   *
+   * @deprecated Use getError(), which is now already filtered.
+   * @return     the current average of the error
+   */
+  @Deprecated
+  public double getAvgError() {
+    m_thisMutex.lock();
+    try {
+      return getError();
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Sets what type of input the PID controller will use.
+   *
+   * @param pidSource the type of input
+   */
+  void setPIDSourceType(PIDSourceType pidSource) {
+    m_pidInput.setPIDSourceType(pidSource);
+  }
+
+  /**
+   * Returns the type of input the PID controller is using.
+   *
+   * @return the PID controller input type
+   */
+  PIDSourceType getPIDSourceType() {
+    return m_pidInput.getPIDSourceType();
+  }
+
+  /**
+   * Set the PID tolerance using a Tolerance object. Tolerance can be specified as a percentage of
+   * the range or as an absolute value. The Tolerance object encapsulates those options in an
+   * object. Use it by creating the type of tolerance that you want to use: setTolerance(new
+   * PIDController.AbsoluteTolerance(0.1))
+   *
+   * @deprecated      Use setPercentTolerance() instead.
+   * @param tolerance A tolerance object of the right type, e.g. PercentTolerance or
+   *                  AbsoluteTolerance
+   */
+  @Deprecated
+  public void setTolerance(Tolerance tolerance) {
+    m_tolerance = tolerance;
+  }
+
+  /**
+   * Set the absolute error which is considered tolerable for use with OnTarget.
+   *
+   * @param absvalue absolute error which is tolerable in the units of the input object
+   */
+  public void setAbsoluteTolerance(double absvalue) {
+    m_thisMutex.lock();
+    try {
+      m_tolerance = new AbsoluteTolerance(absvalue);
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the percentage error which is considered tolerable for use with OnTarget. (Input of 15.0 =
+   * 15 percent)
+   *
+   * @param percentage percent error which is tolerable
+   */
+  public void setPercentTolerance(double percentage) {
+    m_thisMutex.lock();
+    try {
+      m_tolerance = new PercentageTolerance(percentage);
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the number of previous error samples to average for tolerancing. When determining whether a
+   * mechanism is on target, the user may want to use a rolling average of previous measurements
+   * instead of a precise position or velocity. This is useful for noisy sensors which return a few
+   * erroneous measurements when the mechanism is on target. However, the mechanism will not
+   * register as on target for at least the specified bufLength cycles.
+   *
+   * @deprecated      Use a LinearDigitalFilter as the input.
+   * @param bufLength Number of previous cycles to average.
+   */
+  @Deprecated
+  public void setToleranceBuffer(int bufLength) {
+    m_thisMutex.lock();
+    try {
+      m_filter = LinearDigitalFilter.movingAverage(m_origSource, bufLength);
+      m_pidInput = m_filter;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Return true if the error is within the percentage of the total input range, determined by
+   * setTolerance. This assumes that the maximum and minimum input were set using setInput.
+   *
+   * @return true if the error is less than the tolerance
+   */
+  public boolean onTarget() {
+    m_thisMutex.lock();
+    try {
+      return m_tolerance.onTarget();
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Begin running the PIDController.
+   */
+  @Override
+  public void enable() {
+    m_thisMutex.lock();
+    try {
+      m_enabled = true;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Stop running the PIDController, this sets the output to zero before stopping.
+   */
+  @Override
+  public void disable() {
+    // Ensures m_enabled check and pidWrite() call occur atomically
+    m_pidWriteMutex.lock();
+    try {
+      m_thisMutex.lock();
+      try {
+        m_enabled = false;
+      } finally {
+        m_thisMutex.unlock();
+      }
+
+      m_pidOutput.pidWrite(0);
+    } finally {
+      m_pidWriteMutex.unlock();
+    }
+  }
+
+  /**
+   * Set the enabled state of the PIDController.
+   */
+  public void setEnabled(boolean enable) {
+    if (enable) {
+      enable();
+    } else {
+      disable();
+    }
+  }
+
+  /**
+   * Return true if PIDController is enabled.
+   */
+  @Override
+  public boolean isEnabled() {
+    m_thisMutex.lock();
+    try {
+      return m_enabled;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  /**
+   * Reset the previous error,, the integral term, and disable the controller.
+   */
+  @Override
+  public void reset() {
+    disable();
+
+    m_thisMutex.lock();
+    try {
+      m_prevError = 0;
+      m_totalError = 0;
+      m_result = 0;
+    } finally {
+      m_thisMutex.unlock();
+    }
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("PIDController");
+    builder.setSafeState(this::reset);
+    builder.addDoubleProperty("p", this::getP, this::setP);
+    builder.addDoubleProperty("i", this::getI, this::setI);
+    builder.addDoubleProperty("d", this::getD, this::setD);
+    builder.addDoubleProperty("f", this::getF, this::setF);
+    builder.addDoubleProperty("setpoint", this::getSetpoint, this::setSetpoint);
+    builder.addBooleanProperty("enabled", this::isEnabled, this::setEnabled);
+  }
+
+  /**
+   * Wraps error around for continuous inputs. The original error is returned if continuous mode is
+   * disabled. This is an unsynchronized function.
+   *
+   * @param error The current error of the PID controller.
+   * @return Error for continuous inputs.
+   */
+  protected double getContinuousError(double error) {
+    if (m_continuous && m_inputRange > 0) {
+      error %= m_inputRange;
+      if (Math.abs(error) > m_inputRange / 2) {
+        if (error > 0) {
+          return error - m_inputRange;
+        } else {
+          return error + m_inputRange;
+        }
+      }
+    }
+
+    return error;
+  }
+
+  private static double clamp(double value, double low, double high) {
+    return Math.max(low, Math.min(value, high));
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDInterface.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDInterface.java
new file mode 100644
index 0000000..b3c3a32
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDInterface.java
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+@SuppressWarnings("SummaryJavadoc")
+public interface PIDInterface extends Controller {
+
+  @SuppressWarnings("ParameterName")
+  void setPID(double p, double i, double d);
+
+  double getP();
+
+  double getI();
+
+  double getD();
+
+  void setSetpoint(double setpoint);
+
+  double getSetpoint();
+
+  double getError();
+
+  void enable();
+
+  void disable();
+
+  boolean isEnabled();
+
+  void reset();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDOutput.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDOutput.java
new file mode 100644
index 0000000..dd6afbe
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDOutput.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.wpilibj;
+
+/**
+ * This interface allows PIDController to write it's results to its output.
+ */
+@FunctionalInterface
+public interface PIDOutput {
+
+  /**
+   * Set the output to the value calculated by PIDController.
+   *
+   * @param output the value calculated by PIDController
+   */
+  void pidWrite(double output);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSource.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSource.java
new file mode 100644
index 0000000..841a232
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSource.java
@@ -0,0 +1,34 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * This interface allows for PIDController to automatically read from this object.
+ */
+public interface PIDSource {
+  /**
+   * Set which parameter of the device you are using as a process control variable.
+   *
+   * @param pidSource An enum to select the parameter.
+   */
+  void setPIDSourceType(PIDSourceType pidSource);
+
+  /**
+   * Get which parameter of the device you are using as a process control variable.
+   *
+   * @return the currently selected PID source parameter
+   */
+  PIDSourceType getPIDSourceType();
+
+  /**
+   * Get the result to use in PIDController.
+   *
+   * @return the result to use in PIDController
+   */
+  double pidGet();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSourceType.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSourceType.java
new file mode 100644
index 0000000..31aa79a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSourceType.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+/**
+ * A description for the type of output value to provide to a PIDController.
+ */
+public enum PIDSourceType {
+  kDisplacement,
+  kRate
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWM.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWM.java
new file mode 100644
index 0000000..d609f75
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWM.java
@@ -0,0 +1,251 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.DIOJNI;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.PWMJNI;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Class implements the PWM generation in the FPGA.
+ *
+ * <p>The values supplied as arguments for PWM outputs range from -1.0 to 1.0. They are mapped to
+ * the hardware dependent values, in this case 0-2000 for the FPGA. Changes are immediately sent to
+ * the FPGA, and the update occurs at the next FPGA cycle (5.005ms). There is no delay.
+ *
+ * <p>As of revision 0.1.10 of the FPGA, the FPGA interprets the 0-2000 values as follows: - 2000 =
+ * maximum pulse width - 1999 to 1001 = linear scaling from "full forward" to "center" - 1000 =
+ * center value - 999 to 2 = linear scaling from "center" to "full reverse" - 1 = minimum pulse
+ * width (currently .5ms) - 0 = disabled (i.e. PWM output is held low)
+ */
+public class PWM extends SendableBase implements Sendable {
+  /**
+   * Represents the amount to multiply the minimum servo-pulse pwm period by.
+   */
+  public enum PeriodMultiplier {
+    /**
+     * Period Multiplier: don't skip pulses. PWM pulses occur every 5.005 ms
+     */
+    k1X,
+    /**
+     * Period Multiplier: skip every other pulse. PWM pulses occur every 10.010 ms
+     */
+    k2X,
+    /**
+     * Period Multiplier: skip three out of four pulses. PWM pulses occur every 20.020 ms
+     */
+    k4X
+  }
+
+  private int m_channel;
+  private int m_handle;
+
+  /**
+   * Allocate a PWM given a channel.
+   *
+   * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port
+   */
+  public PWM(final int channel) {
+    SensorBase.checkPWMChannel(channel);
+    m_channel = channel;
+
+    m_handle = PWMJNI.initializePWMPort(DIOJNI.getPort((byte) channel));
+
+    setDisabled();
+
+    PWMJNI.setPWMEliminateDeadband(m_handle, false);
+
+    HAL.report(tResourceType.kResourceType_PWM, channel);
+    setName("PWM", channel);
+  }
+
+  /**
+   * Free the PWM channel.
+   *
+   * <p>Free the resource associated with the PWM channel and set the value to 0.
+   */
+  @Override
+  public void free() {
+    super.free();
+    if (m_handle == 0) {
+      return;
+    }
+    setDisabled();
+    PWMJNI.freePWMPort(m_handle);
+    m_handle = 0;
+  }
+
+  /**
+   * Optionally eliminate the deadband from a speed controller.
+   *
+   * @param eliminateDeadband If true, set the motor curve on the Jaguar to eliminate the deadband
+   *                          in the middle of the range. Otherwise, keep the full range without
+   *                          modifying any values.
+   */
+  public void enableDeadbandElimination(boolean eliminateDeadband) {
+    PWMJNI.setPWMEliminateDeadband(m_handle, eliminateDeadband);
+  }
+
+  /**
+   * Set the bounds on the PWM pulse widths. This sets the bounds on the PWM values for a particular
+   * type of controller. The values determine the upper and lower speeds as well as the deadband
+   * bracket.
+   *
+   * @param max         The max PWM pulse width in ms
+   * @param deadbandMax The high end of the deadband range pulse width in ms
+   * @param center      The center (off) pulse width in ms
+   * @param deadbandMin The low end of the deadband pulse width in ms
+   * @param min         The minimum pulse width in ms
+   */
+  public void setBounds(double max, double deadbandMax, double center, double deadbandMin,
+                           double min) {
+    PWMJNI.setPWMConfig(m_handle, max, deadbandMax, center, deadbandMin, min);
+  }
+
+  /**
+   * Gets the bounds on the PWM pulse widths. This Gets the bounds on the PWM values for a
+   * particular type of controller. The values determine the upper and lower speeds as well
+   * as the deadband bracket.
+   */
+  public PWMConfigDataResult getRawBounds() {
+    return PWMJNI.getPWMConfigRaw(m_handle);
+  }
+
+  /**
+   * Gets the channel number associated with the PWM Object.
+   *
+   * @return The channel number.
+   */
+  public int getChannel() {
+    return m_channel;
+  }
+
+  /**
+   * Set the PWM value based on a position.
+   *
+   * <p>This is intended to be used by servos.
+   *
+   * @param pos The position to set the servo between 0.0 and 1.0.
+   * @pre SetMaxPositivePwm() called.
+   * @pre SetMinNegativePwm() called.
+   */
+  public void setPosition(double pos) {
+    PWMJNI.setPWMPosition(m_handle, pos);
+  }
+
+  /**
+   * Get the PWM value in terms of a position.
+   *
+   * <p>This is intended to be used by servos.
+   *
+   * @return The position the servo is set to between 0.0 and 1.0.
+   * @pre SetMaxPositivePwm() called.
+   * @pre SetMinNegativePwm() called.
+   */
+  public double getPosition() {
+    return PWMJNI.getPWMPosition(m_handle);
+  }
+
+  /**
+   * Set the PWM value based on a speed.
+   *
+   * <p>This is intended to be used by speed controllers.
+   *
+   * @param speed The speed to set the speed controller between -1.0 and 1.0.
+   * @pre SetMaxPositivePwm() called.
+   * @pre SetMinPositivePwm() called.
+   * @pre SetCenterPwm() called.
+   * @pre SetMaxNegativePwm() called.
+   * @pre SetMinNegativePwm() called.
+   */
+  public void setSpeed(double speed) {
+    PWMJNI.setPWMSpeed(m_handle, speed);
+  }
+
+  /**
+   * Get the PWM value in terms of speed.
+   *
+   * <p>This is intended to be used by speed controllers.
+   *
+   * @return The most recently set speed between -1.0 and 1.0.
+   * @pre SetMaxPositivePwm() called.
+   * @pre SetMinPositivePwm() called.
+   * @pre SetMaxNegativePwm() called.
+   * @pre SetMinNegativePwm() called.
+   */
+  public double getSpeed() {
+    return PWMJNI.getPWMSpeed(m_handle);
+  }
+
+  /**
+   * Set the PWM value directly to the hardware.
+   *
+   * <p>Write a raw value to a PWM channel.
+   *
+   * @param value Raw PWM value. Range 0 - 255.
+   */
+  public void setRaw(int value) {
+    PWMJNI.setPWMRaw(m_handle, (short) value);
+  }
+
+  /**
+   * Get the PWM value directly from the hardware.
+   *
+   * <p>Read a raw value from a PWM channel.
+   *
+   * @return Raw PWM control value. Range: 0 - 255.
+   */
+  public int getRaw() {
+    return PWMJNI.getPWMRaw(m_handle);
+  }
+
+  /**
+   * Temporarily disables the PWM output. The next set call will reenable
+   * the output.
+   */
+  public void setDisabled() {
+    PWMJNI.setPWMDisabled(m_handle);
+  }
+
+  /**
+   * Slow down the PWM signal for old devices.
+   *
+   * @param mult The period multiplier to apply to this channel
+   */
+  public void setPeriodMultiplier(PeriodMultiplier mult) {
+    switch (mult) {
+      case k4X:
+        // Squelch 3 out of 4 outputs
+        PWMJNI.setPWMPeriodScale(m_handle, 3);
+        break;
+      case k2X:
+        // Squelch 1 out of 2 outputs
+        PWMJNI.setPWMPeriodScale(m_handle, 1);
+        break;
+      case k1X:
+        // Don't squelch any outputs
+        PWMJNI.setPWMPeriodScale(m_handle, 0);
+        break;
+      default:
+        // Cannot hit this, limited by PeriodMultiplier enum
+    }
+  }
+
+  protected void setZeroLatch() {
+    PWMJNI.latchPWMZero(m_handle);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Speed Controller");
+    builder.setSafeState(this::setDisabled);
+    builder.addDoubleProperty("Value", this::getSpeed, this::setSpeed);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMConfigDataResult.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMConfigDataResult.java
new file mode 100644
index 0000000..9373d91
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj;
+
+/**
+ * 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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSpeedController.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSpeedController.java
new file mode 100644
index 0000000..8581a4c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSpeedController.java
@@ -0,0 +1,69 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * Common base class for all PWM Speed Controllers.
+ */
+public abstract class PWMSpeedController extends SafePWM implements SpeedController {
+  private boolean m_isInverted = false;
+
+  /**
+   * Constructor.
+   *
+   * @param channel The PWM channel that the controller is attached to. 0-9 are on-board, 10-19 are
+   *                on the MXP port
+   */
+  protected PWMSpeedController(int channel) {
+    super(channel);
+  }
+
+  /**
+   * Set the PWM value.
+   *
+   * <p>The PWM value is set using a range of -1.0 to 1.0, appropriately scaling the value for the
+   * FPGA.
+   *
+   * @param speed The speed value between -1.0 and 1.0 to set.
+   */
+  @Override
+  public void set(double speed) {
+    setSpeed(m_isInverted ? -speed : speed);
+    feed();
+  }
+
+  /**
+   * Get the recently set value of the PWM.
+   *
+   * @return The most recently set value for the PWM between -1.0 and 1.0.
+   */
+  @Override
+  public double get() {
+    return getSpeed();
+  }
+
+  @Override
+  public void setInverted(boolean isInverted) {
+    m_isInverted = isInverted;
+  }
+
+  @Override
+  public boolean getInverted() {
+    return m_isInverted;
+  }
+
+  /**
+   * Write out the PID value as seen in the PIDOutput base object.
+   *
+   * @param output Write out the PWM value as was found in the PIDController
+   */
+  @Override
+  public void pidWrite(double output) {
+    set(output);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonSRX.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonSRX.java
new file mode 100644
index 0000000..c461bc0
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonSRX.java
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Cross the Road Electronics (CTRE) Talon SRX Speed Controller with PWM control.
+ */
+public class PWMTalonSRX extends PWMSpeedController {
+  /**
+   * Constructor for a PWMTalonSRX connected via PWM.
+   *
+   * <p>Note that the PWMTalonSRX uses the following bounds for PWM values. These values should work
+   * reasonably well for most controllers, but if users experience issues such as asymmetric
+   * behavior around the deadband or inability to saturate the controller in either direction,
+   * calibration is recommended. The calibration procedure can be found in the TalonSRX User Manual
+   * available from CTRE.
+   *
+   * <p>- 2.0004ms = full "forward" - 1.52ms = the "high end" of the deadband range - 1.50ms =
+   * center
+   * of the deadband range (off) - 1.48ms = the "low end" of the deadband range - .997ms = full
+   * "reverse"
+   *
+   * @param channel The PWM channel that the PWMTalonSRX is attached to. 0-9 are on-board, 10-19 are
+   *                on the MXP port
+   */
+  public PWMTalonSRX(final int channel) {
+    super(channel);
+
+    setBounds(2.004, 1.52, 1.50, 1.48, .997);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    HAL.report(tResourceType.kResourceType_PWMTalonSRX, getChannel());
+    setName("PWMTalonSRX", getChannel());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVictorSPX.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVictorSPX.java
new file mode 100644
index 0000000..caa1bb2
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVictorSPX.java
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+//import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+//import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Cross the Road Electronics (CTRE) Victor SPX Speed Controller with PWM control.
+ */
+public class PWMVictorSPX extends PWMSpeedController {
+  /**
+   * Constructor for a PWMVictorSPX connected via PWM.
+   *
+   * <p>Note that the PWMVictorSPX uses the following bounds for PWM values. These values should
+   *  work reasonably well for most controllers, but if users experience issues such as asymmetric
+   * behavior around the deadband or inability to saturate the controller in either direction,
+   * calibration is recommended. The calibration procedure can be found in the VictorSPX User
+   * Manual available from CTRE.
+   *
+   * <p>- 2.0004ms = full "forward" - 1.52ms = the "high end" of the deadband range - 1.50ms =
+   * center
+   * of the deadband range (off) - 1.48ms = the "low end" of the deadband range - .997ms = full
+   * "reverse"
+   *
+   * @param channel The PWM channel that the PWMVictorSPX is attached to. 0-9 are on-board, 10-19
+   *                are on the MXP port
+   */
+  public PWMVictorSPX(final int channel) {
+    super(channel);
+
+    setBounds(2.004, 1.52, 1.50, 1.48, .997);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    //HAL.report(tResourceType.kResourceType_PWMVictorSPX, getChannel());
+    setName("PWMVictorSPX", getChannel());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistributionPanel.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistributionPanel.java
new file mode 100644
index 0000000..958d2e0
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistributionPanel.java
@@ -0,0 +1,121 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2014-2018 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.PDPJNI;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Class for getting voltage, current, temperature, power and energy from the Power Distribution
+ * Panel over CAN.
+ */
+public class PowerDistributionPanel extends SensorBase implements Sendable {
+  private final int m_module;
+
+  /**
+   * Constructor.
+   *
+   * @param module The CAN ID of the PDP
+   */
+  public PowerDistributionPanel(int module) {
+    m_module = module;
+    checkPDPModule(module);
+    PDPJNI.initializePDP(module);
+    setName("PowerDistributionPanel", module);
+  }
+
+  /**
+   * Constructor.  Uses the default CAN ID (0).
+   */
+  public PowerDistributionPanel() {
+    this(0);
+  }
+
+  /**
+   * Query the input voltage of the PDP.
+   *
+   * @return The voltage of the PDP in volts
+   */
+  public double getVoltage() {
+    return PDPJNI.getPDPVoltage(m_module);
+  }
+
+  /**
+   * Query the temperature of the PDP.
+   *
+   * @return The temperature of the PDP in degrees Celsius
+   */
+  public double getTemperature() {
+    return PDPJNI.getPDPTemperature(m_module);
+  }
+
+  /**
+   * Query the current of a single channel of the PDP.
+   *
+   * @return The current of one of the PDP channels (channels 0-15) in Amperes
+   */
+  public double getCurrent(int channel) {
+    double current = PDPJNI.getPDPChannelCurrent((byte) channel, m_module);
+
+    checkPDPChannel(channel);
+
+    return current;
+  }
+
+  /**
+   * Query the current of all monitored PDP channels (0-15).
+   *
+   * @return The current of all the channels in Amperes
+   */
+  public double getTotalCurrent() {
+    return PDPJNI.getPDPTotalCurrent(m_module);
+  }
+
+  /**
+   * Query the total power drawn from the monitored PDP channels.
+   *
+   * @return the total power in Watts
+   */
+  public double getTotalPower() {
+    return PDPJNI.getPDPTotalPower(m_module);
+  }
+
+  /**
+   * Query the total energy drawn from the monitored PDP channels.
+   *
+   * @return the total energy in Joules
+   */
+  public double getTotalEnergy() {
+    return PDPJNI.getPDPTotalEnergy(m_module);
+  }
+
+  /**
+   * Reset the total energy to 0.
+   */
+  public void resetTotalEnergy() {
+    PDPJNI.resetPDPTotalEnergy(m_module);
+  }
+
+  /**
+   * Clear all PDP sticky faults.
+   */
+  public void clearStickyFaults() {
+    PDPJNI.clearPDPStickyFaults(m_module);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("PowerDistributionPanel");
+    for (int i = 0; i < kPDPChannels; ++i) {
+      final int chan = i;
+      builder.addDoubleProperty("Chan" + i, () -> getCurrent(chan), null);
+    }
+    builder.addDoubleProperty("Voltage", this::getVoltage, null);
+    builder.addDoubleProperty("TotalCurrent", this::getTotalCurrent, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Preferences.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Preferences.java
new file mode 100644
index 0000000..fcab667
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Preferences.java
@@ -0,0 +1,247 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.util.Vector;
+
+import edu.wpi.first.networktables.EntryListenerFlags;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * The preferences class provides a relatively simple way to save important values to the roboRIO to
+ * access the next time the roboRIO is booted.
+ *
+ * <p> This class loads and saves from a file inside the roboRIO. The user can not access the file
+ * directly, but may modify values at specific fields which will then be automatically saved to the
+ * file by the NetworkTables server. </p>
+ *
+ * <p> This class is thread safe. </p>
+ *
+ * <p> This will also interact with {@link NetworkTable} by creating a table called "Preferences"
+ * with all the key-value pairs. </p>
+ */
+public class Preferences {
+  /**
+   * The Preferences table name.
+   */
+  private static final String TABLE_NAME = "Preferences";
+  /**
+   * The singleton instance.
+   */
+  private static Preferences instance;
+  /**
+   * The network table.
+   */
+  private final NetworkTable m_table;
+
+  /**
+   * Returns the preferences instance.
+   *
+   * @return the preferences instance
+   */
+  public static synchronized Preferences getInstance() {
+    if (instance == null) {
+      instance = new Preferences();
+    }
+    return instance;
+  }
+
+  /**
+   * Creates a preference class.
+   */
+  private Preferences() {
+    m_table = NetworkTableInstance.getDefault().getTable(TABLE_NAME);
+    m_table.getEntry(".type").setString("RobotPreferences");
+    // Listener to set all Preferences values to persistent
+    // (for backwards compatibility with old dashboards).
+    m_table.addEntryListener(
+        (table, key, entry, value, flags) -> entry.setPersistent(),
+        EntryListenerFlags.kImmediate | EntryListenerFlags.kNew);
+    HAL.report(tResourceType.kResourceType_Preferences, 0);
+  }
+
+  /**
+   * Gets the vector of keys.
+   * @return a vector of the keys
+   */
+  public Vector<String> getKeys() {
+    return new Vector<>(m_table.getKeys());
+  }
+
+  /**
+   * Puts the given string into the preferences table.
+   *
+   * @param key   the key
+   * @param value the value
+   * @throws NullPointerException if value is null
+   */
+  public void putString(String key, String value) {
+    requireNonNull(value, "Provided value was null");
+
+    NetworkTableEntry entry = m_table.getEntry(key);
+    entry.setString(value);
+    entry.setPersistent();
+  }
+
+  /**
+   * Puts the given int into the preferences table.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  public void putInt(String key, int value) {
+    NetworkTableEntry entry = m_table.getEntry(key);
+    entry.setDouble(value);
+    entry.setPersistent();
+  }
+
+  /**
+   * Puts the given double into the preferences table.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  public void putDouble(String key, double value) {
+    NetworkTableEntry entry = m_table.getEntry(key);
+    entry.setDouble(value);
+    entry.setPersistent();
+  }
+
+  /**
+   * Puts the given float into the preferences table.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  public void putFloat(String key, float value) {
+    NetworkTableEntry entry = m_table.getEntry(key);
+    entry.setDouble(value);
+    entry.setPersistent();
+  }
+
+  /**
+   * Puts the given boolean into the preferences table.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  public void putBoolean(String key, boolean value) {
+    NetworkTableEntry entry = m_table.getEntry(key);
+    entry.setBoolean(value);
+    entry.setPersistent();
+  }
+
+  /**
+   * Puts the given long into the preferences table.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  public void putLong(String key, long value) {
+    NetworkTableEntry entry = m_table.getEntry(key);
+    entry.setDouble(value);
+    entry.setPersistent();
+  }
+
+  /**
+   * Returns whether or not there is a key with the given name.
+   *
+   * @param key the key
+   * @return if there is a value at the given key
+   */
+  public boolean containsKey(String key) {
+    return m_table.containsKey(key);
+  }
+
+  /**
+   * Remove a preference.
+   *
+   * @param key the key
+   */
+  public void remove(String key) {
+    m_table.delete(key);
+  }
+
+  /**
+   * Returns the string at the given key. If this table does not have a value for that position,
+   * then the given backup value will be returned.
+   *
+   * @param key    the key
+   * @param backup the value to return if none exists in the table
+   * @return either the value in the table, or the backup
+   */
+  public String getString(String key, String backup) {
+    return m_table.getEntry(key).getString(backup);
+  }
+
+  /**
+   * Returns the int at the given key. If this table does not have a value for that position, then
+   * the given backup value will be returned.
+   *
+   * @param key    the key
+   * @param backup the value to return if none exists in the table
+   * @return either the value in the table, or the backup
+   */
+  public int getInt(String key, int backup) {
+    return (int) m_table.getEntry(key).getDouble(backup);
+  }
+
+  /**
+   * Returns the double at the given key. If this table does not have a value for that position,
+   * then the given backup value will be returned.
+   *
+   * @param key    the key
+   * @param backup the value to return if none exists in the table
+   * @return either the value in the table, or the backup
+   */
+  public double getDouble(String key, double backup) {
+    return m_table.getEntry(key).getDouble(backup);
+  }
+
+  /**
+   * Returns the boolean at the given key. If this table does not have a value for that position,
+   * then the given backup value will be returned.
+   *
+   * @param key    the key
+   * @param backup the value to return if none exists in the table
+   * @return either the value in the table, or the backup
+   */
+  public boolean getBoolean(String key, boolean backup) {
+    return m_table.getEntry(key).getBoolean(backup);
+  }
+
+  /**
+   * Returns the float at the given key. If this table does not have a value for that position, then
+   * the given backup value will be returned.
+   *
+   * @param key    the key
+   * @param backup the value to return if none exists in the table
+   * @return either the value in the table, or the backup
+   */
+  public float getFloat(String key, float backup) {
+    return (float) m_table.getEntry(key).getDouble(backup);
+  }
+
+  /**
+   * Returns the long at the given key. If this table does not have a value for that position, then
+   * the given backup value will be returned.
+   *
+   * @param key    the key
+   * @param backup the value to return if none exists in the table
+   * @return either the value in the table, or the backup
+   */
+  public long getLong(String key, long backup) {
+    return (long) m_table.getEntry(key).getDouble(backup);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Relay.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Relay.java
new file mode 100644
index 0000000..38e18a5
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Relay.java
@@ -0,0 +1,339 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.RelayJNI;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Class for VEX Robotics Spike style relay outputs. Relays are intended to be connected to Spikes
+ * or similar relays. The relay channels controls a pair of channels that are either both off, one
+ * on, the other on, or both on. This translates into two Spike outputs at 0v, one at 12v and one
+ * at 0v, one at 0v and the other at 12v, or two Spike outputs at 12V. This allows off, full
+ * forward, or full reverse control of motors without variable speed. It also allows the two
+ * channels (forward and reverse) to be used independently for something that does not care about
+ * voltage polarity (like a solenoid).
+ */
+public class Relay extends SendableBase implements MotorSafety, Sendable {
+  private MotorSafetyHelper m_safetyHelper;
+
+  /**
+   * This class represents errors in trying to set relay values contradictory to the direction to
+   * which the relay is set.
+   */
+  public class InvalidValueException extends RuntimeException {
+    /**
+     * Create a new exception with the given message.
+     *
+     * @param message the message to pass with the exception
+     */
+    public InvalidValueException(String message) {
+      super(message);
+    }
+  }
+
+  /**
+   * The state to drive a Relay to.
+   */
+  public enum Value {
+    kOff("Off"),
+    kOn("On"),
+    kForward("Forward"),
+    kReverse("Reverse");
+
+    private final String m_prettyValue;
+
+    Value(String prettyValue) {
+      m_prettyValue = prettyValue;
+    }
+
+    public String getPrettyValue() {
+      return m_prettyValue;
+    }
+
+    public static Optional<Value> getValueOf(String value) {
+      return Arrays.stream(Value.values()).filter(v -> v.m_prettyValue.equals(value)).findFirst();
+    }
+  }
+
+  /**
+   * The Direction(s) that a relay is configured to operate in.
+   */
+  public enum Direction {
+    /**
+     * direction: both directions are valid.
+     */
+
+    kBoth,
+    /**
+     * direction: Only forward is valid.
+     */
+    kForward,
+    /**
+     * direction: only reverse is valid.
+     */
+    kReverse
+  }
+
+  private final int m_channel;
+
+  private int m_forwardHandle = 0;
+  private int m_reverseHandle = 0;
+
+  private Direction m_direction;
+
+  /**
+   * Common relay initialization method. This code is common to all Relay constructors and
+   * initializes the relay and reserves all resources that need to be locked. Initially the relay is
+   * set to both lines at 0v.
+   */
+  private void initRelay() {
+    SensorBase.checkRelayChannel(m_channel);
+
+    int portHandle = RelayJNI.getPort((byte) m_channel);
+    if (m_direction == Direction.kBoth || m_direction == Direction.kForward) {
+      m_forwardHandle = RelayJNI.initializeRelayPort(portHandle, true);
+      HAL.report(tResourceType.kResourceType_Relay, m_channel);
+    }
+    if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) {
+      m_reverseHandle = RelayJNI.initializeRelayPort(portHandle, false);
+      HAL.report(tResourceType.kResourceType_Relay, m_channel + 128);
+    }
+
+    m_safetyHelper = new MotorSafetyHelper(this);
+    m_safetyHelper.setSafetyEnabled(false);
+
+    setName("Relay", m_channel);
+  }
+
+  /**
+   * Relay constructor given a channel.
+   *
+   * @param channel The channel number for this relay (0 - 3).
+   * @param direction The direction that the Relay object will control.
+   */
+  public Relay(final int channel, Direction direction) {
+    m_channel = channel;
+    m_direction = requireNonNull(direction, "Null Direction was given");
+    initRelay();
+    set(Value.kOff);
+  }
+
+  /**
+   * Relay constructor given a channel, allowing both directions.
+   *
+   * @param channel The channel number for this relay (0 - 3).
+   */
+  public Relay(final int channel) {
+    this(channel, Direction.kBoth);
+  }
+
+  @Override
+  public void free() {
+    super.free();
+    freeRelay();
+  }
+
+  private void freeRelay() {
+    try {
+      RelayJNI.setRelay(m_forwardHandle, false);
+    } catch (RuntimeException ex) {
+      // do nothing. Ignore
+    }
+    try {
+      RelayJNI.setRelay(m_reverseHandle, false);
+    } catch (RuntimeException ex) {
+      // do nothing. Ignore
+    }
+
+    RelayJNI.freeRelayPort(m_forwardHandle);
+    RelayJNI.freeRelayPort(m_reverseHandle);
+
+    m_forwardHandle = 0;
+    m_reverseHandle = 0;
+  }
+
+  /**
+   * Set the relay state.
+   *
+   * <p>Valid values depend on which directions of the relay are controlled by the object.
+   *
+   * <p>When set to kBothDirections, the relay can be set to any of the four states: 0v-0v, 12v-0v,
+   * 0v-12v, 12v-12v
+   *
+   * <p>When set to kForwardOnly or kReverseOnly, you can specify the constant for the direction or
+   * you can simply specify kOff and kOn. Using only kOff and kOn is recommended.
+   *
+   * @param value The state to set the relay.
+   */
+  public void set(Value value) {
+    switch (value) {
+      case kOff:
+        if (m_direction == Direction.kBoth || m_direction == Direction.kForward) {
+          RelayJNI.setRelay(m_forwardHandle, false);
+        }
+        if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) {
+          RelayJNI.setRelay(m_reverseHandle, false);
+        }
+        break;
+      case kOn:
+        if (m_direction == Direction.kBoth || m_direction == Direction.kForward) {
+          RelayJNI.setRelay(m_forwardHandle, true);
+        }
+        if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) {
+          RelayJNI.setRelay(m_reverseHandle, true);
+        }
+        break;
+      case kForward:
+        if (m_direction == Direction.kReverse) {
+          throw new InvalidValueException("A relay configured for reverse cannot be set to "
+              + "forward");
+        }
+        if (m_direction == Direction.kBoth || m_direction == Direction.kForward) {
+          RelayJNI.setRelay(m_forwardHandle, true);
+        }
+        if (m_direction == Direction.kBoth) {
+          RelayJNI.setRelay(m_reverseHandle, false);
+        }
+        break;
+      case kReverse:
+        if (m_direction == Direction.kForward) {
+          throw new InvalidValueException("A relay configured for forward cannot be set to "
+              + "reverse");
+        }
+        if (m_direction == Direction.kBoth) {
+          RelayJNI.setRelay(m_forwardHandle, false);
+        }
+        if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) {
+          RelayJNI.setRelay(m_reverseHandle, true);
+        }
+        break;
+      default:
+        // Cannot hit this, limited by Value enum
+    }
+  }
+
+  /**
+   * Get the Relay State.
+   *
+   * <p>Gets the current state of the relay.
+   *
+   * <p>When set to kForwardOnly or kReverseOnly, value is returned as kOn/kOff not
+   * kForward/kReverse (per the recommendation in Set)
+   *
+   * @return The current state of the relay as a Relay::Value
+   */
+  public Value get() {
+    if (m_direction == Direction.kForward) {
+      if (RelayJNI.getRelay(m_forwardHandle)) {
+        return Value.kOn;
+      } else {
+        return Value.kOff;
+      }
+    } else if (m_direction == Direction.kReverse) {
+      if (RelayJNI.getRelay(m_reverseHandle)) {
+        return Value.kOn;
+      } else {
+        return Value.kOff;
+      }
+    } else {
+      if (RelayJNI.getRelay(m_forwardHandle)) {
+        if (RelayJNI.getRelay(m_reverseHandle)) {
+          return Value.kOn;
+        } else {
+          return Value.kForward;
+        }
+      } else {
+        if (RelayJNI.getRelay(m_reverseHandle)) {
+          return Value.kReverse;
+        } else {
+          return Value.kOff;
+        }
+      }
+    }
+  }
+
+  /**
+   * Get the channel number.
+   *
+   * @return The channel number.
+   */
+  public int getChannel() {
+    return m_channel;
+  }
+
+  @Override
+  public void setExpiration(double timeout) {
+    m_safetyHelper.setExpiration(timeout);
+  }
+
+  @Override
+  public double getExpiration() {
+    return m_safetyHelper.getExpiration();
+  }
+
+  @Override
+  public boolean isAlive() {
+    return m_safetyHelper.isAlive();
+  }
+
+  @Override
+  public void stopMotor() {
+    set(Value.kOff);
+  }
+
+  @Override
+  public boolean isSafetyEnabled() {
+    return m_safetyHelper.isSafetyEnabled();
+  }
+
+  @Override
+  public void setSafetyEnabled(boolean enabled) {
+    m_safetyHelper.setSafetyEnabled(enabled);
+  }
+
+  @Override
+  public String getDescription() {
+    return "Relay ID " + getChannel();
+  }
+
+  /**
+   * Set the Relay Direction.
+   *
+   * <p>Changes which values the relay can be set to depending on which direction is used
+   *
+   * <p>Valid inputs are kBothDirections, kForwardOnly, and kReverseOnly
+   *
+   * @param direction The direction for the relay to operate in
+   */
+  public void setDirection(Direction direction) {
+    requireNonNull(direction, "Null Direction was given");
+    if (m_direction == direction) {
+      return;
+    }
+
+    freeRelay();
+    m_direction = direction;
+    initRelay();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Relay");
+    builder.setSafeState(() -> set(Value.kOff));
+    builder.addStringProperty("Value", () -> get().getPrettyValue(),
+        (value) -> set(Value.getValueOf(value).orElse(Value.kOff)));
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Resource.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Resource.java
new file mode 100644
index 0000000..4e9ebb1
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Resource.java
@@ -0,0 +1,110 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.util.AllocationException;
+import edu.wpi.first.wpilibj.util.CheckedAllocationException;
+
+/**
+ * Track resources in the program. The Resource class is a convenient way of keeping track of
+ * allocated arbitrary resources in the program. Resources are just indices that have an lower and
+ * upper bound that are tracked by this class. In the library they are used for tracking allocation
+ * of hardware channels but this is purely arbitrary. The resource class does not do any actual
+ * allocation, but simply tracks if a given index is currently in use.
+ *
+ * <p><b>WARNING:</b> this should only be statically allocated. When the program loads into memory
+ * all the static constructors are called. At that time a linked list of all the "Resources" is
+ * created. Then when the program actually starts - in the Robot constructor, all resources are
+ * initialized. This ensures that the program is restartable in memory without having to
+ * unload/reload.
+ */
+public final class Resource {
+  private static Resource resourceList = null;
+  private final boolean[] m_numAllocated;
+  private final int m_size;
+  private final Resource m_nextResource;
+
+  /**
+   * Clears all allocated resources.
+   */
+  public static void restartProgram() {
+    for (Resource r = Resource.resourceList; r != null; r = r.m_nextResource) {
+      for (int i = 0; i < r.m_size; i++) {
+        r.m_numAllocated[i] = false;
+      }
+    }
+  }
+
+  /**
+   * Allocate storage for a new instance of Resource. Allocate a bool array of values that will get
+   * initialized to indicate that no resources have been allocated yet. The indices of the
+   * resources are 0..size-1.
+   *
+   * @param size The number of blocks to allocate
+   */
+  public Resource(final int size) {
+    m_size = size;
+    m_numAllocated = new boolean[size];
+    for (int i = 0; i < size; i++) {
+      m_numAllocated[i] = false;
+    }
+    m_nextResource = Resource.resourceList;
+    Resource.resourceList = this;
+  }
+
+  /**
+   * Allocate a resource. When a resource is requested, mark it allocated. In this case, a free
+   * resource value within the range is located and returned after it is marked allocated.
+   *
+   * @return The index of the allocated block.
+   * @throws CheckedAllocationException If there are no resources available to be allocated.
+   */
+  public int allocate() throws CheckedAllocationException {
+    for (int i = 0; i < m_size; i++) {
+      if (!m_numAllocated[i]) {
+        m_numAllocated[i] = true;
+        return i;
+      }
+    }
+    throw new CheckedAllocationException("No available resources");
+  }
+
+  /**
+   * Allocate a specific resource value. The user requests a specific resource value, i.e. channel
+   * number and it is verified unallocated, then returned.
+   *
+   * @param index The resource to allocate
+   * @return The index of the allocated block
+   * @throws CheckedAllocationException If there are no resources available to be allocated.
+   */
+  public int allocate(final int index) throws CheckedAllocationException {
+    if (index >= m_size || index < 0) {
+      throw new CheckedAllocationException("Index " + index + " out of range");
+    }
+    if (m_numAllocated[index]) {
+      throw new CheckedAllocationException("Resource at index " + index + " already allocated");
+    }
+    m_numAllocated[index] = true;
+    return index;
+  }
+
+  /**
+   * Free an allocated resource. After a resource is no longer needed, for example a destructor is
+   * called for a channel assignment class, Free will release the resource value so it can be reused
+   * somewhere else in the program.
+   *
+   * @param index The index of the resource to free.
+   */
+  public void free(final int index) {
+    if (!m_numAllocated[index]) {
+      throw new AllocationException("No resource available to be freed");
+    }
+    m_numAllocated[index] = false;
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java
new file mode 100644
index 0000000..693df20
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java
@@ -0,0 +1,272 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.Manifest;
+
+import edu.wpi.cscore.CameraServerJNI;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.HALUtil;
+import edu.wpi.first.wpilibj.internal.HardwareHLUsageReporting;
+import edu.wpi.first.wpilibj.internal.HardwareTimer;
+import edu.wpi.first.wpilibj.livewindow.LiveWindow;
+import edu.wpi.first.wpilibj.util.WPILibVersion;
+
+/**
+ * Implement a Robot Program framework. The RobotBase class is intended to be subclassed by a user
+ * creating a robot program. Overridden autonomous() and operatorControl() methods are called at the
+ * appropriate time as the match proceeds. In the current implementation, the Autonomous code will
+ * run to completion before the OperatorControl code could start. In the future the Autonomous code
+ * might be spawned as a task, then killed at the end of the Autonomous period.
+ */
+public abstract class RobotBase {
+  /**
+   * The VxWorks priority that robot code should work at (so Java code should run at).
+   */
+  public static final int ROBOT_TASK_PRIORITY = 101;
+
+  /**
+   * The ID of the main Java thread.
+   */
+  // This is usually 1, but it is best to make sure
+  public static final long MAIN_THREAD_ID = Thread.currentThread().getId();
+
+  protected final DriverStation m_ds;
+
+  /**
+   * Constructor for a generic robot program. User code should be placed in the constructor that
+   * runs before the Autonomous or Operator Control period starts. The constructor will run to
+   * completion before Autonomous is entered.
+   *
+   * <p>This must be used to ensure that the communications code starts. In the future it would be
+   * nice
+   * to put this code into it's own task that loads on boot so ensure that it runs.
+   */
+  protected RobotBase() {
+    NetworkTableInstance inst = NetworkTableInstance.getDefault();
+    inst.setNetworkIdentity("Robot");
+    inst.startServer("/home/lvuser/networktables.ini");
+    m_ds = DriverStation.getInstance();
+    inst.getTable("LiveWindow").getSubTable(".status").getEntry("LW Enabled").setBoolean(false);
+
+    LiveWindow.setEnabled(false);
+  }
+
+  /**
+   * Free the resources for a RobotBase class.
+   */
+  public void free() {
+  }
+
+  /**
+   * Get if the robot is a simulation.
+   *
+   * @return If the robot is running in simulation.
+   */
+  public static boolean isSimulation() {
+    return !isReal();
+  }
+
+  /**
+   * Get if the robot is real.
+   *
+   * @return If the robot is running in the real world.
+   */
+  public static boolean isReal() {
+    return HALUtil.getHALRuntimeType() == 0;
+  }
+
+  /**
+   * Determine if the Robot is currently disabled.
+   *
+   * @return True if the Robot is currently disabled by the field controls.
+   */
+  public boolean isDisabled() {
+    return m_ds.isDisabled();
+  }
+
+  /**
+   * Determine if the Robot is currently enabled.
+   *
+   * @return True if the Robot is currently enabled by the field controls.
+   */
+  public boolean isEnabled() {
+    return m_ds.isEnabled();
+  }
+
+  /**
+   * Determine if the robot is currently in Autonomous mode as determined by the field
+   * controls.
+   *
+   * @return True if the robot is currently operating Autonomously.
+   */
+  public boolean isAutonomous() {
+    return m_ds.isAutonomous();
+  }
+
+  /**
+   * Determine if the robot is currently in Test mode as determined by the driver
+   * station.
+   *
+   * @return True if the robot is currently operating in Test mode.
+   */
+  public boolean isTest() {
+    return m_ds.isTest();
+  }
+
+  /**
+   * Determine if the robot is currently in Operator Control mode as determined by the field
+   * controls.
+   *
+   * @return True if the robot is currently operating in Tele-Op mode.
+   */
+  public boolean isOperatorControl() {
+    return m_ds.isOperatorControl();
+  }
+
+  /**
+   * Indicates if new data is available from the driver station.
+   *
+   * @return Has new data arrived over the network since the last time this function was called?
+   */
+  public boolean isNewDataAvailable() {
+    return m_ds.isNewControlData();
+  }
+
+  /**
+   * Provide an alternate "main loop" via startCompetition().
+   */
+  public abstract void startCompetition();
+
+  @SuppressWarnings("JavadocMethod")
+  public static boolean getBooleanProperty(String name, boolean defaultValue) {
+    String propVal = System.getProperty(name);
+    if (propVal == null) {
+      return defaultValue;
+    }
+    if (propVal.equalsIgnoreCase("false")) {
+      return false;
+    } else if (propVal.equalsIgnoreCase("true")) {
+      return true;
+    } else {
+      throw new IllegalStateException(propVal);
+    }
+  }
+
+  /**
+   * Common initialization for all robot programs.
+   */
+  public static void initializeHardwareConfiguration() {
+    if (!HAL.initialize(500, 0)) {
+      throw new IllegalStateException("Failed to initialize. Terminating");
+    }
+
+    // Set some implementations so that the static methods work properly
+    Timer.SetImplementation(new HardwareTimer());
+    HLUsageReporting.SetImplementation(new HardwareHLUsageReporting());
+    RobotState.SetImplementation(DriverStation.getInstance());
+
+    // Call a CameraServer JNI function to force OpenCV native library loading
+    // Needed because all the OpenCV JNI functions don't have built in loading
+    CameraServerJNI.enumerateSinks();
+  }
+
+  /**
+   * Starting point for the applications.
+   */
+  @SuppressWarnings("PMD.UnusedFormalParameter")
+  public static void main(String... args) {
+    initializeHardwareConfiguration();
+
+    HAL.report(tResourceType.kResourceType_Language, tInstances.kLanguage_Java);
+
+    String robotName = "";
+    Enumeration<URL> resources = null;
+    try {
+      resources = RobotBase.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
+    } catch (IOException ex) {
+      ex.printStackTrace();
+    }
+    while (resources != null && resources.hasMoreElements()) {
+      try {
+        Manifest manifest = new Manifest(resources.nextElement().openStream());
+        robotName = manifest.getMainAttributes().getValue("Robot-Class");
+      } catch (IOException ex) {
+        ex.printStackTrace();
+      }
+    }
+
+    System.out.println("********** Robot program starting **********");
+
+    RobotBase robot;
+    try {
+      robot = (RobotBase) Class.forName(robotName).newInstance();
+    } catch (Throwable throwable) {
+      Throwable cause = throwable.getCause();
+      if (cause != null) {
+        throwable = cause;
+      }
+      DriverStation.reportError("Unhandled exception instantiating robot " + robotName + " "
+          + throwable.toString(), throwable.getStackTrace());
+      DriverStation.reportWarning("Robots should not quit, but yours did!", false);
+      DriverStation.reportError("Could not instantiate robot " + robotName + "!", false);
+      System.exit(1);
+      return;
+    }
+
+    try {
+      final File file = new File("/tmp/frc_versions/FRC_Lib_Version.ini");
+
+      if (file.exists()) {
+        file.delete();
+      }
+
+      file.createNewFile();
+
+      try (FileOutputStream output = new FileOutputStream(file)) {
+        output.write("Java ".getBytes());
+        output.write(WPILibVersion.Version.getBytes());
+      }
+
+    } catch (IOException ex) {
+      ex.printStackTrace();
+    }
+
+    boolean errorOnExit = false;
+    try {
+      robot.startCompetition();
+    } catch (Throwable throwable) {
+      Throwable cause = throwable.getCause();
+      if (cause != null) {
+        throwable = cause;
+      }
+      DriverStation.reportError("Unhandled exception: " + throwable.toString(),
+          throwable.getStackTrace());
+      errorOnExit = true;
+    } finally {
+      // startCompetition never returns unless exception occurs....
+      DriverStation.reportWarning("Robots should not quit, but yours did!", false);
+      if (errorOnExit) {
+        DriverStation.reportError(
+            "The startCompetition() method (or methods called by it) should have "
+                + "handled the exception above.", false);
+      } else {
+        DriverStation.reportError("Unexpected return from startCompetition() method.", false);
+      }
+    }
+    System.exit(1);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java
new file mode 100644
index 0000000..5a2b52f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java
@@ -0,0 +1,231 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.can.CANJNI;
+import edu.wpi.first.wpilibj.can.CANStatus;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.HALUtil;
+import edu.wpi.first.wpilibj.hal.PowerJNI;
+
+/**
+ * Contains functions for roboRIO functionality.
+ */
+public final class RobotController {
+  private RobotController() {
+  }
+
+  /**
+   * Return the FPGA Version number. For now, expect this to be the current
+   * year.
+   *
+   * @return FPGA Version number.
+   */
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public static int getFPGAVersion() {
+    return HALUtil.getFPGAVersion();
+  }
+
+  /**
+   * Return 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.
+   */
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public static long getFPGARevision() {
+    return (long) HALUtil.getFPGARevision();
+  }
+
+  /**
+   * Read the microsecond timer from the FPGA.
+   *
+   * @return The current time in microseconds according to the FPGA.
+   */
+  public static long getFPGATime() {
+    return HALUtil.getFPGATime();
+  }
+
+  /**
+   * Get the state of the "USER" button on the roboRIO.
+   *
+   * @return true if the button is currently pressed down
+   */
+  public static boolean getUserButton() {
+    return HALUtil.getFPGAButton();
+  }
+
+  /**
+   * Read the battery voltage.
+   *
+   * @return The battery voltage in Volts.
+   */
+  public static double getBatteryVoltage() {
+    return PowerJNI.getVinVoltage();
+  }
+
+  /**
+   * Gets a value indicating whether the FPGA outputs are enabled. The outputs may be disabled if
+   * the robot is disabled or e-stopped, the watchdog has expired, or if the roboRIO browns out.
+   *
+   * @return True if the FPGA outputs are enabled.
+   */
+  public static boolean isSysActive() {
+    return HAL.getSystemActive();
+  }
+
+  /**
+   * Check if the system is browned out.
+   *
+   * @return True if the system is browned out
+   */
+  public static boolean isBrownedOut() {
+    return HAL.getBrownedOut();
+  }
+
+  /**
+   * Get the input voltage to the robot controller.
+   *
+   * @return The controller input voltage value in Volts
+   */
+  public static double getInputVoltage() {
+    return PowerJNI.getVinVoltage();
+  }
+
+  /**
+   * Get the input current to the robot controller.
+   *
+   * @return The controller input current value in Amps
+   */
+  public static double getInputCurrent() {
+    return PowerJNI.getVinCurrent();
+  }
+
+  /**
+   * Get the voltage of the 3.3V rail.
+   *
+   * @return The controller 3.3V rail voltage value in Volts
+   */
+  public static double getVoltage3V3() {
+    return PowerJNI.getUserVoltage3V3();
+  }
+
+  /**
+   * Get the current output of the 3.3V rail.
+   *
+   * @return The controller 3.3V rail output current value in Volts
+   */
+  public static double getCurrent3V3() {
+    return PowerJNI.getUserCurrent3V3();
+  }
+
+  /**
+   * Get the enabled state of the 3.3V rail. The rail may be disabled due to a controller brownout,
+   * a short circuit on the rail, or controller over-voltage.
+   *
+   * @return The controller 3.3V rail enabled value
+   */
+  public static boolean getEnabled3V3() {
+    return PowerJNI.getUserActive3V3();
+  }
+
+  /**
+   * Get the count of the total current faults on the 3.3V rail since the controller has booted.
+   *
+   * @return The number of faults
+   */
+  public static int getFaultCount3V3() {
+    return PowerJNI.getUserCurrentFaults3V3();
+  }
+
+  /**
+   * Get the voltage of the 5V rail.
+   *
+   * @return The controller 5V rail voltage value in Volts
+   */
+  public static double getVoltage5V() {
+    return PowerJNI.getUserVoltage5V();
+  }
+
+  /**
+   * Get the current output of the 5V rail.
+   *
+   * @return The controller 5V rail output current value in Amps
+   */
+  public static double getCurrent5V() {
+    return PowerJNI.getUserCurrent5V();
+  }
+
+  /**
+   * Get the enabled state of the 5V rail. The rail may be disabled due to a controller brownout, a
+   * short circuit on the rail, or controller over-voltage.
+   *
+   * @return The controller 5V rail enabled value
+   */
+  public static boolean getEnabled5V() {
+    return PowerJNI.getUserActive5V();
+  }
+
+  /**
+   * Get the count of the total current faults on the 5V rail since the controller has booted.
+   *
+   * @return The number of faults
+   */
+  public static int getFaultCount5V() {
+    return PowerJNI.getUserCurrentFaults5V();
+  }
+
+  /**
+   * Get the voltage of the 6V rail.
+   *
+   * @return The controller 6V rail voltage value in Volts
+   */
+  public static double getVoltage6V() {
+    return PowerJNI.getUserVoltage6V();
+  }
+
+  /**
+   * Get the current output of the 6V rail.
+   *
+   * @return The controller 6V rail output current value in Amps
+   */
+  public static double getCurrent6V() {
+    return PowerJNI.getUserCurrent6V();
+  }
+
+  /**
+   * Get the enabled state of the 6V rail. The rail may be disabled due to a controller brownout, a
+   * short circuit on the rail, or controller over-voltage.
+   *
+   * @return The controller 6V rail enabled value
+   */
+  public static boolean getEnabled6V() {
+    return PowerJNI.getUserActive6V();
+  }
+
+  /**
+   * Get the count of the total current faults on the 6V rail since the controller has booted.
+   *
+   * @return The number of faults
+   */
+  public static int getFaultCount6V() {
+    return PowerJNI.getUserCurrentFaults6V();
+  }
+
+  /**
+   * Get the current status of the CAN bus.
+   *
+   * @return The status of the CAN bus
+   */
+  public static CANStatus getCANStatus() {
+    CANStatus status = new CANStatus();
+    CANJNI.GetCANStatus(status);
+    return status;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java
new file mode 100644
index 0000000..9092758
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java
@@ -0,0 +1,757 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Utility class for handling Robot drive based on a definition of the motor configuration. The
+ * robot drive class handles basic driving for a robot. Currently, 2 and 4 motor tank and mecanum
+ * drive trains are supported. In the future other drive types like swerve might be implemented.
+ * Motor channel numbers are supplied on creation of the class. Those are used for either the drive
+ * function (intended for hand created drive code, such as autonomous) or with the Tank/Arcade
+ * functions intended to be used for Operator Control driving.
+ *
+ * @deprecated Use {@link edu.wpi.first.wpilibj.drive.DifferentialDrive}
+ *             or {@link edu.wpi.first.wpilibj.drive.MecanumDrive} classes instead.
+ */
+@Deprecated
+public class RobotDrive implements MotorSafety {
+  protected MotorSafetyHelper m_safetyHelper;
+
+  /**
+   * The location of a motor on the robot for the purpose of driving.
+   */
+  public enum MotorType {
+    kFrontLeft(0), kFrontRight(1), kRearLeft(2), kRearRight(3);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    MotorType(int value) {
+      this.value = value;
+    }
+  }
+
+  public static final double kDefaultExpirationTime = 0.1;
+  public static final double kDefaultSensitivity = 0.5;
+  public static final double kDefaultMaxOutput = 1.0;
+  protected static final int kMaxNumberOfMotors = 4;
+  protected double m_sensitivity;
+  protected double m_maxOutput;
+  protected SpeedController m_frontLeftMotor;
+  protected SpeedController m_frontRightMotor;
+  protected SpeedController m_rearLeftMotor;
+  protected SpeedController m_rearRightMotor;
+  protected boolean m_allocatedSpeedControllers;
+  protected static boolean kArcadeRatioCurve_Reported = false;
+  protected static boolean kTank_Reported = false;
+  protected static boolean kArcadeStandard_Reported = false;
+  protected static boolean kMecanumCartesian_Reported = false;
+  protected static boolean kMecanumPolar_Reported = false;
+
+  /**
+   * Constructor for RobotDrive with 2 motors specified with channel numbers. Set up parameters for
+   * a two wheel drive system where the left and right motor pwm channels are specified in the call.
+   * This call assumes Talons for controlling the motors.
+   *
+   * @param leftMotorChannel  The PWM channel number that drives the left motor.
+   * @param rightMotorChannel The PWM channel number that drives the right motor.
+   */
+  public RobotDrive(final int leftMotorChannel, final int rightMotorChannel) {
+    m_sensitivity = kDefaultSensitivity;
+    m_maxOutput = kDefaultMaxOutput;
+    m_frontLeftMotor = null;
+    m_rearLeftMotor = new Talon(leftMotorChannel);
+    m_frontRightMotor = null;
+    m_rearRightMotor = new Talon(rightMotorChannel);
+    m_allocatedSpeedControllers = true;
+    setupMotorSafety();
+    drive(0, 0);
+  }
+
+  /**
+   * Constructor for RobotDrive with 4 motors specified with channel numbers. Set up parameters for
+   * a four wheel drive system where all four motor pwm channels are specified in the call. This
+   * call assumes Talons for controlling the motors.
+   *
+   * @param frontLeftMotor  Front left motor channel number
+   * @param rearLeftMotor   Rear Left motor channel number
+   * @param frontRightMotor Front right motor channel number
+   * @param rearRightMotor  Rear Right motor channel number
+   */
+  public RobotDrive(final int frontLeftMotor, final int rearLeftMotor, final int frontRightMotor,
+                    final int rearRightMotor) {
+    m_sensitivity = kDefaultSensitivity;
+    m_maxOutput = kDefaultMaxOutput;
+    m_rearLeftMotor = new Talon(rearLeftMotor);
+    m_rearRightMotor = new Talon(rearRightMotor);
+    m_frontLeftMotor = new Talon(frontLeftMotor);
+    m_frontRightMotor = new Talon(frontRightMotor);
+    m_allocatedSpeedControllers = true;
+    setupMotorSafety();
+    drive(0, 0);
+  }
+
+  /**
+   * Constructor for RobotDrive with 2 motors specified as SpeedController objects. The
+   * SpeedController version of the constructor enables programs to use the RobotDrive classes with
+   * subclasses of the SpeedController objects, for example, versions with ramping or reshaping of
+   * the curve to suit motor bias or dead-band elimination.
+   *
+   * @param leftMotor  The left SpeedController object used to drive the robot.
+   * @param rightMotor the right SpeedController object used to drive the robot.
+   */
+  public RobotDrive(SpeedController leftMotor, SpeedController rightMotor) {
+    requireNonNull(leftMotor, "Provided left motor was null");
+    requireNonNull(rightMotor, "Provided right motor was null");
+
+    m_frontLeftMotor = null;
+    m_rearLeftMotor = leftMotor;
+    m_frontRightMotor = null;
+    m_rearRightMotor = rightMotor;
+    m_sensitivity = kDefaultSensitivity;
+    m_maxOutput = kDefaultMaxOutput;
+    m_allocatedSpeedControllers = false;
+    setupMotorSafety();
+    drive(0, 0);
+  }
+
+  /**
+   * Constructor for RobotDrive with 4 motors specified as SpeedController objects. Speed controller
+   * input version of RobotDrive (see previous comments).
+   *
+   * @param frontLeftMotor  The front left SpeedController object used to drive the robot
+   * @param rearLeftMotor   The back left SpeedController object used to drive the robot.
+   * @param frontRightMotor The front right SpeedController object used to drive the robot.
+   * @param rearRightMotor  The back right SpeedController object used to drive the robot.
+   */
+  public RobotDrive(SpeedController frontLeftMotor, SpeedController rearLeftMotor,
+                    SpeedController frontRightMotor, SpeedController rearRightMotor) {
+    m_frontLeftMotor = requireNonNull(frontLeftMotor, "frontLeftMotor cannot be null");
+    m_rearLeftMotor = requireNonNull(rearLeftMotor, "rearLeftMotor cannot be null");
+    m_frontRightMotor = requireNonNull(frontRightMotor, "frontRightMotor cannot be null");
+    m_rearRightMotor = requireNonNull(rearRightMotor, "rearRightMotor cannot be null");
+    m_sensitivity = kDefaultSensitivity;
+    m_maxOutput = kDefaultMaxOutput;
+    m_allocatedSpeedControllers = false;
+    setupMotorSafety();
+    drive(0, 0);
+  }
+
+  /**
+   * Drive the motors at "outputMagnitude" and "curve". Both outputMagnitude and curve are -1.0 to
+   * +1.0 values, where 0.0 represents stopped and not turning. {@literal curve < 0 will turn left
+   * and curve > 0} will turn right.
+   *
+   * <p>The algorithm for steering provides a constant turn radius for any normal speed range, both
+   * forward and backward. Increasing sensitivity causes sharper turns for fixed values of curve.
+   *
+   * <p>This function will most likely be used in an autonomous routine.
+   *
+   * @param outputMagnitude The speed setting for the outside wheel in a turn, forward or backwards,
+   *                        +1 to -1.
+   * @param curve           The rate of turn, constant for different forward speeds. Set {@literal
+   *                        curve < 0 for left turn or curve > 0 for right turn.} Set curve =
+   *                        e^(-r/w) to get a turn radius r for wheelbase w of your robot.
+   *                        Conversely, turn radius r = -ln(curve)*w for a given value of curve and
+   *                        wheelbase w.
+   */
+  public void drive(double outputMagnitude, double curve) {
+    final double leftOutput;
+    final double rightOutput;
+
+    if (!kArcadeRatioCurve_Reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, getNumMotors(),
+          tInstances.kRobotDrive_ArcadeRatioCurve);
+      kArcadeRatioCurve_Reported = true;
+    }
+    if (curve < 0) {
+      double value = Math.log(-curve);
+      double ratio = (value - m_sensitivity) / (value + m_sensitivity);
+      if (ratio == 0) {
+        ratio = .0000000001;
+      }
+      leftOutput = outputMagnitude / ratio;
+      rightOutput = outputMagnitude;
+    } else if (curve > 0) {
+      double value = Math.log(curve);
+      double ratio = (value - m_sensitivity) / (value + m_sensitivity);
+      if (ratio == 0) {
+        ratio = .0000000001;
+      }
+      leftOutput = outputMagnitude;
+      rightOutput = outputMagnitude / ratio;
+    } else {
+      leftOutput = outputMagnitude;
+      rightOutput = outputMagnitude;
+    }
+    setLeftRightMotorOutputs(leftOutput, rightOutput);
+  }
+
+  /**
+   * Provide tank steering using the stored robot configuration. drive the robot using two joystick
+   * inputs. The Y-axis will be selected from each Joystick object. The calculated values will be
+   * squared to decrease sensitivity at low speeds.
+   *
+   * @param leftStick  The joystick to control the left side of the robot.
+   * @param rightStick The joystick to control the right side of the robot.
+   */
+  public void tankDrive(GenericHID leftStick, GenericHID rightStick) {
+    requireNonNull(leftStick, "Provided left stick was null");
+    requireNonNull(rightStick, "Provided right stick was null");
+
+    tankDrive(leftStick.getY(), rightStick.getY(), true);
+  }
+
+  /**
+   * Provide tank steering using the stored robot configuration. drive the robot using two joystick
+   * inputs. The Y-axis will be selected from each Joystick object.
+   *
+   * @param leftStick     The joystick to control the left side of the robot.
+   * @param rightStick    The joystick to control the right side of the robot.
+   * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
+   */
+  public void tankDrive(GenericHID leftStick, GenericHID rightStick, boolean squaredInputs) {
+    requireNonNull(leftStick, "Provided left stick was null");
+    requireNonNull(rightStick, "Provided right stick was null");
+
+    tankDrive(leftStick.getY(), rightStick.getY(), squaredInputs);
+  }
+
+  /**
+   * Provide tank steering using the stored robot configuration. This function lets you pick the
+   * axis to be used on each Joystick object for the left and right sides of the robot. The
+   * calculated values will be squared to decrease sensitivity at low speeds.
+   *
+   * @param leftStick  The Joystick object to use for the left side of the robot.
+   * @param leftAxis   The axis to select on the left side Joystick object.
+   * @param rightStick The Joystick object to use for the right side of the robot.
+   * @param rightAxis  The axis to select on the right side Joystick object.
+   */
+  public void tankDrive(GenericHID leftStick, final int leftAxis, GenericHID rightStick,
+                        final int rightAxis) {
+    requireNonNull(leftStick, "Provided left stick was null");
+    requireNonNull(rightStick, "Provided right stick was null");
+
+    tankDrive(leftStick.getRawAxis(leftAxis), rightStick.getRawAxis(rightAxis), true);
+  }
+
+  /**
+   * Provide tank steering using the stored robot configuration. This function lets you pick the
+   * axis to be used on each Joystick object for the left and right sides of the robot.
+   *
+   * @param leftStick     The Joystick object to use for the left side of the robot.
+   * @param leftAxis      The axis to select on the left side Joystick object.
+   * @param rightStick    The Joystick object to use for the right side of the robot.
+   * @param rightAxis     The axis to select on the right side Joystick object.
+   * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
+   */
+  public void tankDrive(GenericHID leftStick, final int leftAxis, GenericHID rightStick,
+                        final int rightAxis, boolean squaredInputs) {
+    requireNonNull(leftStick, "Provided left stick was null");
+    requireNonNull(rightStick, "Provided right stick was null");
+
+    tankDrive(leftStick.getRawAxis(leftAxis), rightStick.getRawAxis(rightAxis), squaredInputs);
+  }
+
+  /**
+   * Provide tank steering using the stored robot configuration. This function lets you directly
+   * provide joystick values from any source.
+   *
+   * @param leftValue     The value of the left stick.
+   * @param rightValue    The value of the right stick.
+   * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
+   */
+  public void tankDrive(double leftValue, double rightValue, boolean squaredInputs) {
+
+    if (!kTank_Reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, getNumMotors(),
+          tInstances.kRobotDrive_Tank);
+      kTank_Reported = true;
+    }
+
+    leftValue = limit(leftValue);
+    rightValue = limit(rightValue);
+
+    // square the inputs (while preserving the sign) to increase fine control
+    // while permitting full power
+    if (squaredInputs) {
+      leftValue = Math.copySign(leftValue * leftValue, leftValue);
+      rightValue = Math.copySign(rightValue * rightValue, rightValue);
+    }
+    setLeftRightMotorOutputs(leftValue, rightValue);
+  }
+
+  /**
+   * Provide tank steering using the stored robot configuration. This function lets you directly
+   * provide joystick values from any source. The calculated values will be squared to decrease
+   * sensitivity at low speeds.
+   *
+   * @param leftValue  The value of the left stick.
+   * @param rightValue The value of the right stick.
+   */
+  public void tankDrive(double leftValue, double rightValue) {
+    tankDrive(leftValue, rightValue, true);
+  }
+
+  /**
+   * Arcade drive implements single stick driving. Given a single Joystick, the class assumes the Y
+   * axis for the move value and the X axis for the rotate value. (Should add more information here
+   * regarding the way that arcade drive works.)
+   *
+   * @param stick         The joystick to use for Arcade single-stick driving. The Y-axis will be
+   *                      selected for forwards/backwards and the X-axis will be selected for
+   *                      rotation rate.
+   * @param squaredInputs If true, the sensitivity will be decreased for small values
+   */
+  public void arcadeDrive(GenericHID stick, boolean squaredInputs) {
+    // simply call the full-featured arcadeDrive with the appropriate values
+    arcadeDrive(stick.getY(), stick.getX(), squaredInputs);
+  }
+
+  /**
+   * Arcade drive implements single stick driving. Given a single Joystick, the class assumes the Y
+   * axis for the move value and the X axis for the rotate value. (Should add more information here
+   * regarding the way that arcade drive works.) The calculated values will be squared to decrease
+   * sensitivity at low speeds.
+   *
+   * @param stick The joystick to use for Arcade single-stick driving. The Y-axis will be selected
+   *              for forwards/backwards and the X-axis will be selected for rotation rate.
+   */
+  public void arcadeDrive(GenericHID stick) {
+    arcadeDrive(stick, true);
+  }
+
+  /**
+   * Arcade drive implements single stick driving. Given two joystick instances and two axis,
+   * compute the values to send to either two or four motors.
+   *
+   * @param moveStick     The Joystick object that represents the forward/backward direction
+   * @param moveAxis      The axis on the moveStick object to use for forwards/backwards (typically
+   *                      Y_AXIS)
+   * @param rotateStick   The Joystick object that represents the rotation value
+   * @param rotateAxis    The axis on the rotation object to use for the rotate right/left
+   *                      (typically X_AXIS)
+   * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
+   */
+  public void arcadeDrive(GenericHID moveStick, final int moveAxis, GenericHID rotateStick,
+                          final int rotateAxis, boolean squaredInputs) {
+    double moveValue = moveStick.getRawAxis(moveAxis);
+    double rotateValue = rotateStick.getRawAxis(rotateAxis);
+
+    arcadeDrive(moveValue, rotateValue, squaredInputs);
+  }
+
+  /**
+   * Arcade drive implements single stick driving. Given two joystick instances and two axis,
+   * compute the values to send to either two or four motors. The calculated values will be
+   * squared to decrease sensitivity at low speeds.
+   *
+   * @param moveStick   The Joystick object that represents the forward/backward direction
+   * @param moveAxis    The axis on the moveStick object to use for forwards/backwards (typically
+   *                    Y_AXIS)
+   * @param rotateStick The Joystick object that represents the rotation value
+   * @param rotateAxis  The axis on the rotation object to use for the rotate right/left (typically
+   *                    X_AXIS)
+   */
+  public void arcadeDrive(GenericHID moveStick, final int moveAxis, GenericHID rotateStick,
+                          final int rotateAxis) {
+    arcadeDrive(moveStick, moveAxis, rotateStick, rotateAxis, true);
+  }
+
+  /**
+   * Arcade drive implements single stick driving. This function lets you directly provide
+   * joystick values from any source.
+   *
+   * @param moveValue     The value to use for forwards/backwards
+   * @param rotateValue   The value to use for the rotate right/left
+   * @param squaredInputs If set, decreases the sensitivity at low speeds
+   */
+  public void arcadeDrive(double moveValue, double rotateValue, boolean squaredInputs) {
+    // local variables to hold the computed PWM values for the motors
+    if (!kArcadeStandard_Reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, getNumMotors(),
+          tInstances.kRobotDrive_ArcadeStandard);
+      kArcadeStandard_Reported = true;
+    }
+
+    double leftMotorSpeed;
+    double rightMotorSpeed;
+
+    moveValue = limit(moveValue);
+    rotateValue = limit(rotateValue);
+
+    // square the inputs (while preserving the sign) to increase fine control
+    // while permitting full power
+    if (squaredInputs) {
+      // square the inputs (while preserving the sign) to increase fine control
+      // while permitting full power
+      moveValue = Math.copySign(moveValue * moveValue, moveValue);
+      rotateValue = Math.copySign(rotateValue * rotateValue, rotateValue);
+    }
+
+    if (moveValue > 0.0) {
+      if (rotateValue > 0.0) {
+        leftMotorSpeed = moveValue - rotateValue;
+        rightMotorSpeed = Math.max(moveValue, rotateValue);
+      } else {
+        leftMotorSpeed = Math.max(moveValue, -rotateValue);
+        rightMotorSpeed = moveValue + rotateValue;
+      }
+    } else {
+      if (rotateValue > 0.0) {
+        leftMotorSpeed = -Math.max(-moveValue, rotateValue);
+        rightMotorSpeed = moveValue + rotateValue;
+      } else {
+        leftMotorSpeed = moveValue - rotateValue;
+        rightMotorSpeed = -Math.max(-moveValue, -rotateValue);
+      }
+    }
+
+    setLeftRightMotorOutputs(leftMotorSpeed, rightMotorSpeed);
+  }
+
+  /**
+   * Arcade drive implements single stick driving. This function lets you directly provide
+   * joystick values from any source. The calculated values will be squared to decrease
+   * sensitivity at low speeds.
+   *
+   * @param moveValue   The value to use for forwards/backwards
+   * @param rotateValue The value to use for the rotate right/left
+   */
+  public void arcadeDrive(double moveValue, double rotateValue) {
+    arcadeDrive(moveValue, rotateValue, true);
+  }
+
+  /**
+   * Drive method for Mecanum wheeled robots.
+   *
+   * <p>A method for driving with Mecanum wheeled robots. There are 4 wheels on the robot, arranged
+   * so that the front and back wheels are toed in 45 degrees. When looking at the wheels from the
+   * top, the roller axles should form an X across the robot.
+   *
+   * <p>This is designed to be directly driven by joystick axes.
+   *
+   * @param x         The speed that the robot should drive in the X direction. [-1.0..1.0]
+   * @param y         The speed that the robot should drive in the Y direction. This input is
+   *                  inverted to match the forward == -1.0 that joysticks produce. [-1.0..1.0]
+   * @param rotation  The rate of rotation for the robot that is completely independent of the
+   *                  translation. [-1.0..1.0]
+   * @param gyroAngle The current angle reading from the gyro. Use this to implement field-oriented
+   *                  controls.
+   */
+  @SuppressWarnings("ParameterName")
+  public void mecanumDrive_Cartesian(double x, double y, double rotation, double gyroAngle) {
+    if (!kMecanumCartesian_Reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, getNumMotors(),
+          tInstances.kRobotDrive_MecanumCartesian);
+      kMecanumCartesian_Reported = true;
+    }
+    @SuppressWarnings("LocalVariableName")
+    double xIn = x;
+    @SuppressWarnings("LocalVariableName")
+    double yIn = y;
+    // Negate y for the joystick.
+    yIn = -yIn;
+    // Compensate for gyro angle.
+    double[] rotated = rotateVector(xIn, yIn, gyroAngle);
+    xIn = rotated[0];
+    yIn = rotated[1];
+
+    double[] wheelSpeeds = new double[kMaxNumberOfMotors];
+    wheelSpeeds[MotorType.kFrontLeft.value] = xIn + yIn + rotation;
+    wheelSpeeds[MotorType.kFrontRight.value] = -xIn + yIn - rotation;
+    wheelSpeeds[MotorType.kRearLeft.value] = -xIn + yIn + rotation;
+    wheelSpeeds[MotorType.kRearRight.value] = xIn + yIn - rotation;
+
+    normalize(wheelSpeeds);
+    m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft.value] * m_maxOutput);
+    m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight.value] * m_maxOutput);
+    m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft.value] * m_maxOutput);
+    m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight.value] * m_maxOutput);
+
+    if (m_safetyHelper != null) {
+      m_safetyHelper.feed();
+    }
+  }
+
+  /**
+   * Drive method for Mecanum wheeled robots.
+   *
+   * <p>A method for driving with Mecanum wheeled robots. There are 4 wheels on the robot, arranged
+   * so that the front and back wheels are toed in 45 degrees. When looking at the wheels from the
+   * top, the roller axles should form an X across the robot.
+   *
+   * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0]
+   * @param direction The angle the robot should drive in degrees. The direction and magnitude
+   *                  are independent of the rotation rate. [-180.0..180.0]
+   * @param rotation  The rate of rotation for the robot that is completely independent of the
+   *                  magnitude or direction. [-1.0..1.0]
+   */
+  public void mecanumDrive_Polar(double magnitude, double direction, double rotation) {
+    if (!kMecanumPolar_Reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, getNumMotors(),
+          tInstances.kRobotDrive_MecanumPolar);
+      kMecanumPolar_Reported = true;
+    }
+    // Normalized for full power along the Cartesian axes.
+    magnitude = limit(magnitude) * Math.sqrt(2.0);
+    // The rollers are at 45 degree angles.
+    double dirInRad = (direction + 45.0) * Math.PI / 180.0;
+    double cosD = Math.cos(dirInRad);
+    double sinD = Math.sin(dirInRad);
+
+    double[] wheelSpeeds = new double[kMaxNumberOfMotors];
+    wheelSpeeds[MotorType.kFrontLeft.value] = sinD * magnitude + rotation;
+    wheelSpeeds[MotorType.kFrontRight.value] = cosD * magnitude - rotation;
+    wheelSpeeds[MotorType.kRearLeft.value] = cosD * magnitude + rotation;
+    wheelSpeeds[MotorType.kRearRight.value] = sinD * magnitude - rotation;
+
+    normalize(wheelSpeeds);
+
+    m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft.value] * m_maxOutput);
+    m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight.value] * m_maxOutput);
+    m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft.value] * m_maxOutput);
+    m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight.value] * m_maxOutput);
+
+    if (m_safetyHelper != null) {
+      m_safetyHelper.feed();
+    }
+  }
+
+  /**
+   * Holonomic Drive method for Mecanum wheeled robots.
+   *
+   * <p>This is an alias to mecanumDrive_Polar() for backward compatibility
+   *
+   * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0]
+   * @param direction The direction the robot should drive. The direction and maginitude are
+   *                  independent of the rotation rate.
+   * @param rotation  The rate of rotation for the robot that is completely independent of the
+   *                  magnitute or direction. [-1.0..1.0]
+   */
+  void holonomicDrive(double magnitude, double direction, double rotation) {
+    mecanumDrive_Polar(magnitude, direction, rotation);
+  }
+
+  /**
+   * Set the speed of the right and left motors. This is used once an appropriate drive setup
+   * function is called such as twoWheelDrive(). The motors are set to "leftSpeed" and
+   * "rightSpeed" and includes flipping the direction of one side for opposing motors.
+   *
+   * @param leftOutput  The speed to send to the left side of the robot.
+   * @param rightOutput The speed to send to the right side of the robot.
+   */
+  public void setLeftRightMotorOutputs(double leftOutput, double rightOutput) {
+    requireNonNull(m_rearLeftMotor, "Provided left motor was null");
+    requireNonNull(m_rearRightMotor, "Provided right motor was null");
+
+    if (m_frontLeftMotor != null) {
+      m_frontLeftMotor.set(limit(leftOutput) * m_maxOutput);
+    }
+    m_rearLeftMotor.set(limit(leftOutput) * m_maxOutput);
+
+    if (m_frontRightMotor != null) {
+      m_frontRightMotor.set(-limit(rightOutput) * m_maxOutput);
+    }
+    m_rearRightMotor.set(-limit(rightOutput) * m_maxOutput);
+
+    if (m_safetyHelper != null) {
+      m_safetyHelper.feed();
+    }
+  }
+
+  /**
+   * Limit motor values to the -1.0 to +1.0 range.
+   */
+  protected static double limit(double number) {
+    if (number > 1.0) {
+      return 1.0;
+    }
+    if (number < -1.0) {
+      return -1.0;
+    }
+    return number;
+  }
+
+  /**
+   * Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
+   */
+  protected static void normalize(double[] wheelSpeeds) {
+    double maxMagnitude = Math.abs(wheelSpeeds[0]);
+    for (int i = 1; i < kMaxNumberOfMotors; i++) {
+      double temp = Math.abs(wheelSpeeds[i]);
+      if (maxMagnitude < temp) {
+        maxMagnitude = temp;
+      }
+    }
+    if (maxMagnitude > 1.0) {
+      for (int i = 0; i < kMaxNumberOfMotors; i++) {
+        wheelSpeeds[i] = wheelSpeeds[i] / maxMagnitude;
+      }
+    }
+  }
+
+  /**
+   * Rotate a vector in Cartesian space.
+   */
+  @SuppressWarnings("ParameterName")
+  protected static double[] rotateVector(double x, double y, double angle) {
+    double cosA = Math.cos(angle * (Math.PI / 180.0));
+    double sinA = Math.sin(angle * (Math.PI / 180.0));
+    double[] out = new double[2];
+    out[0] = x * cosA - y * sinA;
+    out[1] = x * sinA + y * cosA;
+    return out;
+  }
+
+  /**
+   * Invert a motor direction. This is used when a motor should run in the opposite direction as the
+   * drive code would normally run it. Motors that are direct drive would be inverted, the drive
+   * code assumes that the motors are geared with one reversal.
+   *
+   * @param motor      The motor index to invert.
+   * @param isInverted True if the motor should be inverted when operated.
+   */
+  public void setInvertedMotor(MotorType motor, boolean isInverted) {
+    switch (motor) {
+      case kFrontLeft:
+        m_frontLeftMotor.setInverted(isInverted);
+        break;
+      case kFrontRight:
+        m_frontRightMotor.setInverted(isInverted);
+        break;
+      case kRearLeft:
+        m_rearLeftMotor.setInverted(isInverted);
+        break;
+      case kRearRight:
+        m_rearRightMotor.setInverted(isInverted);
+        break;
+      default:
+        throw new IllegalArgumentException("Illegal motor type: " + motor);
+    }
+  }
+
+  /**
+   * Set the turning sensitivity.
+   *
+   * <p>This only impacts the drive() entry-point.
+   *
+   * @param sensitivity Effectively sets the turning sensitivity (or turn radius for a given value)
+   */
+  public void setSensitivity(double sensitivity) {
+    m_sensitivity = sensitivity;
+  }
+
+  /**
+   * Configure the scaling factor for using RobotDrive with motor controllers in a mode other than
+   * PercentVbus.
+   *
+   * @param maxOutput Multiplied with the output percentage computed by the drive functions.
+   */
+  public void setMaxOutput(double maxOutput) {
+    m_maxOutput = maxOutput;
+  }
+
+  /**
+   * Free the speed controllers if they were allocated locally.
+   */
+  public void free() {
+    if (m_allocatedSpeedControllers) {
+      if (m_frontLeftMotor != null) {
+        ((PWM) m_frontLeftMotor).free();
+      }
+      if (m_frontRightMotor != null) {
+        ((PWM) m_frontRightMotor).free();
+      }
+      if (m_rearLeftMotor != null) {
+        ((PWM) m_rearLeftMotor).free();
+      }
+      if (m_rearRightMotor != null) {
+        ((PWM) m_rearRightMotor).free();
+      }
+    }
+  }
+
+  @Override
+  public void setExpiration(double timeout) {
+    m_safetyHelper.setExpiration(timeout);
+  }
+
+  @Override
+  public double getExpiration() {
+    return m_safetyHelper.getExpiration();
+  }
+
+  @Override
+  public boolean isAlive() {
+    return m_safetyHelper.isAlive();
+  }
+
+  @Override
+  public boolean isSafetyEnabled() {
+    return m_safetyHelper.isSafetyEnabled();
+  }
+
+  @Override
+  public void setSafetyEnabled(boolean enabled) {
+    m_safetyHelper.setSafetyEnabled(enabled);
+  }
+
+  @Override
+  public String getDescription() {
+    return "Robot Drive";
+  }
+
+  @Override
+  public void stopMotor() {
+    if (m_frontLeftMotor != null) {
+      m_frontLeftMotor.stopMotor();
+    }
+    if (m_frontRightMotor != null) {
+      m_frontRightMotor.stopMotor();
+    }
+    if (m_rearLeftMotor != null) {
+      m_rearLeftMotor.stopMotor();
+    }
+    if (m_rearRightMotor != null) {
+      m_rearRightMotor.stopMotor();
+    }
+    if (m_safetyHelper != null) {
+      m_safetyHelper.feed();
+    }
+  }
+
+  private void setupMotorSafety() {
+    m_safetyHelper = new MotorSafetyHelper(this);
+    m_safetyHelper.setExpiration(kDefaultExpirationTime);
+    m_safetyHelper.setSafetyEnabled(true);
+  }
+
+  protected int getNumMotors() {
+    int motors = 0;
+    if (m_frontLeftMotor != null) {
+      motors++;
+    }
+    if (m_frontRightMotor != null) {
+      motors++;
+    }
+    if (m_rearLeftMotor != null) {
+      motors++;
+    }
+    if (m_rearRightMotor != null) {
+      motors++;
+    }
+    return motors;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotState.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotState.java
new file mode 100644
index 0000000..98d847f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotState.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.wpilibj.util.BaseSystemNotInitializedException;
+
+@SuppressWarnings("JavadocMethod")
+public class RobotState {
+  private static Interface m_impl;
+
+  @SuppressWarnings("MethodName")
+  public static void SetImplementation(Interface implementation) {
+    m_impl = implementation;
+  }
+
+  public static boolean isDisabled() {
+    if (m_impl != null) {
+      return m_impl.isDisabled();
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
+    }
+  }
+
+  public static boolean isEnabled() {
+    if (m_impl != null) {
+      return m_impl.isEnabled();
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
+    }
+  }
+
+  public static boolean isOperatorControl() {
+    if (m_impl != null) {
+      return m_impl.isOperatorControl();
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
+    }
+  }
+
+  public static boolean isAutonomous() {
+    if (m_impl != null) {
+      return m_impl.isAutonomous();
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
+    }
+  }
+
+  public static boolean isTest() {
+    if (m_impl != null) {
+      return m_impl.isTest();
+    } else {
+      throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
+    }
+  }
+
+  interface Interface {
+    boolean isDisabled();
+
+    boolean isEnabled();
+
+    boolean isOperatorControl();
+
+    boolean isAutonomous();
+
+    boolean isTest();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SD540.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SD540.java
new file mode 100644
index 0000000..0da8839
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SD540.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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Mindsensors SD540 Speed Controller.
+ */
+public class SD540 extends PWMSpeedController {
+  /**
+   * Common initialization code called by all constructors.
+   *
+   * <p>Note that the SD540 uses the following bounds for PWM values. These values should work
+   * reasonably well for most controllers, but if users experience issues such as asymmetric
+   * behavior around the deadband or inability to saturate the controller in either direction,
+   * calibration is recommended. The calibration procedure can be found in the SD540 User Manual
+   * available from Mindsensors.
+   *
+   * <p>- 2.05ms = full "forward" - 1.55ms = the "high end" of the deadband range - 1.50ms = center
+   * of the deadband range (off) - 1.44ms = the "low end" of the deadband range - .94ms = full
+   * "reverse"
+   */
+  protected void initSD540() {
+    setBounds(2.05, 1.55, 1.50, 1.44, .94);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    HAL.report(tResourceType.kResourceType_MindsensorsSD540, getChannel());
+    setName("SD540", getChannel());
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param channel The PWM channel that the SD540 is attached to. 0-9 are on-board, 10-19 are on
+   *                the MXP port
+   */
+  public SD540(final int channel) {
+    super(channel);
+    initSD540();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java
new file mode 100644
index 0000000..e80c4d2
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java
@@ -0,0 +1,680 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.nio.ByteBuffer;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.SPIJNI;
+
+/**
+ * Represents a SPI bus port.
+ */
+public class SPI {
+  public enum Port {
+    kOnboardCS0(0), kOnboardCS1(1), kOnboardCS2(2), kOnboardCS3(3), kMXP(4);
+
+    @SuppressWarnings("MemberName")
+    public int value;
+
+    Port(int value) {
+      this.value = value;
+    }
+  }
+
+  private static int devices = 0;
+
+  private int m_port;
+  private int m_bitOrder;
+  private int m_clockPolarity;
+  private int m_dataOnTrailing;
+
+  /**
+   * Constructor.
+   *
+   * @param port the physical SPI port
+   */
+  public SPI(Port port) {
+    m_port = (byte) port.value;
+    devices++;
+
+    SPIJNI.spiInitialize(m_port);
+
+    HAL.report(tResourceType.kResourceType_SPI, devices);
+  }
+
+  /**
+   * Free the resources used by this object.
+   */
+  public void free() {
+    if (m_accum != null) {
+      m_accum.free();
+      m_accum = null;
+    }
+    SPIJNI.spiClose(m_port);
+  }
+
+  /**
+   * Configure the rate of the generated clock signal. The default value is 500,000 Hz. The maximum
+   * value is 4,000,000 Hz.
+   *
+   * @param hz The clock rate in Hertz.
+   */
+  public final void setClockRate(int hz) {
+    SPIJNI.spiSetSpeed(m_port, hz);
+  }
+
+  /**
+   * Configure the order that bits are sent and received on the wire to be most significant bit
+   * first.
+   */
+  public final void setMSBFirst() {
+    m_bitOrder = 1;
+    SPIJNI.spiSetOpts(m_port, m_bitOrder, m_dataOnTrailing, m_clockPolarity);
+  }
+
+  /**
+   * Configure the order that bits are sent and received on the wire to be least significant bit
+   * first.
+   */
+  public final void setLSBFirst() {
+    m_bitOrder = 0;
+    SPIJNI.spiSetOpts(m_port, m_bitOrder, m_dataOnTrailing, m_clockPolarity);
+  }
+
+  /**
+   * Configure the clock output line to be active low. This is sometimes called clock polarity high
+   * or clock idle high.
+   */
+  public final void setClockActiveLow() {
+    m_clockPolarity = 1;
+    SPIJNI.spiSetOpts(m_port, m_bitOrder, m_dataOnTrailing, m_clockPolarity);
+  }
+
+  /**
+   * Configure the clock output line to be active high. This is sometimes called clock polarity low
+   * or clock idle low.
+   */
+  public final void setClockActiveHigh() {
+    m_clockPolarity = 0;
+    SPIJNI.spiSetOpts(m_port, m_bitOrder, m_dataOnTrailing, m_clockPolarity);
+  }
+
+  /**
+   * Configure that the data is stable on the falling edge and the data changes on the rising edge.
+   */
+  public final void setSampleDataOnFalling() {
+    m_dataOnTrailing = 1;
+    SPIJNI.spiSetOpts(m_port, m_bitOrder, m_dataOnTrailing, m_clockPolarity);
+  }
+
+  /**
+   * Configure that the data is stable on the rising edge and the data changes on the falling edge.
+   */
+  public final void setSampleDataOnRising() {
+    m_dataOnTrailing = 0;
+    SPIJNI.spiSetOpts(m_port, m_bitOrder, m_dataOnTrailing, m_clockPolarity);
+  }
+
+  /**
+   * Configure the chip select line to be active high.
+   */
+  public final void setChipSelectActiveHigh() {
+    SPIJNI.spiSetChipSelectActiveHigh(m_port);
+  }
+
+  /**
+   * Configure the chip select line to be active low.
+   */
+  public final void setChipSelectActiveLow() {
+    SPIJNI.spiSetChipSelectActiveLow(m_port);
+  }
+
+  /**
+   * Write data to the slave device. Blocks until there is space in the output FIFO.
+   *
+   * <p>If not running in output only mode, also saves the data received on the MISO input during
+   * the transfer into the receive FIFO.
+   */
+  public int write(byte[] dataToSend, int size) {
+    if (dataToSend.length < size) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + size);
+    }
+    return SPIJNI.spiWriteB(m_port, dataToSend, (byte) size);
+  }
+
+  /**
+   * Write data to the slave device. Blocks until there is space in the output FIFO.
+   *
+   * <p>If not running in output only mode, also saves the data received on the MISO input during
+   * the transfer into the receive FIFO.
+   *
+   * @param dataToSend The buffer containing the data to send.
+   */
+  public int write(ByteBuffer dataToSend, int size) {
+    if (dataToSend.hasArray()) {
+      return write(dataToSend.array(), size);
+    }
+    if (!dataToSend.isDirect()) {
+      throw new IllegalArgumentException("must be a direct buffer");
+    }
+    if (dataToSend.capacity() < size) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + size);
+    }
+    return SPIJNI.spiWrite(m_port, dataToSend, (byte) size);
+  }
+
+  /**
+   * Read a word from the receive FIFO.
+   *
+   * <p>Waits for the current transfer to complete if the receive FIFO is empty.
+   *
+   * <p>If the receive FIFO is empty, there is no active transfer, and initiate is false, errors.
+   *
+   * @param initiate If true, this function pushes "0" into the transmit buffer and initiates a
+   *                 transfer. If false, this function assumes that data is already in the receive
+   *                 FIFO from a previous write.
+   */
+  public int read(boolean initiate, byte[] dataReceived, int size) {
+    if (dataReceived.length < size) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + size);
+    }
+    return SPIJNI.spiReadB(m_port, initiate, dataReceived, (byte) size);
+  }
+
+  /**
+   * Read a word from the receive FIFO.
+   *
+   * <p>Waits for the current transfer to complete if the receive FIFO is empty.
+   *
+   * <p>If the receive FIFO is empty, there is no active transfer, and initiate is false, errors.
+   *
+   * @param initiate     If true, this function pushes "0" into the transmit buffer and initiates
+   *                     a transfer. If false, this function assumes that data is already in the
+   *                     receive FIFO from a previous write.
+   * @param dataReceived The buffer to be filled with the received data.
+   * @param size         The length of the transaction, in bytes
+   */
+  public int read(boolean initiate, ByteBuffer dataReceived, int size) {
+    if (dataReceived.hasArray()) {
+      return read(initiate, dataReceived.array(), size);
+    }
+    if (!dataReceived.isDirect()) {
+      throw new IllegalArgumentException("must be a direct buffer");
+    }
+    if (dataReceived.capacity() < size) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + size);
+    }
+    return SPIJNI.spiRead(m_port, initiate, dataReceived, (byte) size);
+  }
+
+  /**
+   * Perform a simultaneous read/write transaction with the device.
+   *
+   * @param dataToSend   The data to be written out to the device
+   * @param dataReceived Buffer to receive data from the device
+   * @param size         The length of the transaction, in bytes
+   */
+  public int transaction(byte[] dataToSend, byte[] dataReceived, int size) {
+    if (dataToSend.length < size) {
+      throw new IllegalArgumentException("dataToSend is too small, must be at least " + size);
+    }
+    if (dataReceived.length < size) {
+      throw new IllegalArgumentException("dataReceived is too small, must be at least " + size);
+    }
+    return SPIJNI.spiTransactionB(m_port, dataToSend, dataReceived, (byte) size);
+  }
+
+  /**
+   * Perform a simultaneous read/write transaction with the device.
+   *
+   * @param dataToSend   The data to be written out to the device.
+   * @param dataReceived Buffer to receive data from the device.
+   * @param size         The length of the transaction, in bytes
+   */
+  public int transaction(ByteBuffer dataToSend, ByteBuffer dataReceived, int size) {
+    if (dataToSend.hasArray() && dataReceived.hasArray()) {
+      return transaction(dataToSend.array(), dataReceived.array(), size);
+    }
+    if (!dataToSend.isDirect()) {
+      throw new IllegalArgumentException("dataToSend must be a direct buffer");
+    }
+    if (dataToSend.capacity() < size) {
+      throw new IllegalArgumentException("dataToSend is too small, must be at least " + size);
+    }
+    if (!dataReceived.isDirect()) {
+      throw new IllegalArgumentException("dataReceived must be a direct buffer");
+    }
+    if (dataReceived.capacity() < size) {
+      throw new IllegalArgumentException("dataReceived is too small, must be at least " + size);
+    }
+    return SPIJNI.spiTransaction(m_port, dataToSend, dataReceived, (byte) size);
+  }
+
+  /**
+   * Initialize automatic SPI transfer engine.
+   *
+   * <p>Only a single engine is available, and use of it blocks use of all other
+   * chip select usage on the same physical SPI port while it is running.
+   *
+   * @param bufferSize buffer size in bytes
+   */
+  public void initAuto(int bufferSize) {
+    SPIJNI.spiInitAuto(m_port, bufferSize);
+  }
+
+  /**
+   * Frees the automatic SPI transfer engine.
+   */
+  public void freeAuto() {
+    SPIJNI.spiFreeAuto(m_port);
+  }
+
+  /**
+   * Set the data to be transmitted by the engine.
+   *
+   * <p>Up to 16 bytes are configurable, and may be followed by up to 127 zero
+   * bytes.
+   *
+   * @param dataToSend data to send (maximum 16 bytes)
+   * @param zeroSize number of zeros to send after the data
+   */
+  public void setAutoTransmitData(byte[] dataToSend, int zeroSize) {
+    SPIJNI.spiSetAutoTransmitData(m_port, dataToSend, zeroSize);
+  }
+
+  /**
+   * Start running the automatic SPI transfer engine at a periodic rate.
+   *
+   * <p>{@link #initAuto(int)} and {@link #setAutoTransmitData(byte[], int)} must
+   * be called before calling this function.
+   *
+   * @param period period between transfers, in seconds (us resolution)
+   */
+  public void startAutoRate(double period) {
+    SPIJNI.spiStartAutoRate(m_port, period);
+  }
+
+  /**
+   * Start running the automatic SPI transfer engine when a trigger occurs.
+   *
+   * <p>{@link #initAuto(int)} and {@link #setAutoTransmitData(byte[], int)} must
+   * be called before calling this function.
+   *
+   * @param source digital source for the trigger (may be an analog trigger)
+   * @param rising trigger on the rising edge
+   * @param falling trigger on the falling edge
+   */
+  public void startAutoTrigger(DigitalSource source, boolean rising, boolean falling) {
+    SPIJNI.spiStartAutoTrigger(m_port, source.getPortHandleForRouting(),
+                               source.getAnalogTriggerTypeForRouting(), rising, falling);
+  }
+
+  /**
+   * Stop running the automatic SPI transfer engine.
+   */
+  public void stopAuto() {
+    SPIJNI.spiStopAuto(m_port);
+  }
+
+  /**
+   * Force the engine to make a single transfer.
+   */
+  public void forceAutoRead() {
+    SPIJNI.spiForceAutoRead(m_port);
+  }
+
+  /**
+   * Read data that has been transferred by the automatic SPI transfer engine.
+   *
+   * <p>Transfers may be made a byte at a time, so it's necessary for the caller
+   * to handle cases where an entire transfer has not been completed.
+   *
+   * <p>Blocks until numToRead bytes have been read or timeout expires.
+   * May be called with numToRead=0 to retrieve how many bytes are available.
+   *
+   * @param buffer buffer where read bytes are stored
+   * @param numToRead number of bytes to read
+   * @param timeout timeout in seconds (ms resolution)
+   * @return Number of bytes remaining to be read
+   */
+  public int readAutoReceivedData(ByteBuffer buffer, int numToRead, double timeout) {
+    if (buffer.hasArray()) {
+      return readAutoReceivedData(buffer.array(), numToRead, timeout);
+    }
+    if (!buffer.isDirect()) {
+      throw new IllegalArgumentException("must be a direct buffer");
+    }
+    if (buffer.capacity() < numToRead) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + numToRead);
+    }
+    return SPIJNI.spiReadAutoReceivedData(m_port, buffer, numToRead, timeout);
+  }
+
+  /**
+   * Read data that has been transferred by the automatic SPI transfer engine.
+   *
+   * <p>Transfers may be made a byte at a time, so it's necessary for the caller
+   * to handle cases where an entire transfer has not been completed.
+   *
+   * <p>Blocks until numToRead bytes have been read or timeout expires.
+   * May be called with numToRead=0 to retrieve how many bytes are available.
+   *
+   * @param buffer array where read bytes are stored
+   * @param numToRead number of bytes to read
+   * @param timeout timeout in seconds (ms resolution)
+   * @return Number of bytes remaining to be read
+   */
+  public int readAutoReceivedData(byte[] buffer, int numToRead, double timeout) {
+    if (buffer.length < numToRead) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + numToRead);
+    }
+    return SPIJNI.spiReadAutoReceivedData(m_port, buffer, numToRead, timeout);
+  }
+
+  /**
+   * Get the number of bytes dropped by the automatic SPI transfer engine due
+   * to the receive buffer being full.
+   *
+   * @return Number of bytes dropped
+   */
+  public int getAutoDroppedCount() {
+    return SPIJNI.spiGetAutoDroppedCount(m_port);
+  }
+
+  private static final int kAccumulateDepth = 2048;
+
+  private static class Accumulator {
+    Accumulator(int port, int xferSize, int validMask, int validValue, int dataShift,
+                int dataSize, boolean isSigned, boolean bigEndian) {
+      m_notifier = new Notifier(this::update);
+      m_buf = ByteBuffer.allocateDirect(xferSize * kAccumulateDepth);
+      m_xferSize = xferSize;
+      m_validMask = validMask;
+      m_validValue = validValue;
+      m_dataShift = dataShift;
+      m_dataMax = 1 << dataSize;
+      m_dataMsbMask = 1 << (dataSize - 1);
+      m_isSigned = isSigned;
+      m_bigEndian = bigEndian;
+      m_port = port;
+    }
+
+    void free() {
+      m_notifier.stop();
+    }
+
+    final Notifier m_notifier;
+    final ByteBuffer m_buf;
+    final Object m_mutex = new Object();
+
+    long m_value;
+    int m_count;
+    int m_lastValue;
+
+    int m_center;
+    int m_deadband;
+
+    final int m_validMask;
+    final int m_validValue;
+    final int m_dataMax;        // one more than max data value
+    final int m_dataMsbMask;    // data field MSB mask (for signed)
+    final int m_dataShift;      // data field shift right amount, in bits
+    final int m_xferSize;       // SPI transfer size, in bytes
+    final boolean m_isSigned;   // is data field signed?
+    final boolean m_bigEndian;  // is response big endian?
+    final int m_port;
+
+    void update() {
+      synchronized (m_mutex) {
+        boolean done = false;
+        while (!done) {
+          done = true;
+
+          // get amount of data available
+          int numToRead = SPIJNI.spiReadAutoReceivedData(m_port, m_buf, 0, 0);
+
+          // only get whole responses
+          numToRead -= numToRead % m_xferSize;
+          if (numToRead > m_xferSize * kAccumulateDepth) {
+            numToRead = m_xferSize * kAccumulateDepth;
+            done = false;
+          }
+          if (numToRead == 0) {
+            return;  // no samples
+          }
+
+          // read buffered data
+          SPIJNI.spiReadAutoReceivedData(m_port, m_buf, numToRead, 0);
+
+          // loop over all responses
+          for (int off = 0; off < numToRead; off += m_xferSize) {
+            // convert from bytes
+            int resp = 0;
+            if (m_bigEndian) {
+              for (int i = 0; i < m_xferSize; ++i) {
+                resp <<= 8;
+                resp |= ((int) m_buf.get(off + i)) & 0xff;
+              }
+            } else {
+              for (int i = m_xferSize - 1; i >= 0; --i) {
+                resp <<= 8;
+                resp |= ((int) m_buf.get(off + i)) & 0xff;
+              }
+            }
+
+            // process response
+            if ((resp & m_validMask) == m_validValue) {
+              // valid sensor data; extract data field
+              int data = resp >> m_dataShift;
+              data &= m_dataMax - 1;
+              // 2s complement conversion if signed MSB is set
+              if (m_isSigned && (data & m_dataMsbMask) != 0) {
+                data -= m_dataMax;
+              }
+              // center offset
+              data -= m_center;
+              // only accumulate if outside deadband
+              if (data < -m_deadband || data > m_deadband) {
+                m_value += data;
+              }
+              ++m_count;
+              m_lastValue = data;
+            } else {
+              // no data from the sensor; just clear the last value
+              m_lastValue = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  private Accumulator m_accum = null;
+
+  /**
+   * Initialize the accumulator.
+   *
+   * @param period     Time between reads
+   * @param cmd        SPI command to send to request data
+   * @param xferSize   SPI transfer size, in bytes
+   * @param validMask  Mask to apply to received data for validity checking
+   * @param validValue After validMask is applied, required matching value for validity checking
+   * @param dataShift  Bit shift to apply to received data to get actual data value
+   * @param dataSize   Size (in bits) of data field
+   * @param isSigned   Is data field signed?
+   * @param bigEndian  Is device big endian?
+   */
+  public void initAccumulator(double period, int cmd, int xferSize,
+                              int validMask, int validValue,
+                              int dataShift, int dataSize,
+                              boolean isSigned, boolean bigEndian) {
+    initAuto(xferSize * 2048);
+    byte[] cmdBytes = new byte[] {0, 0, 0, 0};
+    if (bigEndian) {
+      for (int i = xferSize - 1; i >= 0; --i) {
+        cmdBytes[i] = (byte) (cmd & 0xff);
+        cmd >>= 8;
+      }
+    } else {
+      cmdBytes[0] = (byte) (cmd & 0xff);
+      cmd >>= 8;
+      cmdBytes[1] = (byte) (cmd & 0xff);
+      cmd >>= 8;
+      cmdBytes[2] = (byte) (cmd & 0xff);
+      cmd >>= 8;
+      cmdBytes[3] = (byte) (cmd & 0xff);
+    }
+    setAutoTransmitData(cmdBytes, xferSize - 4);
+    startAutoRate(period);
+
+    m_accum = new Accumulator(m_port, xferSize, validMask, validValue, dataShift, dataSize,
+                              isSigned, bigEndian);
+    m_accum.m_notifier.startPeriodic(period * 1024);
+  }
+
+  /**
+   * Frees the accumulator.
+   */
+  public void freeAccumulator() {
+    if (m_accum != null) {
+      m_accum.free();
+      m_accum = null;
+    }
+    freeAuto();
+  }
+
+  /**
+   * Resets the accumulator to zero.
+   */
+  public void resetAccumulator() {
+    if (m_accum == null) {
+      return;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.m_value = 0;
+      m_accum.m_count = 0;
+      m_accum.m_lastValue = 0;
+    }
+  }
+
+  /**
+   * Set the center value of the accumulator.
+   *
+   * <p>The center value is subtracted from each 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.
+   */
+  public void setAccumulatorCenter(int center) {
+    if (m_accum == null) {
+      return;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.m_center = center;
+    }
+  }
+
+  /**
+   * Set the accumulator's deadband.
+   */
+  public void setAccumulatorDeadband(int deadband) {
+    if (m_accum == null) {
+      return;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.m_deadband = deadband;
+    }
+  }
+
+  /**
+   * Read the last value read by the accumulator engine.
+   */
+  public int getAccumulatorLastValue() {
+    if (m_accum == null) {
+      return 0;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.update();
+      return m_accum.m_lastValue;
+    }
+  }
+
+  /**
+   * Read the accumulated value.
+   *
+   * @return The 64-bit value accumulated since the last Reset().
+   */
+  public long getAccumulatorValue() {
+    if (m_accum == null) {
+      return 0;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.update();
+      return m_accum.m_value;
+    }
+  }
+
+  /**
+   * Read the number of accumulated values.
+   *
+   * <p>Read the count of the accumulated values since the accumulator was last Reset().
+   *
+   * @return The number of times samples from the channel were accumulated.
+   */
+  public int getAccumulatorCount() {
+    if (m_accum == null) {
+      return 0;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.update();
+      return m_accum.m_count;
+    }
+  }
+
+  /**
+   * Read the average of the accumulated value.
+   *
+   * @return The accumulated average value (value / count).
+   */
+  public double getAccumulatorAverage() {
+    if (m_accum == null) {
+      return 0;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.update();
+      if (m_accum.m_count == 0) {
+        return 0.0;
+      }
+      return ((double) m_accum.m_value) / m_accum.m_count;
+    }
+  }
+
+  /**
+   * Read the accumulated value and the number of accumulated values atomically.
+   *
+   * <p>This function reads the value and count atomically. This can be used for averaging.
+   *
+   * @param result AccumulatorResult object to store the results in.
+   */
+  public void getAccumulatorOutput(AccumulatorResult result) {
+    if (result == null) {
+      throw new IllegalArgumentException("Null parameter `result'");
+    }
+    if (m_accum == null) {
+      result.value = 0;
+      result.count = 0;
+      return;
+    }
+    synchronized (m_accum.m_mutex) {
+      m_accum.update();
+      result.value = m_accum.m_value;
+      result.count = m_accum.m_count;
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SafePWM.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SafePWM.java
new file mode 100644
index 0000000..f48ddb1
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SafePWM.java
@@ -0,0 +1,105 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * Manages a PWM object.
+ */
+public class SafePWM extends PWM implements MotorSafety {
+  private final MotorSafetyHelper m_safetyHelper;
+
+  /**
+   * Constructor for a SafePWM object taking a channel number.
+   *
+   * @param channel The channel number to be used for the underlying PWM object. 0-9 are on-board,
+   *                10-19 are on the MXP port.
+   */
+  public SafePWM(final int channel) {
+    super(channel);
+
+    m_safetyHelper = new MotorSafetyHelper(this);
+    m_safetyHelper.setExpiration(0.0);
+    m_safetyHelper.setSafetyEnabled(false);
+  }
+
+  /**
+   * Set the expiration time for the PWM object.
+   *
+   * @param timeout The timeout (in seconds) for this motor object
+   */
+  public void setExpiration(double timeout) {
+    m_safetyHelper.setExpiration(timeout);
+  }
+
+  /**
+   * Return the expiration time for the PWM object.
+   *
+   * @return The expiration time value.
+   */
+  public double getExpiration() {
+    return m_safetyHelper.getExpiration();
+  }
+
+  /**
+   * Check if the PWM object is currently alive or stopped due to a timeout.
+   *
+   * @return a bool value that is true if the motor has NOT timed out and should still be running.
+   */
+  public boolean isAlive() {
+    return m_safetyHelper.isAlive();
+  }
+
+  /**
+   * Stop the motor associated with this PWM object. This is called by the MotorSafetyHelper object
+   * when it has a timeout for this PWM and needs to stop it from running.
+   */
+  public void stopMotor() {
+    disable();
+  }
+
+  /**
+   * Check if motor safety is enabled for this object.
+   *
+   * @return True if motor safety is enforced for this object
+   */
+  public boolean isSafetyEnabled() {
+    return m_safetyHelper.isSafetyEnabled();
+  }
+
+  /**
+   * Feed the MotorSafety timer. This method is called by the subclass motor whenever it updates its
+   * speed, thereby resetting the timeout value.
+   *
+   * @deprecated Use {@link #feed()} instead.
+   */
+  @Deprecated
+  @SuppressWarnings("MethodName")
+  public void Feed() {
+    feed();
+  }
+
+  /**
+   * Feed the MotorSafety timer. This method is called by the subclass motor whenever it updates its
+   * speed, thereby resetting the timeout value.
+   */
+  public void feed() {
+    m_safetyHelper.feed();
+  }
+
+  public void setSafetyEnabled(boolean enabled) {
+    m_safetyHelper.setSafetyEnabled(enabled);
+  }
+
+  public String getDescription() {
+    return "PWM " + getChannel();
+  }
+
+  public void disable() {
+    setDisabled();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SampleRobot.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SampleRobot.java
new file mode 100644
index 0000000..2ff7c2d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SampleRobot.java
@@ -0,0 +1,161 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.livewindow.LiveWindow;
+
+/**
+ * A simple robot base class that knows the standard FRC competition states (disabled, autonomous,
+ * or operator controlled).
+ *
+ * <p>You can build a simple robot program off of this by overriding the robotinit(), disabled(),
+ * autonomous() and operatorControl() methods. The startCompetition() method will calls these
+ * methods (sometimes repeatedly). depending on the state of the competition.
+ *
+ * <p>Alternatively you can override the robotMain() method and manage all aspects of the robot
+ * yourself.
+ *
+ * @deprecated WARNING: While it may look like a good choice to use for your code if you're
+ *     inexperienced, don't. Unless you know what you are doing, complex code will
+ *     be much more difficult under this system. Use TimedRobot or Command-Based
+ *     instead.
+ */
+@Deprecated
+public class SampleRobot extends RobotBase {
+  private boolean m_robotMainOverridden = true;
+
+  /**
+   * Create a new SampleRobot.
+   */
+  public SampleRobot() {
+    HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Simple);
+  }
+
+  /**
+   * Robot-wide initialization code should go here.
+   *
+   * <p>Users should override this method for default Robot-wide initialization which will be called
+   * when the robot is first powered on. It will be called exactly one time.
+   *
+   * <p>Warning: the Driver Station "Robot Code" light and FMS "Robot Ready" indicators will be off
+   * until RobotInit() exits. Code in RobotInit() that waits for enable will cause the robot to
+   * never indicate that the code is ready, causing the robot to be bypassed in a match.
+   */
+  protected void robotInit() {
+    System.out.println("Default robotInit() method running, consider providing your own");
+  }
+
+  /**
+   * Disabled should go here. Users should overload this method to run code that should run while
+   * the field is disabled.
+   *
+   * <p>Called once each time the robot enters the disabled state.
+   */
+  protected void disabled() {
+    System.out.println("Default disabled() method running, consider providing your own");
+  }
+
+  /**
+   * Autonomous should go here. Users should add autonomous code to this method that should run
+   * while the field is in the autonomous period.
+   *
+   * <p>Called once each time the robot enters the autonomous state.
+   */
+  public void autonomous() {
+    System.out.println("Default autonomous() method running, consider providing your own");
+  }
+
+  /**
+   * Operator control (tele-operated) code should go here. Users should add Operator Control code to
+   * this method that should run while the field is in the Operator Control (tele-operated) period.
+   *
+   * <p>Called once each time the robot enters the operator-controlled state.
+   */
+  public void operatorControl() {
+    System.out.println("Default operatorControl() method running, consider providing your own");
+  }
+
+  /**
+   * Test code should go here. Users should add test code to this method that should run while the
+   * robot is in test mode.
+   */
+  @SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
+  public void test() {
+    System.out.println("Default test() method running, consider providing your own");
+  }
+
+  /**
+   * Robot main program for free-form programs.
+   *
+   * <p>This should be overridden by user subclasses if the intent is to not use the autonomous()
+   * and operatorControl() methods. In that case, the program is responsible for sensing when to run
+   * the autonomous and operator control functions in their program.
+   *
+   * <p>This method will be called immediately after the constructor is called. If it has not been
+   * overridden by a user subclass (i.e. the default version runs), then the robotInit(),
+   * disabled(), autonomous() and operatorControl() methods will be called.
+   */
+  public void robotMain() {
+    m_robotMainOverridden = false;
+  }
+
+  /**
+   * Start a competition. This code tracks the order of the field starting to ensure that everything
+   * happens in the right order. Repeatedly run the correct method, either Autonomous or
+   * OperatorControl when the robot is enabled. After running the correct method, wait for some
+   * state to change, either the other mode starts or the robot is disabled. Then go back and wait
+   * for the robot to be enabled again.
+   */
+  public void startCompetition() {
+    robotInit();
+
+    // Tell the DS that the robot is ready to be enabled
+    HAL.observeUserProgramStarting();
+
+    robotMain();
+
+    if (!m_robotMainOverridden) {
+      while (true) {
+        if (isDisabled()) {
+          m_ds.InDisabled(true);
+          disabled();
+          m_ds.InDisabled(false);
+          while (isDisabled()) {
+            Timer.delay(0.01);
+          }
+        } else if (isAutonomous()) {
+          m_ds.InAutonomous(true);
+          autonomous();
+          m_ds.InAutonomous(false);
+          while (isAutonomous() && !isDisabled()) {
+            Timer.delay(0.01);
+          }
+        } else if (isTest()) {
+          LiveWindow.setEnabled(true);
+          m_ds.InTest(true);
+          test();
+          m_ds.InTest(false);
+          while (isTest() && isEnabled()) {
+            Timer.delay(0.01);
+          }
+          LiveWindow.setEnabled(false);
+        } else {
+          m_ds.InOperatorControl(true);
+          operatorControl();
+          m_ds.InOperatorControl(false);
+          while (isOperatorControl() && !isDisabled()) {
+            Timer.delay(0.01);
+          }
+        }
+      } /* while loop */
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Sendable.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Sendable.java
new file mode 100644
index 0000000..76eb03c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Sendable.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.wpilibj;
+
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+
+/**
+ * The base interface for objects that can be sent over the network through network tables.
+ */
+public interface Sendable {
+  /**
+   * Gets the name of this {@link Sendable} object.
+   *
+   * @return Name
+   */
+  String getName();
+
+  /**
+   * Sets the name of this {@link Sendable} object.
+   *
+   * @param name name
+   */
+  void setName(String name);
+
+  /**
+   * Sets both the subsystem name and device name of this {@link Sendable} object.
+   *
+   * @param subsystem subsystem name
+   * @param name device name
+   */
+  default void setName(String subsystem, String name) {
+    setSubsystem(subsystem);
+    setName(name);
+  }
+
+  /**
+   * Gets the subsystem name of this {@link Sendable} object.
+   *
+   * @return Subsystem name
+   */
+  String getSubsystem();
+
+  /**
+   * Sets the subsystem name of this {@link Sendable} object.
+   *
+   * @param subsystem subsystem name
+   */
+  void setSubsystem(String subsystem);
+
+  /**
+   * Initializes this {@link Sendable} object.
+   *
+   * @param builder sendable builder
+   */
+  void initSendable(SendableBuilder builder);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SendableBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SendableBase.java
new file mode 100644
index 0000000..ffa64ff
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SendableBase.java
@@ -0,0 +1,94 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.livewindow.LiveWindow;
+
+/**
+ * Base class for all sensors. Stores most recent status information as well as containing utility
+ * functions for checking channels and error processing.
+ */
+public abstract class SendableBase implements Sendable {
+  private String m_name = "";
+  private String m_subsystem = "Ungrouped";
+
+  /**
+   * Creates an instance of the sensor base.
+   */
+  public SendableBase() {
+    this(true);
+  }
+
+  /**
+   * Creates an instance of the sensor base.
+   *
+   * @param addLiveWindow if true, add this Sendable to LiveWindow
+   */
+  public SendableBase(boolean addLiveWindow) {
+    if (addLiveWindow) {
+      LiveWindow.add(this);
+    }
+  }
+
+  /**
+   * Free the resources used by this object.
+   */
+  public void free() {
+    LiveWindow.remove(this);
+  }
+
+  @Override
+  public final synchronized String getName() {
+    return m_name;
+  }
+
+  @Override
+  public final synchronized void setName(String name) {
+    m_name = name;
+  }
+
+  /**
+   * Sets the name of the sensor with a channel number.
+   *
+   * @param moduleType A string that defines the module name in the label for the value
+   * @param channel    The channel number the device is plugged into
+   */
+  protected final void setName(String moduleType, int channel) {
+    setName(moduleType + "[" + channel + "]");
+  }
+
+  /**
+   * Sets the name of the sensor with a module and channel number.
+   *
+   * @param moduleType   A string that defines the module name in the label for the value
+   * @param moduleNumber The number of the particular module type
+   * @param channel      The channel number the device is plugged into (usually PWM)
+   */
+  protected final void setName(String moduleType, int moduleNumber, int channel) {
+    setName(moduleType + "[" + moduleNumber + "," + channel + "]");
+  }
+
+  @Override
+  public final synchronized String getSubsystem() {
+    return m_subsystem;
+  }
+
+  @Override
+  public final synchronized void setSubsystem(String subsystem) {
+    m_subsystem = subsystem;
+  }
+
+  /**
+   * Add a child component.
+   *
+   * @param child child component
+   */
+  protected final void addChild(Object child) {
+    LiveWindow.addChild(this, child);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SensorBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SensorBase.java
new file mode 100644
index 0000000..6e33a79
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SensorBase.java
@@ -0,0 +1,236 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.AnalogJNI;
+import edu.wpi.first.wpilibj.hal.ConstantsJNI;
+import edu.wpi.first.wpilibj.hal.DIOJNI;
+import edu.wpi.first.wpilibj.hal.PDPJNI;
+import edu.wpi.first.wpilibj.hal.PWMJNI;
+import edu.wpi.first.wpilibj.hal.PortsJNI;
+import edu.wpi.first.wpilibj.hal.RelayJNI;
+import edu.wpi.first.wpilibj.hal.SolenoidJNI;
+
+/**
+ * Base class for all sensors. Stores most recent status information as well as containing utility
+ * functions for checking channels and error processing.
+ */
+public abstract class SensorBase extends SendableBase {
+  /**
+   * Ticks per microsecond.
+   */
+  public static final int kSystemClockTicksPerMicrosecond =
+      ConstantsJNI.getSystemClockTicksPerMicrosecond();
+  /**
+   * Number of digital channels per roboRIO.
+   */
+  public static final int kDigitalChannels = PortsJNI.getNumDigitalChannels();
+  /**
+   * Number of analog input channels per roboRIO.
+   */
+  public static final int kAnalogInputChannels = PortsJNI.getNumAnalogInputs();
+  /**
+   * Number of analog output channels per roboRIO.
+   */
+  public static final int kAnalogOutputChannels = PortsJNI.getNumAnalogOutputs();
+  /**
+   * Number of solenoid channels per module.
+   */
+  public static final int kSolenoidChannels = PortsJNI.getNumSolenoidChannels();
+  /**
+   * Number of PWM channels per roboRIO.
+   */
+  public static final int kPwmChannels = PortsJNI.getNumPWMChannels();
+  /**
+   * Number of relay channels per roboRIO.
+   */
+  public static final int kRelayChannels = PortsJNI.getNumRelayHeaders();
+  /**
+   * Number of power distribution channels per PDP.
+   */
+  public static final int kPDPChannels = PortsJNI.getNumPDPChannels();
+  /**
+   * Number of power distribution modules per PDP.
+   */
+  public static final int kPDPModules = PortsJNI.getNumPDPModules();
+  /**
+   * Number of PCM Modules.
+   */
+  public static final int kPCMModules = PortsJNI.getNumPCMModules();
+
+  private static int m_defaultSolenoidModule = 0;
+
+  /**
+   * Set the default location for the Solenoid module.
+   *
+   * @param moduleNumber The number of the solenoid module to use.
+   */
+  public static void setDefaultSolenoidModule(final int moduleNumber) {
+    checkSolenoidModule(moduleNumber);
+    SensorBase.m_defaultSolenoidModule = moduleNumber;
+  }
+
+  /**
+   * Verify that the solenoid module is correct.
+   *
+   * @param moduleNumber The solenoid module module number to check.
+   */
+  public static void checkSolenoidModule(final int moduleNumber) {
+    if (!SolenoidJNI.checkSolenoidModule(moduleNumber)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested solenoid module is out of range. Minimum: 0, Maximum: ")
+        .append(kPCMModules)
+        .append(", Requested: ")
+        .append(moduleNumber);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Check that the digital channel number is valid. Verify that the channel number is one of the
+   * legal channel numbers. Channel numbers are 0-based.
+   *
+   * @param channel The channel number to check.
+   */
+  public static void checkDigitalChannel(final int channel) {
+    if (!DIOJNI.checkDIOChannel(channel)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested DIO channel is out of range. Minimum: 0, Maximum: ")
+        .append(kDigitalChannels)
+        .append(", Requested: ")
+        .append(channel);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Check that the digital channel number is valid. Verify that the channel number is one of the
+   * legal channel numbers. Channel numbers are 0-based.
+   *
+   * @param channel The channel number to check.
+   */
+  public static void checkRelayChannel(final int channel) {
+    if (!RelayJNI.checkRelayChannel(channel)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested relay channel is out of range. Minimum: 0, Maximum: ")
+        .append(kRelayChannels)
+        .append(", Requested: ")
+        .append(channel);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Check that the digital channel number is valid. Verify that the channel number is one of the
+   * legal channel numbers. Channel numbers are 0-based.
+   *
+   * @param channel The channel number to check.
+   */
+  public static void checkPWMChannel(final int channel) {
+    if (!PWMJNI.checkPWMChannel(channel)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested PWM channel is out of range. Minimum: 0, Maximum: ")
+        .append(kPwmChannels)
+        .append(", Requested: ")
+        .append(channel);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Check that the analog input number is value. Verify that the analog input number is one of the
+   * legal channel numbers. Channel numbers are 0-based.
+   *
+   * @param channel The channel number to check.
+   */
+  public static void checkAnalogInputChannel(final int channel) {
+    if (!AnalogJNI.checkAnalogInputChannel(channel)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested analog input channel is out of range. Minimum: 0, Maximum: ")
+        .append(kAnalogInputChannels)
+        .append(", Requested: ")
+        .append(channel);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Check that the analog input number is value. Verify that the analog input number is one of the
+   * legal channel numbers. Channel numbers are 0-based.
+   *
+   * @param channel The channel number to check.
+   */
+  public static void checkAnalogOutputChannel(final int channel) {
+    if (!AnalogJNI.checkAnalogOutputChannel(channel)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested analog output channel is out of range. Minimum: 0, Maximum: ")
+        .append(kAnalogOutputChannels)
+        .append(", Requested: ")
+        .append(channel);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Verify that the solenoid channel number is within limits. Channel numbers are 0-based.
+   *
+   * @param channel The channel number to check.
+   */
+  public static void checkSolenoidChannel(final int channel) {
+    if (!SolenoidJNI.checkSolenoidChannel(channel)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested solenoid channel is out of range. Minimum: 0, Maximum: ")
+        .append(kSolenoidChannels)
+        .append(", Requested: ")
+        .append(channel);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Verify that the power distribution channel number is within limits. Channel numbers are
+   * 0-based.
+   *
+   * @param channel The channel number to check.
+   */
+  public static void checkPDPChannel(final int channel) {
+    if (!PDPJNI.checkPDPChannel(channel)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested PDP channel is out of range. Minimum: 0, Maximum: ")
+        .append(kPDPChannels)
+        .append(", Requested: ")
+        .append(channel);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Verify that the PDP module number is within limits. module numbers are 0-based.
+   *
+   * @param module The module number to check.
+   */
+  public static void checkPDPModule(final int module) {
+    if (!PDPJNI.checkPDPModule(module)) {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Requested PDP module is out of range. Minimum: 0, Maximum: ")
+        .append(kPDPModules)
+        .append(", Requested: ")
+        .append(module);
+      throw new IndexOutOfBoundsException(buf.toString());
+    }
+  }
+
+  /**
+   * Get the number of the default solenoid module.
+   *
+   * @return The number of the default solenoid module.
+   */
+  public static int getDefaultSolenoidModule() {
+    return SensorBase.m_defaultSolenoidModule;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SerialPort.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SerialPort.java
new file mode 100644
index 0000000..57cd2f2
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SerialPort.java
@@ -0,0 +1,358 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import java.io.UnsupportedEncodingException;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.SerialPortJNI;
+
+/**
+ * Driver for the RS-232 serial port on the roboRIO.
+ *
+ * <p>The current implementation uses the VISA formatted I/O mode. This means that all traffic goes
+ * through the formatted buffers. This allows the intermingled use of print(), readString(), and the
+ * raw buffer accessors read() and write().
+ *
+ * <p>More information can be found in the NI-VISA User Manual here: http://www.ni
+ * .com/pdf/manuals/370423a.pdf and the NI-VISA Programmer's Reference Manual here:
+ * http://www.ni.com/pdf/manuals/370132c.pdf
+ */
+public class SerialPort {
+  private byte m_port;
+
+  public enum Port {
+    kOnboard(0), kMXP(1), kUSB(2), kUSB1(2), kUSB2(3);
+
+    @SuppressWarnings("MemberName")
+    public int value;
+
+    Port(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Represents the parity to use for serial communications.
+   */
+  public enum Parity {
+    kNone(0), kOdd(1), kEven(2), kMark(3), kSpace(4);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    Parity(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Represents the number of stop bits to use for Serial Communication.
+   */
+  public enum StopBits {
+    kOne(10), kOnePointFive(15), kTwo(20);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    StopBits(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Represents what type of flow control to use for serial communication.
+   */
+  public enum FlowControl {
+    kNone(0), kXonXoff(1), kRtsCts(2), kDtsDsr(4);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    FlowControl(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Represents which type of buffer mode to use when writing to a serial m_port.
+   */
+  public enum WriteBufferMode {
+    kFlushOnAccess(1), kFlushWhenFull(2);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    WriteBufferMode(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Create an instance of a Serial Port class.
+   *
+   * @param baudRate The baud rate to configure the serial port.
+   * @param port     The Serial port to use
+   * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
+   * @param parity   Select the type of parity checking to use.
+   * @param stopBits The number of stop bits to use as defined by the enum StopBits.
+   */
+  public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity,
+                    StopBits stopBits) {
+    m_port = (byte) port.value;
+
+    SerialPortJNI.serialInitializePort(m_port);
+    SerialPortJNI.serialSetBaudRate(m_port, baudRate);
+    SerialPortJNI.serialSetDataBits(m_port, (byte) dataBits);
+    SerialPortJNI.serialSetParity(m_port, (byte) parity.value);
+    SerialPortJNI.serialSetStopBits(m_port, (byte) stopBits.value);
+
+    // Set the default read buffer size to 1 to return bytes immediately
+    setReadBufferSize(1);
+
+    // Set the default timeout to 5 seconds.
+    setTimeout(5.0);
+
+    // Don't wait until the buffer is full to transmit.
+    setWriteBufferMode(WriteBufferMode.kFlushOnAccess);
+
+    disableTermination();
+
+    HAL.report(tResourceType.kResourceType_SerialPort, 0);
+  }
+
+  /**
+   * Create an instance of a Serial Port class. Defaults to one stop bit.
+   *
+   * @param baudRate The baud rate to configure the serial port.
+   * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
+   * @param parity   Select the type of parity checking to use.
+   */
+  public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity) {
+    this(baudRate, port, dataBits, parity, StopBits.kOne);
+  }
+
+  /**
+   * Create an instance of a Serial Port class. Defaults to no parity and one stop bit.
+   *
+   * @param baudRate The baud rate to configure the serial port.
+   * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
+   */
+  public SerialPort(final int baudRate, Port port, final int dataBits) {
+    this(baudRate, port, dataBits, Parity.kNone, StopBits.kOne);
+  }
+
+  /**
+   * Create an instance of a Serial Port class. Defaults to 8 databits, no parity, and one stop
+   * bit.
+   *
+   * @param baudRate The baud rate to configure the serial port.
+   */
+  public SerialPort(final int baudRate, Port port) {
+    this(baudRate, port, 8, Parity.kNone, StopBits.kOne);
+  }
+
+  /**
+   * Destructor.
+   */
+  public void free() {
+    SerialPortJNI.serialClose(m_port);
+  }
+
+  /**
+   * Set the type of flow control to enable on this port.
+   *
+   * <p>By default, flow control is disabled.
+   *
+   * @param flowControl the FlowControl m_value to use
+   */
+  public void setFlowControl(FlowControl flowControl) {
+    SerialPortJNI.serialSetFlowControl(m_port, (byte) flowControl.value);
+  }
+
+  /**
+   * Enable termination and specify the termination character.
+   *
+   * <p>Termination is currently only implemented for receive. When the the terminator is received,
+   * the read() or readString() will return fewer bytes than requested, stopping after the
+   * terminator.
+   *
+   * @param terminator The character to use for termination.
+   */
+  public void enableTermination(char terminator) {
+    SerialPortJNI.serialEnableTermination(m_port, terminator);
+  }
+
+  /**
+   * Enable termination with the default terminator '\n'
+   *
+   * <p>Termination is currently only implemented for receive. When the the terminator is received,
+   * the read() or readString() will return fewer bytes than requested, stopping after the
+   * terminator.
+   *
+   * <p>The default terminator is '\n'
+   */
+  public void enableTermination() {
+    enableTermination('\n');
+  }
+
+  /**
+   * Disable termination behavior.
+   */
+  public void disableTermination() {
+    SerialPortJNI.serialDisableTermination(m_port);
+  }
+
+  /**
+   * Get the number of bytes currently available to read from the serial port.
+   *
+   * @return The number of bytes available to read.
+   */
+  public int getBytesReceived() {
+    return SerialPortJNI.serialGetBytesReceived(m_port);
+  }
+
+  /**
+   * Read a string out of the buffer. Reads the entire contents of the buffer
+   *
+   * @return The read string
+   */
+  public String readString() {
+    return readString(getBytesReceived());
+  }
+
+  /**
+   * Read a string out of the buffer. Reads the entire contents of the buffer
+   *
+   * @param count the number of characters to read into the string
+   * @return The read string
+   */
+  public String readString(int count) {
+    byte[] out = read(count);
+    try {
+      return new String(out, 0, out.length, "US-ASCII");
+    } catch (UnsupportedEncodingException ex) {
+      ex.printStackTrace();
+      return "";
+    }
+  }
+
+  /**
+   * Read raw bytes out of the buffer.
+   *
+   * @param count The maximum number of bytes to read.
+   * @return An array of the read bytes
+   */
+  public byte[] read(final int count) {
+    byte[] dataReceivedBuffer = new byte[count];
+    int gotten = SerialPortJNI.serialRead(m_port, dataReceivedBuffer, count);
+    if (gotten == count) {
+      return dataReceivedBuffer;
+    }
+    byte[] retVal = new byte[gotten];
+    System.arraycopy(dataReceivedBuffer, 0, retVal, 0, gotten);
+    return retVal;
+  }
+
+  /**
+   * Write raw bytes to the serial port.
+   *
+   * @param buffer The buffer of bytes to write.
+   * @param count  The maximum number of bytes to write.
+   * @return The number of bytes actually written into the port.
+   */
+  public int write(byte[] buffer, int count) {
+    if (buffer.length < count) {
+      throw new IllegalArgumentException("buffer is too small, must be at least " + count);
+    }
+    return SerialPortJNI.serialWrite(m_port, buffer, count);
+  }
+
+  /**
+   * Write a string to the serial port.
+   *
+   * @param data The string to write to the serial port.
+   * @return The number of bytes actually written into the port.
+   */
+  public int writeString(String data) {
+    return write(data.getBytes(), data.length());
+  }
+
+  /**
+   * Configure the timeout of the serial m_port.
+   *
+   * <p>This defines the timeout for transactions with the hardware. It will affect reads if less
+   * bytes are available than the read buffer size (defaults to 1) and very large writes.
+   *
+   * @param timeout The number of seconds to to wait for I/O.
+   */
+  public void setTimeout(double timeout) {
+    SerialPortJNI.serialSetTimeout(m_port, timeout);
+  }
+
+  /**
+   * Specify the size of the input buffer.
+   *
+   * <p>Specify the amount of data that can be stored before data from the device is returned to
+   * Read. If you want data that is received to be returned immediately, set this to 1.
+   *
+   * <p>It the buffer is not filled before the read timeout expires, all data that has been received
+   * so far will be returned.
+   *
+   * @param size The read buffer size.
+   */
+  public void setReadBufferSize(int size) {
+    SerialPortJNI.serialSetReadBufferSize(m_port, size);
+  }
+
+  /**
+   * Specify the size of the output buffer.
+   *
+   * <p>Specify the amount of data that can be stored before being transmitted to the device.
+   *
+   * @param size The write buffer size.
+   */
+  public void setWriteBufferSize(int size) {
+    SerialPortJNI.serialSetWriteBufferSize(m_port, size);
+  }
+
+  /**
+   * Specify the flushing behavior of the output buffer.
+   *
+   * <p>When set to kFlushOnAccess, data is synchronously written to the serial port after each
+   * call to either print() or write().
+   *
+   * <p>When set to kFlushWhenFull, data will only be written to the serial port when the buffer
+   * is full or when flush() is called.
+   *
+   * @param mode The write buffer mode.
+   */
+  public void setWriteBufferMode(WriteBufferMode mode) {
+    SerialPortJNI.serialSetWriteMode(m_port, (byte) mode.value);
+  }
+
+  /**
+   * Force the output buffer to be written to the port.
+   *
+   * <p>This is used when setWriteBufferMode() is set to kFlushWhenFull to force a flush before the
+   * buffer is full.
+   */
+  public void flush() {
+    SerialPortJNI.serialFlush(m_port);
+  }
+
+  /**
+   * Reset the serial port driver to a known state.
+   *
+   * <p>Empty the transmit and receive buffers in the device and formatted I/O.
+   */
+  public void reset() {
+    SerialPortJNI.serialClear(m_port);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Servo.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Servo.java
new file mode 100644
index 0000000..5f8b88a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Servo.java
@@ -0,0 +1,112 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Standard hobby style servo.
+ *
+ * <p>The range parameters default to the appropriate values for the Hitec HS-322HD servo provided
+ * in the FIRST Kit of Parts in 2008.
+ */
+public class Servo extends PWM {
+  private static final double kMaxServoAngle = 180.0;
+  private static final double kMinServoAngle = 0.0;
+
+  protected static final double kDefaultMaxServoPWM = 2.4;
+  protected static final double kDefaultMinServoPWM = .6;
+
+  /**
+   * Constructor.<br>
+   *
+   * <p>By default {@value #kDefaultMaxServoPWM} ms is used as the maxPWM value<br> By default
+   * {@value #kDefaultMinServoPWM} ms is used as the minPWM value<br>
+   *
+   * @param channel The PWM channel to which the servo is attached. 0-9 are on-board, 10-19 are on
+   *                the MXP port
+   */
+  public Servo(final int channel) {
+    super(channel);
+    setBounds(kDefaultMaxServoPWM, 0, 0, 0, kDefaultMinServoPWM);
+    setPeriodMultiplier(PeriodMultiplier.k4X);
+
+    HAL.report(tResourceType.kResourceType_Servo, getChannel());
+    setName("Servo", getChannel());
+  }
+
+
+  /**
+   * Set the servo position.
+   *
+   * <p>Servo values range from 0.0 to 1.0 corresponding to the range of full left to full right.
+   *
+   * @param value Position from 0.0 to 1.0.
+   */
+  public void set(double value) {
+    setPosition(value);
+  }
+
+  /**
+   * Get the servo position.
+   *
+   * <p>Servo values range from 0.0 to 1.0 corresponding to the range of full left to full right.
+   *
+   * @return Position from 0.0 to 1.0.
+   */
+  public double get() {
+    return getPosition();
+  }
+
+  /**
+   * Set the servo angle.
+   *
+   * <p>Assume that the servo angle is linear with respect to the PWM value (big assumption, need to
+   * test).
+   *
+   * <p>Servo angles that are out of the supported range of the servo simply "saturate" in that
+   * direction In other words, if the servo has a range of (X degrees to Y degrees) than angles of
+   * less than X result in an angle of X being set and angles of more than Y degrees result in an
+   * angle of Y being set.
+   *
+   * @param degrees The angle in degrees to set the servo.
+   */
+  public void setAngle(double degrees) {
+    if (degrees < kMinServoAngle) {
+      degrees = kMinServoAngle;
+    } else if (degrees > kMaxServoAngle) {
+      degrees = kMaxServoAngle;
+    }
+
+    setPosition(((degrees - kMinServoAngle)) / getServoAngleRange());
+  }
+
+  /**
+   * Get the servo angle.
+   *
+   * <p>Assume that the servo angle is linear with respect to the PWM value (big assumption, need to
+   * test).
+   *
+   * @return The angle in degrees to which the servo is set.
+   */
+  public double getAngle() {
+    return getPosition() * getServoAngleRange() + kMinServoAngle;
+  }
+
+  private double getServoAngleRange() {
+    return kMaxServoAngle - kMinServoAngle;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Servo");
+    builder.addDoubleProperty("Value", this::get, this::set);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Solenoid.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Solenoid.java
new file mode 100644
index 0000000..a421a5a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Solenoid.java
@@ -0,0 +1,124 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.hal.SolenoidJNI;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Solenoid class for running high voltage Digital Output on the PCM.
+ *
+ * <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any
+ * device within the current spec of the PCM.
+ */
+public class Solenoid extends SolenoidBase implements Sendable {
+  private final int m_channel; // The channel to control.
+  private int m_solenoidHandle;
+
+  /**
+   * Constructor using the default PCM ID (defaults to 0).
+   *
+   * @param channel The channel on the PCM to control (0..7).
+   */
+  public Solenoid(final int channel) {
+    this(SensorBase.getDefaultSolenoidModule(), channel);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param moduleNumber The CAN ID of the PCM the solenoid is attached to.
+   * @param channel      The channel on the PCM to control (0..7).
+   */
+  public Solenoid(final int moduleNumber, final int channel) {
+    super(moduleNumber);
+    m_channel = channel;
+
+    SensorBase.checkSolenoidModule(m_moduleNumber);
+    SensorBase.checkSolenoidChannel(m_channel);
+
+    int portHandle = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
+    m_solenoidHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
+
+    HAL.report(tResourceType.kResourceType_Solenoid, m_channel, m_moduleNumber);
+    setName("Solenoid", m_moduleNumber, m_channel);
+  }
+
+  /**
+   * Destructor.
+   */
+  @Override
+  public synchronized void free() {
+    super.free();
+    SolenoidJNI.freeSolenoidPort(m_solenoidHandle);
+    m_solenoidHandle = 0;
+  }
+
+  /**
+   * Set the value of a solenoid.
+   *
+   * @param on True will turn the solenoid output on. False will turn the solenoid output off.
+   */
+  public void set(boolean on) {
+    SolenoidJNI.setSolenoid(m_solenoidHandle, on);
+  }
+
+  /**
+   * Read the current value of the solenoid.
+   *
+   * @return True if the solenoid output is on or false if the solenoid output is off.
+   */
+  public boolean get() {
+    return SolenoidJNI.getSolenoid(m_solenoidHandle);
+  }
+
+  /**
+   * Check if solenoid is blacklisted. If a solenoid is shorted, it is added to the blacklist and
+   * disabled until power cycle, or until faults are cleared.
+   *
+   * @return If solenoid is disabled due to short.
+   * @see #clearAllPCMStickyFaults()
+   */
+  public boolean isBlackListed() {
+    int value = getPCMSolenoidBlackList() & (1 << m_channel);
+    return value != 0;
+  }
+
+  /**
+   * Set the pulse duration in the PCM. This is used in conjunction with
+   * the startPulse method to allow the PCM to control the timing of a pulse.
+   * The timing can be controlled in 0.01 second increments.
+   *
+   * @param durationSeconds The duration of the pulse, from 0.01 to 2.55 seconds.
+   *
+   * @see #startPulse()
+   */
+  public void setPulseDuration(double durationSeconds) {
+    long durationMS = (long) (durationSeconds * 1000);
+    SolenoidJNI.setOneShotDuration(m_solenoidHandle, durationMS);
+  }
+
+  /**
+   * Trigger the PCM to generate a pulse of the duration set in
+   * setPulseDuration.
+   *
+   * @see #setPulseDuration(double)
+   */
+  public void startPulse() {
+    SolenoidJNI.fireOneShot(m_solenoidHandle);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Solenoid");
+    builder.setSafeState(() -> set(false));
+    builder.addBooleanProperty("Value", this::get, this::set);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SolenoidBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SolenoidBase.java
new file mode 100644
index 0000000..ff70dcd
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SolenoidBase.java
@@ -0,0 +1,141 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.SolenoidJNI;
+
+/**
+ * SolenoidBase class is the common base class for the {@link Solenoid} and {@link DoubleSolenoid}
+ * classes.
+ */
+public abstract class SolenoidBase extends SendableBase {
+  protected final int m_moduleNumber; // The number of the solenoid module being used.
+
+  /**
+   * Constructor.
+   *
+   * @param moduleNumber The PCM CAN ID
+   */
+  public SolenoidBase(final int moduleNumber) {
+    m_moduleNumber = moduleNumber;
+  }
+
+  /**
+   * Read all 8 solenoids from the specified module as a single byte.
+   *
+   * @param moduleNumber the module number to read
+   * @return The current value of all 8 solenoids on the module.
+   */
+  public static int getAll(int moduleNumber) {
+    return SolenoidJNI.getAllSolenoids(moduleNumber);
+  }
+
+  /**
+   * Read all 8 solenoids from the module used by this solenoid as a single byte.
+   *
+   * @return The current value of all 8 solenoids on this module.
+   */
+  public int getAll() {
+    return SolenoidBase.getAll(m_moduleNumber);
+  }
+
+  /**
+   * Reads complete solenoid blacklist for all 8 solenoids as a single byte. If a solenoid is
+   * shorted, it is added to the blacklist and disabled until power cycle, or until faults are
+   * cleared.
+   *
+   * @param moduleNumber the module number to read
+   * @return The solenoid blacklist of all 8 solenoids on the module.
+   * @see #clearAllPCMStickyFaults()
+   */
+  public static int getPCMSolenoidBlackList(int moduleNumber) {
+    return SolenoidJNI.getPCMSolenoidBlackList(moduleNumber);
+  }
+
+  /**
+   * Reads complete solenoid blacklist for all 8 solenoids as a single byte. If a solenoid is
+   * shorted, it is added to the blacklist and disabled until power cycle, or until faults are
+   * cleared.
+   *
+   * @return The solenoid blacklist of all 8 solenoids on the module.
+   * @see #clearAllPCMStickyFaults()
+   */
+  public int getPCMSolenoidBlackList() {
+    return SolenoidBase.getPCMSolenoidBlackList(m_moduleNumber);
+  }
+
+  /**
+   * If true, the common highside solenoid voltage rail is too low, most likely a solenoid channel
+   * is shorted.
+   *
+   * @param moduleNumber the module number to read
+   * @return true if PCM sticky fault is set
+   */
+  public static boolean getPCMSolenoidVoltageStickyFault(int moduleNumber) {
+    return SolenoidJNI.getPCMSolenoidVoltageStickyFault(moduleNumber);
+  }
+
+  /**
+   * If true, the common highside solenoid voltage rail is too low, most likely a solenoid channel
+   * is shorted.
+   *
+   * @return true if PCM sticky fault is set
+   */
+  public boolean getPCMSolenoidVoltageStickyFault() {
+    return SolenoidBase.getPCMSolenoidVoltageStickyFault(m_moduleNumber);
+  }
+
+  /**
+   * The common highside solenoid voltage rail is too low, most likely a solenoid channel is
+   * shorted.
+   *
+   * @param moduleNumber the module number to read
+   * @return true if PCM is in fault state.
+   */
+  public static boolean getPCMSolenoidVoltageFault(int moduleNumber) {
+    return SolenoidJNI.getPCMSolenoidVoltageFault(moduleNumber);
+  }
+
+  /**
+   * The common highside solenoid voltage rail is too low, most likely a solenoid channel is
+   * shorted.
+   *
+   * @return true if PCM is in fault state.
+   */
+  public boolean getPCMSolenoidVoltageFault() {
+    return SolenoidBase.getPCMSolenoidVoltageFault(m_moduleNumber);
+  }
+
+  /**
+   * Clear ALL sticky faults inside PCM that Compressor is wired to.
+   *
+   * <p>If a sticky fault is set, then it will be persistently cleared. Compressor drive maybe
+   * momentarily disable while flags are being cleared. Care should be taken to not call this too
+   * frequently, otherwise normal compressor functionality may be prevented.
+   *
+   * <p>If no sticky faults are set then this call will have no effect.
+   *
+   * @param moduleNumber the module number to read
+   */
+  public static void clearAllPCMStickyFaults(int moduleNumber) {
+    SolenoidJNI.clearAllPCMStickyFaults(moduleNumber);
+  }
+
+  /**
+   * Clear ALL sticky faults inside PCM that Compressor is wired to.
+   *
+   * <p>If a sticky fault is set, then it will be persistently cleared. Compressor drive maybe
+   * momentarily disable while flags are being cleared. Care should be taken to not call this too
+   * frequently, otherwise normal compressor functionality may be prevented.
+   *
+   * <p>If no sticky faults are set then this call will have no effect.
+   */
+  public void clearAllPCMStickyFaults() {
+    SolenoidBase.clearAllPCMStickyFaults(m_moduleNumber);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Spark.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Spark.java
new file mode 100644
index 0000000..1deefe5
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Spark.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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * REV Robotics SPARK Speed Controller.
+ */
+public class Spark extends PWMSpeedController {
+  /**
+   * Common initialization code called by all constructors.
+   *
+   * <p>Note that the SPARK uses the following bounds for PWM values. These values should work
+   * reasonably well for most controllers, but if users experience issues such as asymmetric
+   * behavior around the deadband or inability to saturate the controller in either direction,
+   * calibration is recommended. The calibration procedure can be found in the Spark User Manual
+   * available from REV Robotics.
+   *
+   * <p>- 2.003ms = full "forward" - 1.55ms = the "high end" of the deadband range - 1.50ms =
+   * center of the deadband range (off) - 1.46ms = the "low end" of the deadband range - .999ms =
+   * full "reverse"
+   */
+  protected void initSpark() {
+    setBounds(2.003, 1.55, 1.50, 1.46, .999);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    HAL.report(tResourceType.kResourceType_RevSPARK, getChannel());
+    setName("Spark", getChannel());
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param channel The PWM channel that the SPARK is attached to. 0-9 are on-board, 10-19 are on
+   *                the MXP port
+   */
+  public Spark(final int channel) {
+    super(channel);
+    initSpark();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedController.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedController.java
new file mode 100644
index 0000000..b90d19f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedController.java
@@ -0,0 +1,52 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+/**
+ * Interface for speed controlling devices.
+ */
+public interface SpeedController extends PIDOutput {
+  /**
+   * Common interface for setting the speed of a speed controller.
+   *
+   * @param speed The speed to set. Value should be between -1.0 and 1.0.
+   */
+  void set(double speed);
+
+  /**
+   * Common interface for getting the current set speed of a speed controller.
+   *
+   * @return The current set speed. Value is between -1.0 and 1.0.
+   */
+  double get();
+
+  /**
+   * Common interface for inverting direction of a speed controller.
+   *
+   * @param isInverted The state of inversion true is inverted.
+   */
+  void setInverted(boolean isInverted);
+
+  /**
+   * Common interface for returning if a speed controller is in the inverted state or not.
+   *
+   * @return isInverted The state of the inversion true is inverted.
+   */
+  boolean getInverted();
+
+  /**
+   * Disable the speed controller.
+   */
+  void disable();
+
+  /**
+   * Stops motor movement. Motor can be moved again by calling set without having to re-enable the
+   * motor.
+   */
+  void stopMotor();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedControllerGroup.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedControllerGroup.java
new file mode 100644
index 0000000..75dff58
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedControllerGroup.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * Allows multiple {@link SpeedController} objects to be linked together.
+ */
+public class SpeedControllerGroup extends SendableBase implements SpeedController {
+  private boolean m_isInverted = false;
+  private final SpeedController[] m_speedControllers;
+  private static int instances = 0;
+
+  /**
+   * Create a new SpeedControllerGroup with the provided SpeedControllers.
+   *
+   * @param speedControllers The SpeedControllers to add
+   */
+  public SpeedControllerGroup(SpeedController speedController,
+                              SpeedController... speedControllers) {
+    m_speedControllers = new SpeedController[speedControllers.length + 1];
+    m_speedControllers[0] = speedController;
+    addChild(speedController);
+    for (int i = 0; i < speedControllers.length; i++) {
+      m_speedControllers[i + 1] = speedControllers[i];
+      addChild(speedControllers[i]);
+    }
+    instances++;
+    setName("SpeedControllerGroup", instances);
+  }
+
+  @Override
+  public void set(double speed) {
+    for (SpeedController speedController : m_speedControllers) {
+      speedController.set(m_isInverted ? -speed : speed);
+    }
+  }
+
+  @Override
+  public double get() {
+    if (m_speedControllers.length > 0) {
+      return m_speedControllers[0].get() * (m_isInverted ? -1 : 1);
+    }
+    return 0.0;
+  }
+
+  @Override
+  public void setInverted(boolean isInverted) {
+    m_isInverted = isInverted;
+  }
+
+  @Override
+  public boolean getInverted() {
+    return m_isInverted;
+  }
+
+  @Override
+  public void disable() {
+    for (SpeedController speedController : m_speedControllers) {
+      speedController.disable();
+    }
+  }
+
+  @Override
+  public void stopMotor() {
+    for (SpeedController speedController : m_speedControllers) {
+      speedController.stopMotor();
+    }
+  }
+
+  @Override
+  public void pidWrite(double output) {
+    set(output);
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Speed Controller");
+    builder.setSafeState(this::stopMotor);
+    builder.addDoubleProperty("Value", this::get, this::set);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Talon.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Talon.java
new file mode 100644
index 0000000..9e42a56
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Talon.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Cross the Road Electronics (CTRE) Talon and Talon SR Speed Controller.
+ */
+public class Talon extends PWMSpeedController {
+  /**
+   * Constructor for a Talon (original or Talon SR).
+   *
+   * <p>Note that the Talon uses the following bounds for PWM values. These values should work
+   * reasonably well for most controllers, but if users experience issues such as asymmetric
+   * behavior around the deadband or inability to saturate the controller in either direction,
+   * calibration is recommended. The calibration procedure can be found in the Talon User Manual
+   * available from CTRE.
+   *
+   * <p>- 2.037ms = full "forward" - 1.539ms = the "high end" of the deadband range - 1.513ms =
+   * center of the deadband range (off) - 1.487ms = the "low end" of the deadband range - .989ms
+   * = full "reverse"
+   *
+   * @param channel The PWM channel that the Talon is attached to. 0-9 are on-board, 10-19 are on
+   *                the MXP port
+   */
+  public Talon(final int channel) {
+    super(channel);
+
+    setBounds(2.037, 1.539, 1.513, 1.487, .989);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    HAL.report(tResourceType.kResourceType_Talon, getChannel());
+    setName("Talon", getChannel());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Threads.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Threads.java
new file mode 100644
index 0000000..5d455e2
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Threads.java
@@ -0,0 +1,42 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.ThreadsJNI;
+
+public class Threads {
+  /**
+  * Get the thread priority for the current thread.
+  * @return The current thread priority. Scaled 1-99.
+  */
+  public static int getCurrentThreadPriority() {
+    return ThreadsJNI.getCurrentThreadPriority();
+  }
+
+  /**
+  * Get if the current thread is realtime.
+  * @return If the current thread is realtime
+  */
+  public static boolean getCurrentThreadIsRealTime() {
+    return ThreadsJNI.getCurrentThreadIsRealTime();
+  }
+
+  /**
+  * Sets the thread priority for the current thread.
+  *
+  * @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. On RoboRIO, priority is ignored for non realtime setting
+  *
+  * @return The success state of setting the priority
+  */
+  public static boolean setCurrentThreadPriority(boolean realTime, int priority) {
+    return ThreadsJNI.setCurrentThreadPriority(realTime, priority);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimedRobot.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimedRobot.java
new file mode 100644
index 0000000..d533313
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimedRobot.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * TimedRobot implements the IterativeRobotBase robot program framework.
+ *
+ * <p>The TimedRobot class is intended to be subclassed by a user creating a robot program.
+ *
+ * <p>periodic() functions from the base class are called on an interval by a Notifier instance.
+ */
+public class TimedRobot extends IterativeRobotBase {
+  public static final double DEFAULT_PERIOD = 0.02;
+
+  private double m_period = DEFAULT_PERIOD;
+
+  // Prevents loop from starting if user calls setPeriod() in robotInit()
+  private boolean m_startLoop = false;
+
+  private Notifier m_loop = new Notifier(() -> {
+    loopFunc();
+  });
+
+  public TimedRobot() {
+    // HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Periodic);
+    HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Iterative);
+  }
+
+  /**
+   * Provide an alternate "main loop" via startCompetition().
+   */
+  public void startCompetition() {
+    robotInit();
+
+    // Tell the DS that the robot is ready to be enabled
+    HAL.observeUserProgramStarting();
+
+    // Loop forever, calling the appropriate mode-dependent function
+    m_startLoop = true;
+    m_loop.startPeriodic(m_period);
+    while (true) {
+      try {
+        Thread.sleep(1000 * 60 * 60 * 24);
+      } catch (InterruptedException ex) {
+        Thread.currentThread().interrupt();
+      }
+    }
+  }
+
+  /**
+   * Set time period between calls to Periodic() functions.
+   *
+   * @param period Period in seconds.
+   */
+  public void setPeriod(double period) {
+    m_period = period;
+
+    if (m_startLoop) {
+      m_loop.startPeriodic(m_period);
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Timer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Timer.java
new file mode 100644
index 0000000..7184115
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Timer.java
@@ -0,0 +1,179 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.util.BaseSystemNotInitializedException;
+
+public class Timer {
+  private static StaticInterface impl;
+
+  @SuppressWarnings("MethodName")
+  public static void SetImplementation(StaticInterface ti) {
+    impl = ti;
+  }
+
+  /**
+   * Return the system clock time in seconds. Return the time from the FPGA hardware clock in
+   * seconds since the FPGA started.
+   *
+   * @return Robot running time in seconds.
+   */
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public static double getFPGATimestamp() {
+    if (impl != null) {
+      return impl.getFPGATimestamp();
+    } else {
+      throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
+    }
+  }
+
+  /**
+   * Return 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.
+   *
+   * @return Time remaining in current match period (auto or teleop) in seconds
+   */
+  public static double getMatchTime() {
+    if (impl != null) {
+      return impl.getMatchTime();
+    } else {
+      throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
+    }
+  }
+
+  /**
+   * Pause the thread for a specified time. Pause the execution of the thread for a specified period
+   * of time given in seconds. Motors will continue to run at their last assigned values, and
+   * sensors will continue to update. Only the task containing the wait will pause until the wait
+   * time is expired.
+   *
+   * @param seconds Length of time to pause
+   */
+  public static void delay(final double seconds) {
+    if (impl != null) {
+      impl.delay(seconds);
+    } else {
+      throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
+    }
+  }
+
+  public interface StaticInterface {
+    @SuppressWarnings("AbbreviationAsWordInName")
+    double getFPGATimestamp();
+
+    double getMatchTime();
+
+    void delay(double seconds);
+
+    @SuppressWarnings("JavadocMethod")
+    Interface newTimer();
+  }
+
+  private final Interface m_timer;
+
+  @SuppressWarnings("JavadocMethod")
+  public Timer() {
+    if (impl != null) {
+      m_timer = impl.newTimer();
+    } else {
+      throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
+    }
+  }
+
+  /**
+   * Get the current time from the timer. If the clock is running it is derived from the current
+   * system clock the start time stored in the timer class. If the clock is not running, then return
+   * the time when it was last stopped.
+   *
+   * @return Current time value for this timer in seconds
+   */
+  public double get() {
+    return m_timer.get();
+  }
+
+  /**
+   * Reset the timer by setting the time to 0. Make the timer startTime the current time so new
+   * requests will be relative now
+   */
+  public void reset() {
+    m_timer.reset();
+  }
+
+  /**
+   * Start the timer running. Just set the running flag to true indicating that all time requests
+   * should be relative to the system clock.
+   */
+  public void start() {
+    m_timer.start();
+  }
+
+  /**
+   * Stop the timer. This computes the time as of now and clears the running flag, causing all
+   * subsequent time requests to be read from the accumulated time rather than looking at the system
+   * clock.
+   */
+  public void stop() {
+    m_timer.stop();
+  }
+
+  /**
+   * Check if the period specified has passed and if it has, advance the start time by that period.
+   * This is useful to decide if it's time to do periodic work without drifting later by the time it
+   * took to get around to checking.
+   *
+   * @param period The period to check for (in seconds).
+   * @return If the period has passed.
+   */
+  public boolean hasPeriodPassed(double period) {
+    return m_timer.hasPeriodPassed(period);
+  }
+
+  public interface Interface {
+    /**
+     * Get the current time from the timer. If the clock is running it is derived from the current
+     * system clock the start time stored in the timer class. If the clock is not running, then
+     * return the time when it was last stopped.
+     *
+     * @return Current time value for this timer in seconds
+     */
+    double get();
+
+    /**
+     * Reset the timer by setting the time to 0. Make the timer startTime the current time so new
+     * requests will be relative now
+     */
+    void reset();
+
+    /**
+     * Start the timer running. Just set the running flag to true indicating that all time requests
+     * should be relative to the system clock.
+     */
+    void start();
+
+    /**
+     * Stop the timer. This computes the time as of now and clears the running flag, causing all
+     * subsequent time requests to be read from the accumulated time rather than looking at the
+     * system clock.
+     */
+    void stop();
+
+
+    /**
+     * Check if the period specified has passed and if it has, advance the start time by that
+     * period. This is useful to decide if it's time to do periodic work without drifting later by
+     * the time it took to get around to checking.
+     *
+     * @param period The period to check for (in seconds).
+     * @return If the period has passed.
+     */
+    boolean hasPeriodPassed(double period);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Ultrasonic.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Ultrasonic.java
new file mode 100644
index 0000000..a89f088
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Ultrasonic.java
@@ -0,0 +1,398 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Ultrasonic rangefinder class. The Ultrasonic rangefinder measures absolute distance based on the
+ * round-trip time of a ping generated by the controller. These sensors use two transducers, a
+ * speaker and a microphone both tuned to the ultrasonic range. A common ultrasonic sensor, the
+ * Daventech SRF04 requires a short pulse to be generated on a digital channel. This causes the
+ * chirp to be emitted. A second line becomes high as the ping is transmitted and goes low when the
+ * echo is received. The time that the line is high determines the round trip distance (time of
+ * flight).
+ */
+public class Ultrasonic extends SensorBase implements PIDSource, Sendable {
+  /**
+   * The units to return when PIDGet is called.
+   */
+  public enum Unit {
+    /**
+     * Use inches for PIDGet.
+     */
+    kInches,
+    /**
+     * Use millimeters for PIDGet.
+     */
+    kMillimeters
+  }
+
+  // Time (sec) for the ping trigger pulse.
+  private static final double kPingTime = 10 * 1e-6;
+  private static final double kSpeedOfSoundInchesPerSec = 1130.0 * 12.0;
+  // head of the ultrasonic sensor list
+  private static Ultrasonic m_firstSensor = null;
+  // automatic round robin mode
+  private static boolean m_automaticEnabled = false;
+  private DigitalInput m_echoChannel;
+  private DigitalOutput m_pingChannel = null;
+  private boolean m_allocatedChannels;
+  private boolean m_enabled = false;
+  private Counter m_counter = null;
+  private Ultrasonic m_nextSensor = null;
+  // task doing the round-robin automatic sensing
+  private static Thread m_task = null;
+  private Unit m_units;
+  private static int m_instances = 0;
+  protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
+
+  /**
+   * Background task that goes through the list of ultrasonic sensors and pings each one in turn.
+   * The counter is configured to read the timing of the returned echo pulse.
+   *
+   * <p><b>DANGER WILL ROBINSON, DANGER WILL ROBINSON:</b> This code runs as a task and assumes that
+   * none of the ultrasonic sensors will change while it's running. If one does, then this will
+   * certainly break. Make sure to disable automatic mode before changing anything with the
+   * sensors!!
+   */
+  private class UltrasonicChecker extends Thread {
+    @Override
+    public synchronized void run() {
+      Ultrasonic ultrasonic = null;
+      while (m_automaticEnabled) {
+        if (ultrasonic == null) {
+          ultrasonic = m_firstSensor;
+        }
+        if (ultrasonic == null) {
+          return;
+        }
+        if (ultrasonic.isEnabled()) {
+          // Do the ping
+          ultrasonic.m_pingChannel.pulse(kPingTime);
+        }
+        ultrasonic = ultrasonic.m_nextSensor;
+        Timer.delay(.1); // wait for ping to return
+      }
+    }
+  }
+
+  /**
+   * Initialize the Ultrasonic Sensor. This is the common code that initializes the ultrasonic
+   * sensor given that there are two digital I/O channels allocated. If the system was running in
+   * automatic mode (round robin) when the new sensor is added, it is stopped, the sensor is added,
+   * then automatic mode is restored.
+   */
+  private synchronized void initialize() {
+    if (m_task == null) {
+      m_task = new UltrasonicChecker();
+    }
+    final boolean originalMode = m_automaticEnabled;
+    setAutomaticMode(false); // kill task when adding a new sensor
+    m_nextSensor = m_firstSensor;
+    m_firstSensor = this;
+
+    m_counter = new Counter(m_echoChannel); // set up counter for this
+    addChild(m_counter);
+    // sensor
+    m_counter.setMaxPeriod(1.0);
+    m_counter.setSemiPeriodMode(true);
+    m_counter.reset();
+    m_enabled = true; // make it available for round robin scheduling
+    setAutomaticMode(originalMode);
+
+    m_instances++;
+    HAL.report(tResourceType.kResourceType_Ultrasonic, m_instances);
+    setName("Ultrasonic", m_echoChannel.getChannel());
+  }
+
+  /**
+   * Create an instance of the Ultrasonic Sensor. This is designed to supchannel the Daventech SRF04
+   * and Vex ultrasonic sensors.
+   *
+   * @param pingChannel The digital output channel that sends the pulse to initiate the sensor
+   *                    sending the ping.
+   * @param echoChannel The digital input channel that receives the echo. The length of time that
+   *                    the echo is high represents the round trip time of the ping, and the
+   *                    distance.
+   * @param units       The units returned in either kInches or kMilliMeters
+   */
+  public Ultrasonic(final int pingChannel, final int echoChannel, Unit units) {
+    m_pingChannel = new DigitalOutput(pingChannel);
+    m_echoChannel = new DigitalInput(echoChannel);
+    addChild(m_pingChannel);
+    addChild(m_echoChannel);
+    m_allocatedChannels = true;
+    m_units = units;
+    initialize();
+  }
+
+  /**
+   * Create an instance of the Ultrasonic Sensor. This is designed to supchannel the Daventech SRF04
+   * and Vex ultrasonic sensors. Default unit is inches.
+   *
+   * @param pingChannel The digital output channel that sends the pulse to initiate the sensor
+   *                    sending the ping.
+   * @param echoChannel The digital input channel that receives the echo. The length of time that
+   *                    the echo is high represents the round trip time of the ping, and the
+   *                    distance.
+   */
+  public Ultrasonic(final int pingChannel, final int echoChannel) {
+    this(pingChannel, echoChannel, Unit.kInches);
+  }
+
+  /**
+   * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a
+   * DigitalOutput for the ping channel.
+   *
+   * @param pingChannel The digital output object that starts the sensor doing a ping. Requires a
+   *                    10uS pulse to start.
+   * @param echoChannel The digital input object that times the return pulse to determine the
+   *                    range.
+   * @param units       The units returned in either kInches or kMilliMeters
+   */
+  public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel, Unit units) {
+    requireNonNull(pingChannel, "Provided ping channel was null");
+    requireNonNull(echoChannel, "Provided echo channel was null");
+
+    m_allocatedChannels = false;
+    m_pingChannel = pingChannel;
+    m_echoChannel = echoChannel;
+    m_units = units;
+    initialize();
+  }
+
+  /**
+   * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a
+   * DigitalOutput for the ping channel. Default unit is inches.
+   *
+   * @param pingChannel The digital output object that starts the sensor doing a ping. Requires a
+   *                    10uS pulse to start.
+   * @param echoChannel The digital input object that times the return pulse to determine the
+   *                    range.
+   */
+  public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel) {
+    this(pingChannel, echoChannel, Unit.kInches);
+  }
+
+  /**
+   * Destructor for the ultrasonic sensor. Delete the instance of the ultrasonic sensor by freeing
+   * the allocated digital channels. If the system was in automatic mode (round robin), then it is
+   * stopped, then started again after this sensor is removed (provided this wasn't the last
+   * sensor).
+   */
+  @Override
+  public synchronized void free() {
+    super.free();
+    final boolean wasAutomaticMode = m_automaticEnabled;
+    setAutomaticMode(false);
+    if (m_allocatedChannels) {
+      if (m_pingChannel != null) {
+        m_pingChannel.free();
+      }
+      if (m_echoChannel != null) {
+        m_echoChannel.free();
+      }
+    }
+
+    if (m_counter != null) {
+      m_counter.free();
+      m_counter = null;
+    }
+
+    m_pingChannel = null;
+    m_echoChannel = null;
+
+    if (this == m_firstSensor) {
+      m_firstSensor = m_nextSensor;
+      if (m_firstSensor == null) {
+        setAutomaticMode(false);
+      }
+    } else {
+      for (Ultrasonic s = m_firstSensor; s != null; s = s.m_nextSensor) {
+        if (this == s.m_nextSensor) {
+          s.m_nextSensor = s.m_nextSensor.m_nextSensor;
+          break;
+        }
+      }
+    }
+    if (m_firstSensor != null && wasAutomaticMode) {
+      setAutomaticMode(true);
+    }
+  }
+
+  /**
+   * Turn Automatic mode on/off. When in Automatic mode, all sensors will fire in round robin,
+   * waiting a set time between each sensor.
+   *
+   * @param enabling Set to true if round robin scheduling should start for all the ultrasonic
+   *                 sensors. This scheduling method assures that the sensors are non-interfering
+   *                 because no two sensors fire at the same time. If another scheduling algorithm
+   *                 is preferred, it can be implemented by pinging the sensors manually and waiting
+   *                 for the results to come back.
+   */
+  public void setAutomaticMode(boolean enabling) {
+    if (enabling == m_automaticEnabled) {
+      return; // ignore the case of no change
+    }
+    m_automaticEnabled = enabling;
+
+    if (enabling) {
+      /* Clear all the counters so no data is valid. No synchronization is
+       * needed because the background task is stopped.
+       */
+      for (Ultrasonic u = m_firstSensor; u != null; u = u.m_nextSensor) {
+        u.m_counter.reset();
+      }
+
+      // Start round robin task
+      m_task.start();
+    } else {
+      // Wait for background task to stop running
+      try {
+        m_task.join();
+      } catch (InterruptedException ex) {
+        Thread.currentThread().interrupt();
+        ex.printStackTrace();
+      }
+
+      /* Clear all the counters (data now invalid) since automatic mode is
+       * disabled. No synchronization is needed because the background task is
+       * stopped.
+       */
+      for (Ultrasonic u = m_firstSensor; u != null; u = u.m_nextSensor) {
+        u.m_counter.reset();
+      }
+    }
+  }
+
+  /**
+   * Single ping to ultrasonic sensor. Send out a single ping to the ultrasonic sensor. This only
+   * works if automatic (round robin) mode is disabled. A single ping is sent out, and the counter
+   * should count the semi-period when it comes in. The counter is reset to make the current value
+   * invalid.
+   */
+  public void ping() {
+    setAutomaticMode(false); // turn off automatic round robin if pinging
+    // single sensor
+    m_counter.reset(); // reset the counter to zero (invalid data now)
+    // do the ping to start getting a single range
+    m_pingChannel.pulse(kPingTime);
+  }
+
+  /**
+   * Check if there is a valid range measurement. The ranges are accumulated in a counter that will
+   * increment on each edge of the echo (return) signal. If the count is not at least 2, then the
+   * range has not yet been measured, and is invalid.
+   *
+   * @return true if the range is valid
+   */
+  public boolean isRangeValid() {
+    return m_counter.get() > 1;
+  }
+
+  /**
+   * Get the range in inches from the ultrasonic sensor. If there is no valid value yet, i.e. at
+   * least one measurement hasn't completed, then return 0.
+   *
+   * @return double Range in inches of the target returned from the ultrasonic sensor.
+   */
+  public double getRangeInches() {
+    if (isRangeValid()) {
+      return m_counter.getPeriod() * kSpeedOfSoundInchesPerSec / 2.0;
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * Get the range in millimeters from the ultrasonic sensor. If there is no valid value yet, i.e.
+   * at least one measurement hasn't completed, then return 0.
+   *
+   * @return double Range in millimeters of the target returned by the ultrasonic sensor.
+   */
+  public double getRangeMM() {
+    return getRangeInches() * 25.4;
+  }
+
+  @Override
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    if (!pidSource.equals(PIDSourceType.kDisplacement)) {
+      throw new IllegalArgumentException("Only displacement PID is allowed for ultrasonics.");
+    }
+    m_pidSource = pidSource;
+  }
+
+  @Override
+  public PIDSourceType getPIDSourceType() {
+    return m_pidSource;
+  }
+
+  /**
+   * Get the range in the current DistanceUnit for the PIDSource base object.
+   *
+   * @return The range in DistanceUnit
+   */
+  @Override
+  public double pidGet() {
+    switch (m_units) {
+      case kInches:
+        return getRangeInches();
+      case kMillimeters:
+        return getRangeMM();
+      default:
+        return 0.0;
+    }
+  }
+
+  /**
+   * Set the current DistanceUnit that should be used for the PIDSource base object.
+   *
+   * @param units The DistanceUnit that should be used.
+   */
+  public void setDistanceUnits(Unit units) {
+    m_units = units;
+  }
+
+  /**
+   * Get the current DistanceUnit that is used for the PIDSource base object.
+   *
+   * @return The type of DistanceUnit that is being used.
+   */
+  public Unit getDistanceUnits() {
+    return m_units;
+  }
+
+  /**
+   * Is the ultrasonic enabled.
+   *
+   * @return true if the ultrasonic is enabled
+   */
+  public boolean isEnabled() {
+    return m_enabled;
+  }
+
+  /**
+   * Set if the ultrasonic is enabled.
+   *
+   * @param enable set to true to enable the ultrasonic
+   */
+  public void setEnabled(boolean enable) {
+    m_enabled = enable;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Ultrasonic");
+    builder.addDoubleProperty("Value", this::getRangeInches, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Utility.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Utility.java
new file mode 100644
index 0000000..26c9e69
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Utility.java
@@ -0,0 +1,69 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.HALUtil;
+
+/**
+ * Contains global utility functions.
+ * @deprecated Use RobotController class instead
+ */
+@Deprecated
+public final class Utility {
+  private Utility() {
+  }
+
+  /**
+   * Return the FPGA Version number. For now, expect this to be 2009.
+   *
+   * @return FPGA Version number.
+   * @deprecated Use RobotController.getFPGAVersion()
+   */
+  @SuppressWarnings("AbbreviationAsWordInName")
+  @Deprecated
+  int getFPGAVersion() {
+    return HALUtil.getFPGAVersion();
+  }
+
+  /**
+   * Return 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.
+   * @deprecated Use RobotController.getFPGARevision()
+   */
+  @SuppressWarnings("AbbreviationAsWordInName")
+  @Deprecated
+  long getFPGARevision() {
+    return (long) HALUtil.getFPGARevision();
+  }
+
+  /**
+   * Read the microsecond timer from the FPGA.
+   *
+   * @return The current time in microseconds according to the FPGA.
+   * @deprecated Use RobotController.getFPGATime()
+   */
+  @Deprecated
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public static long getFPGATime() {
+    return HALUtil.getFPGATime();
+  }
+
+  /**
+   * Get the state of the "USER" button on the roboRIO.
+   *
+   * @return true if the button is currently pressed down
+   * @deprecated Use RobotController.getUserButton()
+   */
+  @Deprecated
+  public static boolean getUserButton() {
+    return HALUtil.getFPGAButton();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Victor.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Victor.java
new file mode 100644
index 0000000..886e07d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/Victor.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * VEX Robotics Victor 888 Speed Controller The Vex Robotics Victor 884 Speed Controller can also
+ * be used with this class but may need to be calibrated per the Victor 884 user manual.
+ */
+public class Victor extends PWMSpeedController {
+  /**
+   * Constructor.
+   *
+   * <p>Note that the Victor uses the following bounds for PWM values. These values were determined
+   * empirically and optimized for the Victor 888. These values should work reasonably well for
+   * Victor 884 controllers also but if users experience issues such as asymmetric behaviour around
+   * the deadband or inability to saturate the controller in either direction, calibration is
+   * recommended. The calibration procedure can be found in the Victor 884 User Manual available
+   * from VEX Robotics: http://content.vexrobotics.com/docs/ifi-v884-users-manual-9-25-06.pdf
+   *
+   * <p>- 2.027ms = full "forward" - 1.525ms = the "high end" of the deadband range - 1.507ms =
+   * center of the deadband range (off) - 1.49ms = the "low end" of the deadband range - 1.026ms =
+   * full "reverse"
+   *
+   * @param channel The PWM channel that the Victor is attached to. 0-9 are
+   *        on-board, 10-19 are on the MXP port
+   */
+  public Victor(final int channel) {
+    super(channel);
+
+    setBounds(2.027, 1.525, 1.507, 1.49, 1.026);
+    setPeriodMultiplier(PeriodMultiplier.k2X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    HAL.report(tResourceType.kResourceType_Victor, getChannel());
+    setName("Victor", getChannel());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/VictorSP.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/VictorSP.java
new file mode 100644
index 0000000..88e6414
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/VictorSP.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * VEX Robotics Victor SP Speed Controller.
+ */
+public class VictorSP extends PWMSpeedController {
+  /**
+   * Constructor.
+   *
+   * <p>Note that the VictorSP uses the following bounds for PWM values. These values should work
+   * reasonably well for most controllers, but if users experience issues such as asymmetric
+   * behavior around the deadband or inability to saturate the controller in either direction,
+   * calibration is recommended. The calibration procedure can be found in the VictorSP User Manual
+   * available from CTRE.
+   *
+   * <p>- 2.004ms = full "forward" - 1.52ms = the "high end" of the deadband range - 1.50ms =
+   * center of the deadband range (off) - 1.48ms = the "low end" of the deadband range - .997ms =
+   * full "reverse"
+   *
+   * @param channel The PWM channel that the VictorSP is attached to. 0-9 are
+   *        on-board, 10-19 are on the MXP port
+   */
+  public VictorSP(final int channel) {
+    super(channel);
+
+    setBounds(2.004, 1.52, 1.50, 1.48, .997);
+    setPeriodMultiplier(PeriodMultiplier.k1X);
+    setSpeed(0.0);
+    setZeroLatch();
+
+    HAL.report(tResourceType.kResourceType_VictorSP, getChannel());
+    setName("VictorSP", getChannel());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/XboxController.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/XboxController.java
new file mode 100644
index 0000000..140ce36
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/XboxController.java
@@ -0,0 +1,346 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * Handle input from Xbox 360 or Xbox One controllers connected to the Driver Station.
+ *
+ * <p>This class handles Xbox input that comes from the Driver Station. Each time a value is
+ * requested the most recent value is returned. There is a single class instance for each controller
+ * and the mapping of ports to hardware buttons depends on the code in the Driver Station.
+ */
+public class XboxController extends GenericHID {
+  /**
+   * Represents a digital button on an XboxController.
+   */
+  private enum Button {
+    kBumperLeft(5),
+    kBumperRight(6),
+    kStickLeft(9),
+    kStickRight(10),
+    kA(1),
+    kB(2),
+    kX(3),
+    kY(4),
+    kBack(7),
+    kStart(8);
+
+    @SuppressWarnings("MemberName")
+    private int value;
+
+    Button(int value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * Construct an instance of a joystick. The joystick index is the USB port on the drivers
+   * station.
+   *
+   * @param port The port on the Driver Station that the joystick is plugged into.
+   */
+  public XboxController(final int port) {
+    super(port);
+
+    // HAL.report(tResourceType.kResourceType_XboxController, port);
+    HAL.report(tResourceType.kResourceType_Joystick, port);
+  }
+
+  /**
+   * Get the X axis value of the controller.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return The X axis value of the controller.
+   */
+  @Override
+  public double getX(Hand hand) {
+    if (hand.equals(Hand.kLeft)) {
+      return getRawAxis(0);
+    } else {
+      return getRawAxis(4);
+    }
+  }
+
+  /**
+   * Get the Y axis value of the controller.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return The Y axis value of the controller.
+   */
+  @Override
+  public double getY(Hand hand) {
+    if (hand.equals(Hand.kLeft)) {
+      return getRawAxis(1);
+    } else {
+      return getRawAxis(5);
+    }
+  }
+
+  /**
+   * Get the trigger axis value of the controller.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return The trigger axis value of the controller.
+   */
+  public double getTriggerAxis(Hand hand) {
+    if (hand.equals(Hand.kLeft)) {
+      return getRawAxis(2);
+    } else {
+      return getRawAxis(3);
+    }
+  }
+
+  /**
+   * Read the value of the bumper button on the controller.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return The state of the button.
+   */
+  public boolean getBumper(Hand hand) {
+    if (hand.equals(Hand.kLeft)) {
+      return getRawButton(Button.kBumperLeft.value);
+    } else {
+      return getRawButton(Button.kBumperRight.value);
+    }
+  }
+
+  /**
+   * Whether the bumper was pressed since the last check.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getBumperPressed(Hand hand) {
+    if (hand == Hand.kLeft) {
+      return getRawButtonPressed(Button.kBumperLeft.value);
+    } else {
+      return getRawButtonPressed(Button.kBumperRight.value);
+    }
+  }
+
+  /**
+   * Whether the bumper was released since the last check.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getBumperReleased(Hand hand) {
+    if (hand == Hand.kLeft) {
+      return getRawButtonReleased(Button.kBumperLeft.value);
+    } else {
+      return getRawButtonReleased(Button.kBumperRight.value);
+    }
+  }
+
+  /**
+   * Read the value of the stick button on the controller.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return The state of the button.
+   */
+  public boolean getStickButton(Hand hand) {
+    if (hand.equals(Hand.kLeft)) {
+      return getRawButton(Button.kStickLeft.value);
+    } else {
+      return getRawButton(Button.kStickRight.value);
+    }
+  }
+
+  /**
+   * Whether the stick button was pressed since the last check.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getStickButtonPressed(Hand hand) {
+    if (hand == Hand.kLeft) {
+      return getRawButtonPressed(Button.kStickLeft.value);
+    } else {
+      return getRawButtonPressed(Button.kStickRight.value);
+    }
+  }
+
+  /**
+   * Whether the stick button was released since the last check.
+   *
+   * @param hand Side of controller whose value should be returned.
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getStickButtonReleased(Hand hand) {
+    if (hand == Hand.kLeft) {
+      return getRawButtonReleased(Button.kStickLeft.value);
+    } else {
+      return getRawButtonReleased(Button.kStickRight.value);
+    }
+  }
+
+  /**
+   * Read the value of the A button on the controller.
+   *
+   * @return The state of the button.
+   */
+  public boolean getAButton() {
+    return getRawButton(Button.kA.value);
+  }
+
+  /**
+   * Whether the A button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getAButtonPressed() {
+    return getRawButtonPressed(Button.kA.value);
+  }
+
+  /**
+   * Whether the A button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getAButtonReleased() {
+    return getRawButtonReleased(Button.kA.value);
+  }
+
+  /**
+   * Read the value of the B button on the controller.
+   *
+   * @return The state of the button.
+   */
+  public boolean getBButton() {
+    return getRawButton(Button.kB.value);
+  }
+
+  /**
+   * Whether the B button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getBButtonPressed() {
+    return getRawButtonPressed(Button.kB.value);
+  }
+
+  /**
+   * Whether the B button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getBButtonReleased() {
+    return getRawButtonReleased(Button.kB.value);
+  }
+
+  /**
+   * Read the value of the X button on the controller.
+   *
+   * @return The state of the button.
+   */
+  public boolean getXButton() {
+    return getRawButton(Button.kX.value);
+  }
+
+  /**
+   * Whether the X button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getXButtonPressed() {
+    return getRawButtonPressed(Button.kX.value);
+  }
+
+  /**
+   * Whether the X button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getXButtonReleased() {
+    return getRawButtonReleased(Button.kX.value);
+  }
+
+  /**
+   * Read the value of the Y button on the controller.
+   *
+   * @return The state of the button.
+   */
+  public boolean getYButton() {
+    return getRawButton(Button.kY.value);
+  }
+
+  /**
+   * Whether the Y button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getYButtonPressed() {
+    return getRawButtonPressed(Button.kY.value);
+  }
+
+  /**
+   * Whether the Y button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getYButtonReleased() {
+    return getRawButtonReleased(Button.kY.value);
+  }
+
+  /**
+   * Read the value of the back button on the controller.
+   *
+   * @return The state of the button.
+   */
+  public boolean getBackButton() {
+    return getRawButton(Button.kBack.value);
+  }
+
+  /**
+   * Whether the back button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getBackButtonPressed() {
+    return getRawButtonPressed(Button.kBack.value);
+  }
+
+  /**
+   * Whether the back button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getBackButtonReleased() {
+    return getRawButtonReleased(Button.kBack.value);
+  }
+
+  /**
+   * Read the value of the start button on the controller.
+   *
+   * @return The state of the button.
+   */
+  public boolean getStartButton() {
+    return getRawButton(Button.kStart.value);
+  }
+
+  /**
+   * Whether the start button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  public boolean getStartButtonPressed() {
+    return getRawButtonPressed(Button.kStart.value);
+  }
+
+  /**
+   * Whether the start button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  public boolean getStartButtonReleased() {
+    return getRawButtonReleased(Button.kStart.value);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/Button.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/Button.java
new file mode 100644
index 0000000..a7dc2fa
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/Button.java
@@ -0,0 +1,70 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.buttons;
+
+import edu.wpi.first.wpilibj.command.Command;
+
+/**
+ * This class provides an easy way to link commands to OI inputs.
+ *
+ * <p>It is very easy to link a button to a command. For instance, you could link the trigger button
+ * of a joystick to a "score" command.
+ *
+ * <p>This class represents a subclass of Trigger that is specifically aimed at buttons on an
+ * operator interface as a common use case of the more generalized Trigger objects. This is a simple
+ * wrapper around Trigger with the method names renamed to fit the Button object use.
+ */
+public abstract class Button extends Trigger {
+  /**
+   * Starts the given command whenever the button is newly pressed.
+   *
+   * @param command the command to start
+   */
+  public void whenPressed(final Command command) {
+    whenActive(command);
+  }
+
+  /**
+   * Constantly starts the given command while the button is held.
+   *
+   * {@link Command#start()} will be called repeatedly while the button is held, and will be
+   * canceled when the button is released.
+   *
+   * @param command the command to start
+   */
+  public void whileHeld(final Command command) {
+    whileActive(command);
+  }
+
+  /**
+   * Starts the command when the button is released.
+   *
+   * @param command the command to start
+   */
+  public void whenReleased(final Command command) {
+    whenInactive(command);
+  }
+
+  /**
+   * Toggles the command whenever the button is pressed (on then off then on).
+   *
+   * @param command the command to start
+   */
+  public void toggleWhenPressed(final Command command) {
+    toggleWhenActive(command);
+  }
+
+  /**
+   * Cancel the command when the button is pressed.
+   *
+   * @param command the command to start
+   */
+  public void cancelWhenPressed(final Command command) {
+    cancelWhenActive(command);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/InternalButton.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/InternalButton.java
new file mode 100644
index 0000000..a44df17
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/InternalButton.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.buttons;
+
+/**
+ * This class is intended to be used within a program. The programmer can manually set its value.
+ * Also includes a setting for whether or not it should invert its value.
+ */
+public class InternalButton extends Button {
+  private boolean m_pressed;
+  private boolean m_inverted;
+
+  /**
+   * Creates an InternalButton that is not inverted.
+   */
+  public InternalButton() {
+    this(false);
+  }
+
+  /**
+   * Creates an InternalButton which is inverted depending on the input.
+   *
+   * @param inverted if false, then this button is pressed when set to true, otherwise it is pressed
+   *                 when set to false.
+   */
+  public InternalButton(boolean inverted) {
+    m_pressed = m_inverted = inverted;
+  }
+
+  public void setInverted(boolean inverted) {
+    m_inverted = inverted;
+  }
+
+  public void setPressed(boolean pressed) {
+    m_pressed = pressed;
+  }
+
+  public boolean get() {
+    return m_pressed ^ m_inverted;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/JoystickButton.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/JoystickButton.java
new file mode 100644
index 0000000..516f6ad
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/JoystickButton.java
@@ -0,0 +1,39 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.buttons;
+
+import edu.wpi.first.wpilibj.GenericHID;
+
+/**
+ * A {@link Button} that gets its state from a {@link GenericHID}.
+ */
+public class JoystickButton extends Button {
+  private final GenericHID m_joystick;
+  private final int m_buttonNumber;
+
+  /**
+   * Create a joystick button for triggering commands.
+   *
+   * @param joystick     The GenericHID object that has the button (e.g. Joystick, KinectStick,
+   *                     etc)
+   * @param buttonNumber The button number (see {@link GenericHID#getRawButton(int) }
+   */
+  public JoystickButton(GenericHID joystick, int buttonNumber) {
+    m_joystick = joystick;
+    m_buttonNumber = buttonNumber;
+  }
+
+  /**
+   * Gets the value of the joystick button.
+   *
+   * @return The value of the joystick button
+   */
+  public boolean get() {
+    return m_joystick.getRawButton(m_buttonNumber);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/NetworkButton.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/NetworkButton.java
new file mode 100644
index 0000000..90a1593
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/NetworkButton.java
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.buttons;
+
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+
+/**
+ * A {@link Button} that uses a {@link NetworkTable} boolean field.
+ */
+public class NetworkButton extends Button {
+  private final NetworkTableEntry m_entry;
+
+  public NetworkButton(String table, String field) {
+    this(NetworkTableInstance.getDefault().getTable(table), field);
+  }
+
+  public NetworkButton(NetworkTable table, String field) {
+    m_entry = table.getEntry(field);
+  }
+
+  public boolean get() {
+    return m_entry.getInstance().isConnected() && m_entry.getBoolean(false);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/Trigger.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/Trigger.java
new file mode 100644
index 0000000..6541562
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/buttons/Trigger.java
@@ -0,0 +1,198 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.buttons;
+
+import edu.wpi.first.wpilibj.SendableBase;
+import edu.wpi.first.wpilibj.command.Command;
+import edu.wpi.first.wpilibj.command.Scheduler;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * This class provides an easy way to link commands to inputs.
+ *
+ * <p>It is very easy to link a button to a command. For instance, you could link the trigger
+ * button of a joystick to a "score" command.
+ *
+ * <p>It is encouraged that teams write a subclass of Trigger if they want to have something unusual
+ * (for instance, if they want to react to the user holding a button while the robot is reading a
+ * certain sensor input). For this, they only have to write the {@link Trigger#get()} method to get
+ * the full functionality of the Trigger class.
+ */
+public abstract class Trigger extends SendableBase {
+  private volatile boolean m_sendablePressed = false;
+
+  /**
+   * Returns whether or not the trigger is active.
+   *
+   * <p>This method will be called repeatedly a command is linked to the Trigger.
+   *
+   * @return whether or not the trigger condition is active.
+   */
+  public abstract boolean get();
+
+  /**
+   * Returns whether get() return true or the internal table for SmartDashboard use is pressed.
+   *
+   * @return whether get() return true or the internal table for SmartDashboard use is pressed.
+   */
+  @SuppressWarnings("PMD.UselessParentheses")
+  private boolean grab() {
+    return get() || m_sendablePressed;
+  }
+
+  /**
+   * Starts the given command whenever the trigger just becomes active.
+   *
+   * @param command the command to start
+   */
+  public void whenActive(final Command command) {
+    new ButtonScheduler() {
+
+      private boolean m_pressedLast = grab();
+
+      @Override
+      public void execute() {
+        if (grab()) {
+          if (!m_pressedLast) {
+            m_pressedLast = true;
+            command.start();
+          }
+        } else {
+          m_pressedLast = false;
+        }
+      }
+    }.start();
+  }
+
+  /**
+   * Constantly starts the given command while the button is held.
+   *
+   * {@link Command#start()} will be called repeatedly while the trigger is active, and will be
+   * canceled when the trigger becomes inactive.
+   *
+   * @param command the command to start
+   */
+  public void whileActive(final Command command) {
+    new ButtonScheduler() {
+
+      private boolean m_pressedLast = grab();
+
+      @Override
+      public void execute() {
+        if (grab()) {
+          m_pressedLast = true;
+          command.start();
+        } else {
+          if (m_pressedLast) {
+            m_pressedLast = false;
+            command.cancel();
+          }
+        }
+      }
+    }.start();
+  }
+
+  /**
+   * Starts the command when the trigger becomes inactive.
+   *
+   * @param command the command to start
+   */
+  public void whenInactive(final Command command) {
+    new ButtonScheduler() {
+
+      private boolean m_pressedLast = grab();
+
+      @Override
+      public void execute() {
+        if (grab()) {
+          m_pressedLast = true;
+        } else {
+          if (m_pressedLast) {
+            m_pressedLast = false;
+            command.start();
+          }
+        }
+      }
+    }.start();
+  }
+
+  /**
+   * Toggles a command when the trigger becomes active.
+   *
+   * @param command the command to toggle
+   */
+  public void toggleWhenActive(final Command command) {
+    new ButtonScheduler() {
+
+      private boolean m_pressedLast = grab();
+
+      @Override
+      public void execute() {
+        if (grab()) {
+          if (!m_pressedLast) {
+            m_pressedLast = true;
+            if (command.isRunning()) {
+              command.cancel();
+            } else {
+              command.start();
+            }
+          }
+        } else {
+          m_pressedLast = false;
+        }
+      }
+    }.start();
+  }
+
+  /**
+   * Cancels a command when the trigger becomes active.
+   *
+   * @param command the command to cancel
+   */
+  public void cancelWhenActive(final Command command) {
+    new ButtonScheduler() {
+
+      private boolean m_pressedLast = grab();
+
+      @Override
+      public void execute() {
+        if (grab()) {
+          if (!m_pressedLast) {
+            m_pressedLast = true;
+            command.cancel();
+          }
+        } else {
+          m_pressedLast = false;
+        }
+      }
+    }.start();
+  }
+
+  /**
+   * An internal class of {@link Trigger}. The user should ignore this, it is only public to
+   * interface between packages.
+   */
+  public abstract class ButtonScheduler {
+    public abstract void execute();
+
+    protected void start() {
+      Scheduler.getInstance().addButton(this);
+    }
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Button");
+    builder.setSafeState(() -> {
+      m_sendablePressed = false;
+    });
+    builder.addBooleanProperty("pressed", this::grab, (value) -> {
+      m_sendablePressed = value;
+    });
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANExceptionFactory.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANExceptionFactory.java
new file mode 100644
index 0000000..79670cf
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANExceptionFactory.java
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.can;
+
+import edu.wpi.first.wpilibj.communication.NIRioStatus;
+import edu.wpi.first.wpilibj.util.UncleanStatusException;
+
+public 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")
+  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));
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANInvalidBufferException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANInvalidBufferException.java
new file mode 100644
index 0000000..3ce53bf
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANInvalidBufferException.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.wpilibj.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 {
+  public CANInvalidBufferException() {
+    super();
+  }
+
+  public CANInvalidBufferException(String msg) {
+    super(msg);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANJNI.java
new file mode 100644
index 0000000..2430776
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.can;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+import edu.wpi.first.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANMessageNotAllowedException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANMessageNotAllowedException.java
new file mode 100644
index 0000000..7977aa4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANMessageNotAllowedException.java
@@ -0,0 +1,18 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.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 {
+  public CANMessageNotAllowedException(String msg) {
+    super(msg);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANMessageNotFoundException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANMessageNotFoundException.java
new file mode 100644
index 0000000..d6f6f12
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANMessageNotFoundException.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.wpilibj.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 {
+  public CANMessageNotFoundException() {
+    super();
+  }
+
+  public CANMessageNotFoundException(String msg) {
+    super(msg);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANNotInitializedException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANNotInitializedException.java
new file mode 100644
index 0000000..16079b4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANNotInitializedException.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.wpilibj.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 {
+  public CANNotInitializedException() {
+    super();
+  }
+
+  public CANNotInitializedException(String msg) {
+    super(msg);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANStatus.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/can/CANStatus.java
new file mode 100644
index 0000000..d9c2920
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Command.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Command.java
new file mode 100644
index 0000000..cdcbc9d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Command.java
@@ -0,0 +1,572 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import java.util.Enumeration;
+
+import edu.wpi.first.wpilibj.RobotState;
+import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.wpilibj.SendableBase;
+import edu.wpi.first.wpilibj.Timer;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * The Command class is at the very core of the entire command framework. Every command can be
+ * started with a call to {@link Command#start() start()}. Once a command is started it will call
+ * {@link Command#initialize() initialize()}, and then will repeatedly call {@link Command#execute()
+ * execute()} until the {@link Command#isFinished() isFinished()} returns true. Once it does, {@link
+ * Command#end() end()} will be called.
+ *
+ * <p>However, if at any point while it is running {@link Command#cancel() cancel()} is called,
+ * then the command will be stopped and {@link Command#interrupted() interrupted()} will be called.
+ *
+ * <p>If a command uses a {@link Subsystem}, then it should specify that it does so by calling the
+ * {@link Command#requires(Subsystem) requires(...)} method in its constructor. Note that a Command
+ * may have multiple requirements, and {@link Command#requires(Subsystem) requires(...)} should be
+ * called for each one.
+ *
+ * <p>If a command is running and a new command with shared requirements is started, then one of
+ * two things will happen. If the active command is interruptible, then {@link Command#cancel()
+ * cancel()} will be called and the command will be removed to make way for the new one. If the
+ * active command is not interruptible, the other one will not even be started, and the active one
+ * will continue functioning.
+ *
+ * @see Subsystem
+ * @see CommandGroup
+ * @see IllegalUseOfCommandException
+ */
+public abstract class Command extends SendableBase implements Sendable {
+  /**
+   * The time since this command was initialized.
+   */
+  private double m_startTime = -1;
+
+  /**
+   * The time (in seconds) before this command "times out" (or -1 if no timeout).
+   */
+  private double m_timeout = -1;
+
+  /**
+   * Whether or not this command has been initialized.
+   */
+  private boolean m_initialized = false;
+
+  /**
+   * The required subsystems.
+   */
+  private final Set m_requirements = new Set();
+
+  /**
+   * Whether or not it is running.
+   */
+  private boolean m_running = false;
+
+  /**
+   * Whether or not it is interruptible.
+   */
+  private boolean m_interruptible = true;
+
+  /**
+   * Whether or not it has been canceled.
+   */
+  private boolean m_canceled = false;
+
+  /**
+   * Whether or not it has been locked.
+   */
+  private boolean m_locked = false;
+
+  /**
+   * Whether this command should run when the robot is disabled.
+   */
+  private boolean m_runWhenDisabled = false;
+
+  /**
+   * Whether or not this command has completed running.
+   */
+  private boolean m_completed = false;
+
+  /**
+   * The {@link CommandGroup} this is in.
+   */
+  private CommandGroup m_parent;
+
+  /**
+   * Creates a new command. The name of this command will be set to its class name.
+   */
+  public Command() {
+    super(false);
+    String name = getClass().getName();
+    setName(name.substring(name.lastIndexOf('.') + 1));
+  }
+
+  /**
+   * Creates a new command with the given name.
+   *
+   * @param name the name for this command
+   * @throws IllegalArgumentException if name is null
+   */
+  public Command(String name) {
+    super(false);
+    if (name == null) {
+      throw new IllegalArgumentException("Name must not be null.");
+    }
+    setName(name);
+  }
+
+  /**
+   * Creates a new command with the given timeout and a default name. The default name is the name
+   * of the class.
+   *
+   * @param timeout the time (in seconds) before this command "times out"
+   * @throws IllegalArgumentException if given a negative timeout
+   * @see Command#isTimedOut() isTimedOut()
+   */
+  public Command(double timeout) {
+    this();
+    if (timeout < 0) {
+      throw new IllegalArgumentException("Timeout must not be negative.  Given:" + timeout);
+    }
+    m_timeout = timeout;
+  }
+
+  /**
+   * Creates a new command with the given name and timeout.
+   *
+   * @param name    the name of the command
+   * @param timeout the time (in seconds) before this command "times out"
+   * @throws IllegalArgumentException if given a negative timeout or name was null.
+   * @see Command#isTimedOut() isTimedOut()
+   */
+  public Command(String name, double timeout) {
+    this(name);
+    if (timeout < 0) {
+      throw new IllegalArgumentException("Timeout must not be negative.  Given:" + timeout);
+    }
+    m_timeout = timeout;
+  }
+
+  /**
+   * Sets the timeout of this command.
+   *
+   * @param seconds the timeout (in seconds)
+   * @throws IllegalArgumentException if seconds is negative
+   * @see Command#isTimedOut() isTimedOut()
+   */
+  protected final synchronized void setTimeout(double seconds) {
+    if (seconds < 0) {
+      throw new IllegalArgumentException("Seconds must be positive.  Given:" + seconds);
+    }
+    m_timeout = seconds;
+  }
+
+  /**
+   * Returns the time since this command was initialized (in seconds). This function will work even
+   * if there is no specified timeout.
+   *
+   * @return the time since this command was initialized (in seconds).
+   */
+  public final synchronized double timeSinceInitialized() {
+    return m_startTime < 0 ? 0 : Timer.getFPGATimestamp() - m_startTime;
+  }
+
+  /**
+   * This method specifies that the given {@link Subsystem} is used by this command. This method is
+   * crucial to the functioning of the Command System in general.
+   *
+   * <p>Note that the recommended way to call this method is in the constructor.
+   *
+   * @param subsystem the {@link Subsystem} required
+   * @throws IllegalArgumentException     if subsystem is null
+   * @throws IllegalUseOfCommandException if this command has started before or if it has been given
+   *                                      to a {@link CommandGroup}
+   * @see Subsystem
+   */
+  protected synchronized void requires(Subsystem subsystem) {
+    validate("Can not add new requirement to command");
+    if (subsystem != null) {
+      m_requirements.add(subsystem);
+    } else {
+      throw new IllegalArgumentException("Subsystem must not be null.");
+    }
+  }
+
+  /**
+   * Called when the command has been removed. This will call {@link Command#interrupted()
+   * interrupted()} or {@link Command#end() end()}.
+   */
+  synchronized void removed() {
+    if (m_initialized) {
+      if (isCanceled()) {
+        interrupted();
+        _interrupted();
+      } else {
+        end();
+        _end();
+      }
+    }
+    m_initialized = false;
+    m_canceled = false;
+    m_running = false;
+    m_completed = true;
+  }
+
+  /**
+   * The run method is used internally to actually run the commands.
+   *
+   * @return whether or not the command should stay within the {@link Scheduler}.
+   */
+  synchronized boolean run() {
+    if (!m_runWhenDisabled && m_parent == null && RobotState.isDisabled()) {
+      cancel();
+    }
+    if (isCanceled()) {
+      return false;
+    }
+    if (!m_initialized) {
+      m_initialized = true;
+      startTiming();
+      _initialize();
+      initialize();
+    }
+    _execute();
+    execute();
+    return !isFinished();
+  }
+
+  /**
+   * The initialize method is called the first time this Command is run after being started.
+   */
+  protected void initialize() {}
+
+  /**
+   * A shadow method called before {@link Command#initialize() initialize()}.
+   */
+  @SuppressWarnings("MethodName")
+  void _initialize() {
+  }
+
+  /**
+   * The execute method is called repeatedly until this Command either finishes or is canceled.
+   */
+  @SuppressWarnings("MethodName")
+  protected void execute() {}
+
+  /**
+   * A shadow method called before {@link Command#execute() execute()}.
+   */
+  @SuppressWarnings("MethodName")
+  void _execute() {
+  }
+
+  /**
+   * Returns whether this command is finished. If it is, then the command will be removed and {@link
+   * Command#end() end()} will be called.
+   *
+   * <p>It may be useful for a team to reference the {@link Command#isTimedOut() isTimedOut()}
+   * method for time-sensitive commands.
+   *
+   * <p>Returning false will result in the command never ending automatically. It may still be
+   * cancelled manually or interrupted by another command. Returning true will result in the
+   * command executing once and finishing immediately. We recommend using {@link InstantCommand}
+   * for this.
+   *
+   * @return whether this command is finished.
+   * @see Command#isTimedOut() isTimedOut()
+   */
+  protected abstract boolean isFinished();
+
+  /**
+   * Called when the command ended peacefully. This is where you may want to wrap up loose ends,
+   * like shutting off a motor that was being used in the command.
+   */
+  protected void end() {}
+
+  /**
+   * A shadow method called after {@link Command#end() end()}.
+   */
+  @SuppressWarnings("MethodName")
+  void _end() {
+  }
+
+  /**
+   * Called when the command ends because somebody called {@link Command#cancel() cancel()} or
+   * another command shared the same requirements as this one, and booted it out.
+   *
+   * <p>This is where you may want to wrap up loose ends, like shutting off a motor that was being
+   * used in the command.
+   *
+   * <p>Generally, it is useful to simply call the {@link Command#end() end()} method within this
+   * method, as done here.
+   */
+  protected void interrupted() {
+    end();
+  }
+
+  /**
+   * A shadow method called after {@link Command#interrupted() interrupted()}.
+   */
+  @SuppressWarnings("MethodName")
+  void _interrupted() {}
+
+  /**
+   * Called to indicate that the timer should start. This is called right before {@link
+   * Command#initialize() initialize()} is, inside the {@link Command#run() run()} method.
+   */
+  private void startTiming() {
+    m_startTime = Timer.getFPGATimestamp();
+  }
+
+  /**
+   * Returns whether or not the {@link Command#timeSinceInitialized() timeSinceInitialized()} method
+   * returns a number which is greater than or equal to the timeout for the command. If there is no
+   * timeout, this will always return false.
+   *
+   * @return whether the time has expired
+   */
+  protected synchronized boolean isTimedOut() {
+    return m_timeout != -1 && timeSinceInitialized() >= m_timeout;
+  }
+
+  /**
+   * Returns the requirements (as an {@link Enumeration Enumeration} of {@link Subsystem
+   * Subsystems}) of this command.
+   *
+   * @return the requirements (as an {@link Enumeration Enumeration} of {@link Subsystem
+   * Subsystems}) of this command
+   */
+  synchronized Enumeration getRequirements() {
+    return m_requirements.getElements();
+  }
+
+  /**
+   * Prevents further changes from being made.
+   */
+  synchronized void lockChanges() {
+    m_locked = true;
+  }
+
+  /**
+   * If changes are locked, then this will throw an {@link IllegalUseOfCommandException}.
+   *
+   * @param message the message to say (it is appended by a default message)
+   */
+  synchronized void validate(String message) {
+    if (m_locked) {
+      throw new IllegalUseOfCommandException(message
+          + " after being started or being added to a command group");
+    }
+  }
+
+  /**
+   * Sets the parent of this command. No actual change is made to the group.
+   *
+   * @param parent the parent
+   * @throws IllegalUseOfCommandException if this {@link Command} already is already in a group
+   */
+  synchronized void setParent(CommandGroup parent) {
+    if (m_parent != null) {
+      throw new IllegalUseOfCommandException(
+          "Can not give command to a command group after already being put in a command group");
+    }
+    lockChanges();
+    m_parent = parent;
+  }
+
+  /**
+   * Returns whether the command has a parent.
+   *
+   * @param True if the command has a parent.
+   */
+  synchronized boolean isParented() {
+    return m_parent != null;
+  }
+
+  /**
+   * Clears list of subsystem requirements. This is only used by
+   * {@link ConditionalCommand} so cancelling the chosen command works properly
+   * in {@link CommandGroup}.
+   */
+  protected void clearRequirements() {
+    m_requirements.clear();
+  }
+
+  /**
+   * Starts up the command. Gets the command ready to start. <p> Note that the command will
+   * eventually start, however it will not necessarily do so immediately, and may in fact be
+   * canceled before initialize is even called. </p>
+   *
+   * @throws IllegalUseOfCommandException if the command is a part of a CommandGroup
+   */
+  public synchronized void start() {
+    lockChanges();
+    if (m_parent != null) {
+      throw new IllegalUseOfCommandException(
+          "Can not start a command that is a part of a command group");
+    }
+    Scheduler.getInstance().add(this);
+    m_completed = false;
+  }
+
+  /**
+   * This is used internally to mark that the command has been started. The lifecycle of a command
+   * is:
+   *
+   * <p>startRunning() is called. run() is called (multiple times potentially) removed() is called.
+   *
+   * <p>It is very important that startRunning and removed be called in order or some assumptions of
+   * the code will be broken.
+   */
+  synchronized void startRunning() {
+    m_running = true;
+    m_startTime = -1;
+  }
+
+  /**
+   * Returns whether or not the command is running. This may return true even if the command has
+   * just been canceled, as it may not have yet called {@link Command#interrupted()}.
+   *
+   * @return whether or not the command is running
+   */
+  public synchronized boolean isRunning() {
+    return m_running;
+  }
+
+  /**
+   * This will cancel the current command. <p> This will cancel the current command eventually. It
+   * can be called multiple times. And it can be called when the command is not running. If the
+   * command is running though, then the command will be marked as canceled and eventually removed.
+   * </p> <p> A command can not be canceled if it is a part of a command group, you must cancel the
+   * command group instead. </p>
+   *
+   * @throws IllegalUseOfCommandException if this command is a part of a command group
+   */
+  public synchronized void cancel() {
+    if (m_parent != null) {
+      throw new IllegalUseOfCommandException("Can not manually cancel a command in a command "
+          + "group");
+    }
+    _cancel();
+  }
+
+  /**
+   * This works like cancel(), except that it doesn't throw an exception if it is a part of a
+   * command group. Should only be called by the parent command group.
+   */
+  @SuppressWarnings("MethodName")
+  synchronized void _cancel() {
+    if (isRunning()) {
+      m_canceled = true;
+    }
+  }
+
+  /**
+   * Returns whether or not this has been canceled.
+   *
+   * @return whether or not this has been canceled
+   */
+  public synchronized boolean isCanceled() {
+    return m_canceled;
+  }
+
+  /**
+   * Whether or not this command has completed running.
+   *
+   * @return whether or not this command has completed running.
+   */
+  public synchronized boolean isCompleted() {
+    return m_completed;
+  }
+
+  /**
+   * Returns whether or not this command can be interrupted.
+   *
+   * @return whether or not this command can be interrupted
+   */
+  public synchronized boolean isInterruptible() {
+    return m_interruptible;
+  }
+
+  /**
+   * Sets whether or not this command can be interrupted.
+   *
+   * @param interruptible whether or not this command can be interrupted
+   */
+  protected synchronized void setInterruptible(boolean interruptible) {
+    m_interruptible = interruptible;
+  }
+
+  /**
+   * Checks if the command requires the given {@link Subsystem}.
+   *
+   * @param system the system
+   * @return whether or not the subsystem is required, or false if given null
+   */
+  public synchronized boolean doesRequire(Subsystem system) {
+    return m_requirements.contains(system);
+  }
+
+  /**
+   * Returns the {@link CommandGroup} that this command is a part of. Will return null if this
+   * {@link Command} is not in a group.
+   *
+   * @return the {@link CommandGroup} that this command is a part of (or null if not in group)
+   */
+  public synchronized CommandGroup getGroup() {
+    return m_parent;
+  }
+
+  /**
+   * Sets whether or not this {@link Command} should run when the robot is disabled.
+   *
+   * <p>By default a command will not run when the robot is disabled, and will in fact be canceled.
+   *
+   * @param run whether or not this command should run when the robot is disabled
+   */
+  public void setRunWhenDisabled(boolean run) {
+    m_runWhenDisabled = run;
+  }
+
+  /**
+   * Returns whether or not this {@link Command} will run when the robot is disabled, or if it will
+   * cancel itself.
+   *
+   * @return True if this command will run when the robot is disabled.
+   */
+  public boolean willRunWhenDisabled() {
+    return m_runWhenDisabled;
+  }
+
+  /**
+   * The string representation for a {@link Command} is by default its name.
+   *
+   * @return the string representation of this object
+   */
+  @Override
+  public String toString() {
+    return getName();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Command");
+    builder.addStringProperty(".name", this::getName, null);
+    builder.addBooleanProperty("running", this::isRunning, (value) -> {
+      if (value) {
+        if (!isRunning()) {
+          start();
+        }
+      } else {
+        if (isRunning()) {
+          cancel();
+        }
+      }
+    });
+    builder.addBooleanProperty(".isParented", this::isParented, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/CommandGroup.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/CommandGroup.java
new file mode 100644
index 0000000..4cc2ac4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/CommandGroup.java
@@ -0,0 +1,410 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A {@link CommandGroup} is a list of commands which are executed in sequence.
+ *
+ * <p> Commands in a {@link CommandGroup} are added using the {@link
+ * CommandGroup#addSequential(Command) addSequential(...)} method and are called sequentially.
+ * {@link CommandGroup CommandGroups} are themselves {@link Command commands} and can be given to
+ * other {@link CommandGroup CommandGroups}. </p>
+ *
+ * <p> {@link CommandGroup CommandGroups} will carry all of the requirements of their {@link Command
+ * subcommands}. Additional requirements can be specified by calling {@link
+ * CommandGroup#requires(Subsystem) requires(...)} normally in the constructor. </P>
+ *
+ * <p> CommandGroups can also execute commands in parallel, simply by adding them using {@link
+ * CommandGroup#addParallel(Command) addParallel(...)}. </p>
+ *
+ * @see Command
+ * @see Subsystem
+ * @see IllegalUseOfCommandException
+ */
+public class CommandGroup extends Command {
+  /**
+   * The commands in this group (stored in entries).
+   */
+  private final Vector<Entry> m_commands = new Vector<>();
+  /*
+   * Intentionally package private
+   */
+  /**
+   * The active children in this group (stored in entries).
+   */
+  final Vector<Entry> m_children = new Vector<>();
+  /**
+   * The current command, -1 signifies that none have been run.
+   */
+  private int m_currentCommandIndex = -1;
+
+  /**
+   * Creates a new {@link CommandGroup CommandGroup}. The name of this command will be set to its
+   * class name.
+   */
+  public CommandGroup() {
+  }
+
+  /**
+   * Creates a new {@link CommandGroup CommandGroup} with the given name.
+   *
+   * @param name the name for this command group
+   * @throws IllegalArgumentException if name is null
+   */
+  public CommandGroup(String name) {
+    super(name);
+  }
+
+  /**
+   * Adds a new {@link Command Command} to the group. The {@link Command Command} will be started
+   * after all the previously added {@link Command Commands}.
+   *
+   * <p> Note that any requirements the given {@link Command Command} has will be added to the
+   * group. For this reason, a {@link Command Command's} requirements can not be changed after being
+   * added to a group. </p>
+   *
+   * <p> It is recommended that this method be called in the constructor. </p>
+   *
+   * @param command The {@link Command Command} to be added
+   * @throws IllegalUseOfCommandException if the group has been started before or been given to
+   *                                      another group
+   * @throws IllegalArgumentException     if command is null
+   */
+  public final synchronized void addSequential(Command command) {
+    validate("Can not add new command to command group");
+    if (command == null) {
+      throw new IllegalArgumentException("Given null command");
+    }
+
+    command.setParent(this);
+
+    m_commands.addElement(new Entry(command, Entry.IN_SEQUENCE));
+    for (Enumeration e = command.getRequirements(); e.hasMoreElements(); ) {
+      requires((Subsystem) e.nextElement());
+    }
+  }
+
+  /**
+   * Adds a new {@link Command Command} to the group with a given timeout. The {@link Command
+   * Command} will be started after all the previously added commands.
+   *
+   * <p> Once the {@link Command Command} is started, it will be run until it finishes or the time
+   * expires, whichever is sooner. Note that the given {@link Command Command} will have no
+   * knowledge that it is on a timer. </p>
+   *
+   * <p> Note that any requirements the given {@link Command Command} has will be added to the
+   * group. For this reason, a {@link Command Command's} requirements can not be changed after being
+   * added to a group. </p>
+   *
+   * <p> It is recommended that this method be called in the constructor. </p>
+   *
+   * @param command The {@link Command Command} to be added
+   * @param timeout The timeout (in seconds)
+   * @throws IllegalUseOfCommandException if the group has been started before or been given to
+   *                                      another group or if the {@link Command Command} has been
+   *                                      started before or been given to another group
+   * @throws IllegalArgumentException     if command is null or timeout is negative
+   */
+  public final synchronized void addSequential(Command command, double timeout) {
+    validate("Can not add new command to command group");
+    if (command == null) {
+      throw new IllegalArgumentException("Given null command");
+    }
+    if (timeout < 0) {
+      throw new IllegalArgumentException("Can not be given a negative timeout");
+    }
+
+    command.setParent(this);
+
+    m_commands.addElement(new Entry(command, Entry.IN_SEQUENCE, timeout));
+    for (Enumeration e = command.getRequirements(); e.hasMoreElements(); ) {
+      requires((Subsystem) e.nextElement());
+    }
+  }
+
+  /**
+   * Adds a new child {@link Command} to the group. The {@link Command} will be started after all
+   * the previously added {@link Command Commands}.
+   *
+   * <p> Instead of waiting for the child to finish, a {@link CommandGroup} will have it run at the
+   * same time as the subsequent {@link Command Commands}. The child will run until either it
+   * finishes, a new child with conflicting requirements is started, or the main sequence runs a
+   * {@link Command} with conflicting requirements. In the latter two cases, the child will be
+   * canceled even if it says it can't be interrupted. </p>
+   *
+   * <p> Note that any requirements the given {@link Command Command} has will be added to the
+   * group. For this reason, a {@link Command Command's} requirements can not be changed after being
+   * added to a group. </p>
+   *
+   * <p> It is recommended that this method be called in the constructor. </p>
+   *
+   * @param command The command to be added
+   * @throws IllegalUseOfCommandException if the group has been started before or been given to
+   *                                      another command group
+   * @throws IllegalArgumentException     if command is null
+   */
+  public final synchronized void addParallel(Command command) {
+    requireNonNull(command, "Provided command was null");
+    validate("Can not add new command to command group");
+
+    command.setParent(this);
+
+    m_commands.addElement(new Entry(command, Entry.BRANCH_CHILD));
+    for (Enumeration e = command.getRequirements(); e.hasMoreElements(); ) {
+      requires((Subsystem) e.nextElement());
+    }
+  }
+
+  /**
+   * Adds a new child {@link Command} to the group with the given timeout. The {@link Command} will
+   * be started after all the previously added {@link Command Commands}.
+   *
+   * <p> Once the {@link Command Command} is started, it will run until it finishes, is interrupted,
+   * or the time expires, whichever is sooner. Note that the given {@link Command Command} will have
+   * no knowledge that it is on a timer. </p>
+   *
+   * <p> Instead of waiting for the child to finish, a {@link CommandGroup} will have it run at the
+   * same time as the subsequent {@link Command Commands}. The child will run until either it
+   * finishes, the timeout expires, a new child with conflicting requirements is started, or the
+   * main sequence runs a {@link Command} with conflicting requirements. In the latter two cases,
+   * the child will be canceled even if it says it can't be interrupted. </p>
+   *
+   * <p> Note that any requirements the given {@link Command Command} has will be added to the
+   * group. For this reason, a {@link Command Command's} requirements can not be changed after being
+   * added to a group. </p>
+   *
+   * <p> It is recommended that this method be called in the constructor. </p>
+   *
+   * @param command The command to be added
+   * @param timeout The timeout (in seconds)
+   * @throws IllegalUseOfCommandException if the group has been started before or been given to
+   *                                      another command group
+   * @throws IllegalArgumentException     if command is null
+   */
+  public final synchronized void addParallel(Command command, double timeout) {
+    requireNonNull(command, "Provided command was null");
+    if (timeout < 0) {
+      throw new IllegalArgumentException("Can not be given a negative timeout");
+    }
+    validate("Can not add new command to command group");
+
+    command.setParent(this);
+
+    m_commands.addElement(new Entry(command, Entry.BRANCH_CHILD, timeout));
+    for (Enumeration e = command.getRequirements(); e.hasMoreElements(); ) {
+      requires((Subsystem) e.nextElement());
+    }
+  }
+
+  @SuppressWarnings("MethodName")
+  void _initialize() {
+    m_currentCommandIndex = -1;
+  }
+
+  @SuppressWarnings("MethodName")
+  void _execute() {
+    Entry entry = null;
+    Command cmd = null;
+    boolean firstRun = false;
+    if (m_currentCommandIndex == -1) {
+      firstRun = true;
+      m_currentCommandIndex = 0;
+    }
+
+    while (m_currentCommandIndex < m_commands.size()) {
+
+      if (cmd != null) {
+        if (entry.isTimedOut()) {
+          cmd._cancel();
+        }
+        if (cmd.run()) {
+          break;
+        } else {
+          cmd.removed();
+          m_currentCommandIndex++;
+          firstRun = true;
+          cmd = null;
+          continue;
+        }
+      }
+
+      entry = m_commands.elementAt(m_currentCommandIndex);
+      cmd = null;
+
+      switch (entry.m_state) {
+        case Entry.IN_SEQUENCE:
+          cmd = entry.m_command;
+          if (firstRun) {
+            cmd.startRunning();
+            cancelConflicts(cmd);
+          }
+          firstRun = false;
+          break;
+        case Entry.BRANCH_PEER:
+          m_currentCommandIndex++;
+          entry.m_command.start();
+          break;
+        case Entry.BRANCH_CHILD:
+          m_currentCommandIndex++;
+          cancelConflicts(entry.m_command);
+          entry.m_command.startRunning();
+          m_children.addElement(entry);
+          break;
+        default:
+          break;
+      }
+    }
+
+    // Run Children
+    for (int i = 0; i < m_children.size(); i++) {
+      entry = m_children.elementAt(i);
+      Command child = entry.m_command;
+      if (entry.isTimedOut()) {
+        child._cancel();
+      }
+      if (!child.run()) {
+        child.removed();
+        m_children.removeElementAt(i--);
+      }
+    }
+  }
+
+  @SuppressWarnings("MethodName")
+  void _end() {
+    // Theoretically, we don't have to check this, but we do if teams override
+    // the isFinished method
+    if (m_currentCommandIndex != -1 && m_currentCommandIndex < m_commands.size()) {
+      Command cmd = m_commands.elementAt(m_currentCommandIndex).m_command;
+      cmd._cancel();
+      cmd.removed();
+    }
+
+    Enumeration children = m_children.elements();
+    while (children.hasMoreElements()) {
+      Command cmd = ((Entry) children.nextElement()).m_command;
+      cmd._cancel();
+      cmd.removed();
+    }
+    m_children.removeAllElements();
+  }
+
+  @SuppressWarnings("MethodName")
+  void _interrupted() {
+    _end();
+  }
+
+  /**
+   * Returns true if all the {@link Command Commands} in this group have been started and have
+   * finished.
+   *
+   * <p> Teams may override this method, although they should probably reference super.isFinished()
+   * if they do. </p>
+   *
+   * @return whether this {@link CommandGroup} is finished
+   */
+  protected boolean isFinished() {
+    return m_currentCommandIndex >= m_commands.size() && m_children.isEmpty();
+  }
+
+  // Can be overwritten by teams
+  protected void initialize() {
+  }
+
+  // Can be overwritten by teams
+  protected void execute() {
+  }
+
+  // Can be overwritten by teams
+  protected void end() {
+  }
+
+  // Can be overwritten by teams
+  protected void interrupted() {
+  }
+
+  /**
+   * Returns whether or not this group is interruptible. A command group will be uninterruptible if
+   * {@link CommandGroup#setInterruptible(boolean) setInterruptable(false)} was called or if it is
+   * currently running an uninterruptible command or child.
+   *
+   * @return whether or not this {@link CommandGroup} is interruptible.
+   */
+  public synchronized boolean isInterruptible() {
+    if (!super.isInterruptible()) {
+      return false;
+    }
+
+    if (m_currentCommandIndex != -1 && m_currentCommandIndex < m_commands.size()) {
+      Command cmd = m_commands.elementAt(m_currentCommandIndex).m_command;
+      if (!cmd.isInterruptible()) {
+        return false;
+      }
+    }
+
+    for (int i = 0; i < m_children.size(); i++) {
+      if (!m_children.elementAt(i).m_command.isInterruptible()) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  private void cancelConflicts(Command command) {
+    for (int i = 0; i < m_children.size(); i++) {
+      Command child = m_children.elementAt(i).m_command;
+
+      Enumeration requirements = command.getRequirements();
+
+      while (requirements.hasMoreElements()) {
+        Object requirement = requirements.nextElement();
+        if (child.doesRequire((Subsystem) requirement)) {
+          child._cancel();
+          child.removed();
+          m_children.removeElementAt(i--);
+          break;
+        }
+      }
+    }
+  }
+
+  private static class Entry {
+    private static final int IN_SEQUENCE = 0;
+    private static final int BRANCH_PEER = 1;
+    private static final int BRANCH_CHILD = 2;
+    private final Command m_command;
+    private final int m_state;
+    private final double m_timeout;
+
+    Entry(Command command, int state) {
+      m_command = command;
+      m_state = state;
+      m_timeout = -1;
+    }
+
+    Entry(Command command, int state, double timeout) {
+      m_command = command;
+      m_state = state;
+      m_timeout = timeout;
+    }
+
+    boolean isTimedOut() {
+      if (m_timeout == -1) {
+        return false;
+      } else {
+        double time = m_command.timeSinceInitialized();
+        return time != 0 && time >= m_timeout;
+      }
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/ConditionalCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/ConditionalCommand.java
new file mode 100644
index 0000000..9d06d3d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/ConditionalCommand.java
@@ -0,0 +1,175 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import java.util.Enumeration;
+
+/**
+ * A {@link ConditionalCommand} is a {@link Command} that starts one of two commands.
+ *
+ * <p>
+ * A {@link ConditionalCommand} uses m_condition to determine whether it should run m_onTrue or
+ * m_onFalse.
+ * </p>
+ *
+ * <p>
+ * A {@link ConditionalCommand} adds the proper {@link Command} to the {@link Scheduler} during
+ * {@link ConditionalCommand#initialize()} and then {@link ConditionalCommand#isFinished()} will
+ * return true once that {@link Command} has finished executing.
+ * </p>
+ *
+ * <p>
+ * If no {@link Command} is specified for m_onFalse, the occurrence of that condition will be a
+ * no-op.
+ * </p>
+ *
+ * @see Command
+ * @see Scheduler
+ */
+public abstract class ConditionalCommand extends Command {
+  /**
+   * The Command to execute if {@link ConditionalCommand#condition()} returns true.
+   */
+  private Command m_onTrue;
+
+  /**
+   * The Command to execute if {@link ConditionalCommand#condition()} returns false.
+   */
+  private Command m_onFalse;
+
+  /**
+   * Stores command chosen by condition.
+   */
+  private Command m_chosenCommand = null;
+
+  private void requireAll() {
+    if (m_onTrue != null) {
+      for (Enumeration e = m_onTrue.getRequirements(); e.hasMoreElements(); ) {
+        requires((Subsystem) e.nextElement());
+      }
+    }
+
+    if (m_onFalse != null) {
+      for (Enumeration e = m_onFalse.getRequirements(); e.hasMoreElements(); ) {
+        requires((Subsystem) e.nextElement());
+      }
+    }
+  }
+
+  /**
+   * Creates a new ConditionalCommand with given onTrue and onFalse Commands.
+   *
+   * <p>Users of this constructor should also override condition().
+   *
+   * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true
+   */
+  public ConditionalCommand(Command onTrue) {
+    this(onTrue, null);
+  }
+
+  /**
+   * Creates a new ConditionalCommand with given onTrue and onFalse Commands.
+   *
+   * <p>Users of this constructor should also override condition().
+   *
+   * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true
+   * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false
+   */
+  public ConditionalCommand(Command onTrue, Command onFalse) {
+    m_onTrue = onTrue;
+    m_onFalse = onFalse;
+
+    requireAll();
+  }
+
+  /**
+   * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands.
+   *
+   * <p>Users of this constructor should also override condition().
+   *
+   * @param name the name for this command group
+   * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true
+   */
+  public ConditionalCommand(String name, Command onTrue) {
+    this(name, onTrue, null);
+  }
+
+  /**
+   * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands.
+   *
+   * <p>Users of this constructor should also override condition().
+   *
+   * @param name the name for this command group
+   * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true
+   * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false
+   */
+  public ConditionalCommand(String name, Command onTrue, Command onFalse) {
+    super(name);
+    m_onTrue = onTrue;
+    m_onFalse = onFalse;
+
+    requireAll();
+  }
+
+  /**
+   * The Condition to test to determine which Command to run.
+   *
+   * @return true if m_onTrue should be run or false if m_onFalse should be run.
+   */
+  protected abstract boolean condition();
+
+  /**
+   * Calls {@link ConditionalCommand#condition()} and runs the proper command.
+   */
+  @Override
+  protected void _initialize() {
+    if (condition()) {
+      m_chosenCommand = m_onTrue;
+    } else {
+      m_chosenCommand = m_onFalse;
+    }
+
+    if (m_chosenCommand != null) {
+      /*
+       * This is a hack to make cancelling the chosen command inside a
+       * CommandGroup work properly
+       */
+      m_chosenCommand.clearRequirements();
+
+      m_chosenCommand.start();
+    }
+    super._initialize();
+  }
+
+  @Override
+  protected void _cancel() {
+    if (m_chosenCommand != null && m_chosenCommand.isRunning()) {
+      m_chosenCommand.cancel();
+    }
+
+    super._cancel();
+  }
+
+  @Override
+  protected boolean isFinished() {
+    if (m_chosenCommand != null) {
+      return m_chosenCommand.isCompleted();
+    } else {
+      return true;
+    }
+  }
+
+  @Override
+  protected void _interrupted() {
+    if (m_chosenCommand != null && m_chosenCommand.isRunning()) {
+      m_chosenCommand.cancel();
+    }
+
+    super._interrupted();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/IllegalUseOfCommandException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/IllegalUseOfCommandException.java
new file mode 100644
index 0000000..59f6e9c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/IllegalUseOfCommandException.java
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+/**
+ * This exception will be thrown if a command is used illegally. There are several ways for this to
+ * happen.
+ *
+ * <p> Basically, a command becomes "locked" after it is first started or added to a command group.
+ * </p>
+ *
+ * <p> This exception should be thrown if (after a command has been locked) its requirements change,
+ * it is put into multiple command groups, it is started from outside its command group, or it adds
+ * a new child. </p>
+ */
+public class IllegalUseOfCommandException extends RuntimeException {
+  /**
+   * Instantiates an {@link IllegalUseOfCommandException}.
+   */
+  public IllegalUseOfCommandException() {
+  }
+
+  /**
+   * Instantiates an {@link IllegalUseOfCommandException} with the given message.
+   *
+   * @param message the message
+   */
+  public IllegalUseOfCommandException(String message) {
+    super(message);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/InstantCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/InstantCommand.java
new file mode 100644
index 0000000..ca27472
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/InstantCommand.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.command;
+
+/**
+ * This command will execute once, then finish immediately afterward.
+ *
+ * <p>Subclassing {@link InstantCommand} is shorthand for returning true from
+ * {@link Command isFinished}.
+ */
+public class InstantCommand extends Command {
+  public InstantCommand() {
+  }
+
+  /**
+   * Creates a new {@link InstantCommand InstantCommand} with the given name.
+   * @param name the name for this command
+   */
+  public InstantCommand(String name) {
+    super(name);
+  }
+
+  protected boolean isFinished() {
+    return true;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/LinkedListElement.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/LinkedListElement.java
new file mode 100644
index 0000000..e717a47
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/LinkedListElement.java
@@ -0,0 +1,63 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+/**
+ * An element that is in a LinkedList.
+ */
+class LinkedListElement {
+  private LinkedListElement m_next;
+  private LinkedListElement m_previous;
+  private Command m_data;
+
+  public void setData(Command newData) {
+    m_data = newData;
+  }
+
+  public Command getData() {
+    return m_data;
+  }
+
+  public LinkedListElement getNext() {
+    return m_next;
+  }
+
+  public LinkedListElement getPrevious() {
+    return m_previous;
+  }
+
+  public void add(LinkedListElement listElement) {
+    if (m_next == null) {
+      m_next = listElement;
+      m_next.m_previous = this;
+    } else {
+      m_next.m_previous = listElement;
+      listElement.m_next = m_next;
+      listElement.m_previous = this;
+      m_next = listElement;
+    }
+  }
+
+  @SuppressWarnings("PMD.EmptyIfStmt")
+  public LinkedListElement remove() {
+    if (m_previous == null && m_next == null) {
+      // no-op
+    } else if (m_next == null) {
+      m_previous.m_next = null;
+    } else if (m_previous == null) {
+      m_next.m_previous = null;
+    } else {
+      m_next.m_previous = m_previous;
+      m_previous.m_next = m_next;
+    }
+    LinkedListElement returnNext = m_next;
+    m_next = null;
+    m_previous = null;
+    return returnNext;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PIDCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PIDCommand.java
new file mode 100644
index 0000000..0569fa6
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PIDCommand.java
@@ -0,0 +1,217 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import edu.wpi.first.wpilibj.PIDController;
+import edu.wpi.first.wpilibj.PIDOutput;
+import edu.wpi.first.wpilibj.PIDSource;
+import edu.wpi.first.wpilibj.PIDSourceType;
+import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * This class defines a {@link Command} which interacts heavily with a PID loop.
+ *
+ * <p> It provides some convenience methods to run an internal {@link PIDController} . It will also
+ * start and stop said {@link PIDController} when the {@link PIDCommand} is first initialized and
+ * ended/interrupted. </p>
+ */
+public abstract class PIDCommand extends Command implements Sendable {
+  /**
+   * The internal {@link PIDController}.
+   */
+  private final PIDController m_controller;
+  /**
+   * An output which calls {@link PIDCommand#usePIDOutput(double)}.
+   */
+  private final PIDOutput m_output = this::usePIDOutput;
+  /**
+   * A source which calls {@link PIDCommand#returnPIDInput()}.
+   */
+  private final PIDSource m_source = new PIDSource() {
+    public void setPIDSourceType(PIDSourceType pidSource) {
+    }
+
+    public PIDSourceType getPIDSourceType() {
+      return PIDSourceType.kDisplacement;
+    }
+
+    public double pidGet() {
+      return returnPIDInput();
+    }
+  };
+
+  /**
+   * Instantiates a {@link PIDCommand} that will use the given p, i and d values.
+   *
+   * @param name the name of the command
+   * @param p    the proportional value
+   * @param i    the integral value
+   * @param d    the derivative value
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDCommand(String name, double p, double i, double d) {
+    super(name);
+    m_controller = new PIDController(p, i, d, m_source, m_output);
+  }
+
+  /**
+   * Instantiates a {@link PIDCommand} that will use the given p, i and d values. It will also space
+   * the time between PID loop calculations to be equal to the given period.
+   *
+   * @param name   the name
+   * @param p      the proportional value
+   * @param i      the integral value
+   * @param d      the derivative value
+   * @param period the time (in seconds) between calculations
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDCommand(String name, double p, double i, double d, double period) {
+    super(name);
+    m_controller = new PIDController(p, i, d, m_source, m_output, period);
+  }
+
+  /**
+   * Instantiates a {@link PIDCommand} that will use the given p, i and d values. It will use the
+   * class name as its name.
+   *
+   * @param p the proportional value
+   * @param i the integral value
+   * @param d the derivative value
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDCommand(double p, double i, double d) {
+    m_controller = new PIDController(p, i, d, m_source, m_output);
+  }
+
+  /**
+   * Instantiates a {@link PIDCommand} that will use the given p, i and d values. It will use the
+   * class name as its name.. It will also space the time between PID loop calculations to be equal
+   * to the given period.
+   *
+   * @param p      the proportional value
+   * @param i      the integral value
+   * @param d      the derivative value
+   * @param period the time (in seconds) between calculations
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDCommand(double p, double i, double d, double period) {
+    m_controller = new PIDController(p, i, d, m_source, m_output, period);
+  }
+
+  /**
+   * Returns the {@link PIDController} used by this {@link PIDCommand}. Use this if you would like
+   * to fine tune the pid loop.
+   *
+   * @return the {@link PIDController} used by this {@link PIDCommand}
+   */
+  protected PIDController getPIDController() {
+    return m_controller;
+  }
+
+  @Override
+  @SuppressWarnings("MethodName")
+  void _initialize() {
+    m_controller.enable();
+  }
+
+  @Override
+  @SuppressWarnings("MethodName")
+  void _end() {
+    m_controller.disable();
+  }
+
+  @Override
+  @SuppressWarnings("MethodName")
+  void _interrupted() {
+    _end();
+  }
+
+  /**
+   * Adds the given value to the setpoint. If {@link PIDCommand#setInputRange(double, double)
+   * setInputRange(...)} was used, then the bounds will still be honored by this method.
+   *
+   * @param deltaSetpoint the change in the setpoint
+   */
+  public void setSetpointRelative(double deltaSetpoint) {
+    setSetpoint(getSetpoint() + deltaSetpoint);
+  }
+
+  /**
+   * Sets the setpoint to the given value. If {@link PIDCommand#setInputRange(double, double)
+   * setInputRange(...)} was called, then the given setpoint will be trimmed to fit within the
+   * range.
+   *
+   * @param setpoint the new setpoint
+   */
+  protected void setSetpoint(double setpoint) {
+    m_controller.setSetpoint(setpoint);
+  }
+
+  /**
+   * Returns the setpoint.
+   *
+   * @return the setpoint
+   */
+  protected double getSetpoint() {
+    return m_controller.getSetpoint();
+  }
+
+  /**
+   * Returns the current position.
+   *
+   * @return the current position
+   */
+  protected double getPosition() {
+    return returnPIDInput();
+  }
+
+  /**
+   * Sets the maximum and minimum values expected from the input and setpoint.
+   *
+   * @param minimumInput the minimum value expected from the input and setpoint
+   * @param maximumInput the maximum value expected from the input and setpoint
+   */
+  protected void setInputRange(double minimumInput, double maximumInput) {
+    m_controller.setInputRange(minimumInput, maximumInput);
+  }
+
+  /**
+   * Returns the input for the pid loop.
+   *
+   * <p>It returns the input for the pid loop, so if this command was based off of a gyro, then it
+   * should return the angle of the gyro.
+   *
+   * <p>All subclasses of {@link PIDCommand} must override this method.
+   *
+   * <p>This method will be called in a different thread then the {@link Scheduler} thread.
+   *
+   * @return the value the pid loop should use as input
+   */
+  protected abstract double returnPIDInput();
+
+  /**
+   * Uses the value that the pid loop calculated. The calculated value is the "output" parameter.
+   * This method is a good time to set motor values, maybe something along the lines of
+   * <code>driveline.tankDrive(output, -output)</code>
+   *
+   * <p>All subclasses of {@link PIDCommand} must override this method.
+   *
+   * <p>This method will be called in a different thread then the {@link Scheduler} thread.
+   *
+   * @param output the value the pid loop calculated
+   */
+  protected abstract void usePIDOutput(double output);
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    m_controller.initSendable(builder);
+    super.initSendable(builder);
+    builder.setSmartDashboardType("PIDCommand");
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PIDSubsystem.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PIDSubsystem.java
new file mode 100644
index 0000000..e2edfb9
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PIDSubsystem.java
@@ -0,0 +1,284 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import edu.wpi.first.wpilibj.PIDController;
+import edu.wpi.first.wpilibj.PIDOutput;
+import edu.wpi.first.wpilibj.PIDSource;
+import edu.wpi.first.wpilibj.PIDSourceType;
+import edu.wpi.first.wpilibj.Sendable;
+
+/**
+ * This class is designed to handle the case where there is a {@link Subsystem} which uses a single
+ * {@link PIDController} almost constantly (for instance, an elevator which attempts to stay at a
+ * constant height).
+ *
+ * <p>It provides some convenience methods to run an internal {@link PIDController} . It also
+ * allows access to the internal {@link PIDController} in order to give total control to the
+ * programmer.
+ */
+public abstract class PIDSubsystem extends Subsystem implements Sendable {
+  /**
+   * The internal {@link PIDController}.
+   */
+  private final PIDController m_controller;
+  /**
+   * An output which calls {@link PIDCommand#usePIDOutput(double)}.
+   */
+  private final PIDOutput m_output = this::usePIDOutput;
+
+  /**
+   * A source which calls {@link PIDCommand#returnPIDInput()}.
+   */
+  private final PIDSource m_source = new PIDSource() {
+    public void setPIDSourceType(PIDSourceType pidSource) {
+    }
+
+    public PIDSourceType getPIDSourceType() {
+      return PIDSourceType.kDisplacement;
+    }
+
+    public double pidGet() {
+      return returnPIDInput();
+    }
+  };
+
+  /**
+   * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
+   *
+   * @param name the name
+   * @param p    the proportional value
+   * @param i    the integral value
+   * @param d    the derivative value
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDSubsystem(String name, double p, double i, double d) {
+    super(name);
+    m_controller = new PIDController(p, i, d, m_source, m_output);
+    addChild("PIDController", m_controller);
+  }
+
+  /**
+   * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
+   *
+   * @param name the name
+   * @param p    the proportional value
+   * @param i    the integral value
+   * @param d    the derivative value
+   * @param f    the feed forward value
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDSubsystem(String name, double p, double i, double d, double f) {
+    super(name);
+    m_controller = new PIDController(p, i, d, f, m_source, m_output);
+    addChild("PIDController", m_controller);
+  }
+
+  /**
+   * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will also
+   * space the time between PID loop calculations to be equal to the given period.
+   *
+   * @param name   the name
+   * @param p      the proportional value
+   * @param i      the integral value
+   * @param d      the derivative value
+   * @param period the time (in seconds) between calculations
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDSubsystem(String name, double p, double i, double d, double f, double period) {
+    super(name);
+    m_controller = new PIDController(p, i, d, f, m_source, m_output, period);
+    addChild("PIDController", m_controller);
+  }
+
+  /**
+   * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will use the
+   * class name as its name.
+   *
+   * @param p the proportional value
+   * @param i the integral value
+   * @param d the derivative value
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDSubsystem(double p, double i, double d) {
+    m_controller = new PIDController(p, i, d, m_source, m_output);
+    addChild("PIDController", m_controller);
+  }
+
+  /**
+   * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will use the
+   * class name as its name. It will also space the time between PID loop calculations to be equal
+   * to the given period.
+   *
+   * @param p      the proportional value
+   * @param i      the integral value
+   * @param d      the derivative value
+   * @param f      the feed forward coefficient
+   * @param period the time (in seconds) between calculations
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDSubsystem(double p, double i, double d, double period, double f) {
+    m_controller = new PIDController(p, i, d, f, m_source, m_output, period);
+    addChild("PIDController", m_controller);
+  }
+
+  /**
+   * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will use the
+   * class name as its name. It will also space the time between PID loop calculations to be equal
+   * to the given period.
+   *
+   * @param p      the proportional value
+   * @param i      the integral value
+   * @param d      the derivative value
+   * @param period the time (in seconds) between calculations
+   */
+  @SuppressWarnings("ParameterName")
+  public PIDSubsystem(double p, double i, double d, double period) {
+    m_controller = new PIDController(p, i, d, m_source, m_output, period);
+    addChild("PIDController", m_controller);
+  }
+
+  /**
+   * Returns the {@link PIDController} used by this {@link PIDSubsystem}. Use this if you would like
+   * to fine tune the pid loop.
+   *
+   * @return the {@link PIDController} used by this {@link PIDSubsystem}
+   */
+  public PIDController getPIDController() {
+    return m_controller;
+  }
+
+
+  /**
+   * Adds the given value to the setpoint. If {@link PIDSubsystem#setInputRange(double, double)
+   * setInputRange(...)} was used, then the bounds will still be honored by this method.
+   *
+   * @param deltaSetpoint the change in the setpoint
+   */
+  public void setSetpointRelative(double deltaSetpoint) {
+    setSetpoint(getPosition() + deltaSetpoint);
+  }
+
+  /**
+   * Sets the setpoint to the given value. If {@link PIDSubsystem#setInputRange(double, double)
+   * setInputRange(...)} was called, then the given setpoint will be trimmed to fit within the
+   * range.
+   *
+   * @param setpoint the new setpoint
+   */
+  public void setSetpoint(double setpoint) {
+    m_controller.setSetpoint(setpoint);
+  }
+
+  /**
+   * Returns the setpoint.
+   *
+   * @return the setpoint
+   */
+  public double getSetpoint() {
+    return m_controller.getSetpoint();
+  }
+
+  /**
+   * Returns the current position.
+   *
+   * @return the current position
+   */
+  public double getPosition() {
+    return returnPIDInput();
+  }
+
+  /**
+   * Sets the maximum and minimum values expected from the input.
+   *
+   * @param minimumInput the minimum value expected from the input
+   * @param maximumInput the maximum value expected from the output
+   */
+  public void setInputRange(double minimumInput, double maximumInput) {
+    m_controller.setInputRange(minimumInput, maximumInput);
+  }
+
+  /**
+   * Sets the maximum and minimum values to write.
+   *
+   * @param minimumOutput the minimum value to write to the output
+   * @param maximumOutput the maximum value to write to the output
+   */
+  public void setOutputRange(double minimumOutput, double maximumOutput) {
+    m_controller.setOutputRange(minimumOutput, maximumOutput);
+  }
+
+  /**
+   * Set the absolute error which is considered tolerable for use with OnTarget. The value is in the
+   * same range as the PIDInput values.
+   *
+   * @param t the absolute tolerance
+   */
+  @SuppressWarnings("ParameterName")
+  public void setAbsoluteTolerance(double t) {
+    m_controller.setAbsoluteTolerance(t);
+  }
+
+  /**
+   * Set the percentage error which is considered tolerable for use with OnTarget. (Value of 15.0 ==
+   * 15 percent).
+   *
+   * @param p the percent tolerance
+   */
+  @SuppressWarnings("ParameterName")
+  public void setPercentTolerance(double p) {
+    m_controller.setPercentTolerance(p);
+  }
+
+  /**
+   * Return true if the error is within the percentage of the total input range, determined by
+   * setTolerance. This assumes that the maximum and minimum input were set using setInput.
+   *
+   * @return true if the error is less than the tolerance
+   */
+  public boolean onTarget() {
+    return m_controller.onTarget();
+  }
+
+  /**
+   * Returns the input for the pid loop.
+   *
+   * <p>It returns the input for the pid loop, so if this Subsystem was based off of a gyro, then
+   * it should return the angle of the gyro.
+   *
+   * <p>All subclasses of {@link PIDSubsystem} must override this method.
+   *
+   * @return the value the pid loop should use as input
+   */
+  protected abstract double returnPIDInput();
+
+  /**
+   * Uses the value that the pid loop calculated. The calculated value is the "output" parameter.
+   * This method is a good time to set motor values, maybe something along the lines of
+   * <code>driveline.tankDrive(output, -output)</code>.
+   *
+   * <p>All subclasses of {@link PIDSubsystem} must override this method.
+   *
+   * @param output the value the pid loop calculated
+   */
+  protected abstract void usePIDOutput(double output);
+
+  /**
+   * Enables the internal {@link PIDController}.
+   */
+  public void enable() {
+    m_controller.enable();
+  }
+
+  /**
+   * Disables the internal {@link PIDController}.
+   */
+  public void disable() {
+    m_controller.disable();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PrintCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PrintCommand.java
new file mode 100644
index 0000000..3582670
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/PrintCommand.java
@@ -0,0 +1,34 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+/**
+ * A {@link PrintCommand} is a command which prints out a string when it is initialized, and then
+ * immediately finishes. It is useful if you want a {@link CommandGroup} to print out a string when
+ * it reaches a certain point.
+ */
+public class PrintCommand extends InstantCommand {
+  /**
+   * The message to print out.
+   */
+  private String m_message;
+
+  /**
+   * Instantiates a {@link PrintCommand} which will print the given message when it is run.
+   *
+   * @param message the message to print
+   */
+  public PrintCommand(String message) {
+    super("Print(\"" + message + "\"");
+    m_message = message;
+  }
+
+  protected void initialize() {
+    System.out.println(m_message);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Scheduler.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Scheduler.java
new file mode 100644
index 0000000..411d74a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Scheduler.java
@@ -0,0 +1,349 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.wpilibj.HLUsageReporting;
+import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.wpilibj.SendableBase;
+import edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * The {@link Scheduler} is a singleton which holds the top-level running commands. It is in charge
+ * of both calling the command's {@link Command#run() run()} method and to make sure that there are
+ * no two commands with conflicting requirements running.
+ *
+ * <p> It is fine if teams wish to take control of the {@link Scheduler} themselves, all that needs
+ * to be done is to call {@link Scheduler#getInstance() Scheduler.getInstance()}.{@link
+ * Scheduler#run() run()} often to have {@link Command Commands} function correctly. However, this
+ * is already done for you if you use the CommandBased Robot template. </p>
+ *
+ * @see Command
+ */
+public class Scheduler extends SendableBase implements Sendable {
+  /**
+   * The Singleton Instance.
+   */
+  private static Scheduler instance;
+
+  /**
+   * Returns the {@link Scheduler}, creating it if one does not exist.
+   *
+   * @return the {@link Scheduler}
+   */
+  public static synchronized Scheduler getInstance() {
+    if (instance == null) {
+      instance = new Scheduler();
+    }
+    return instance;
+  }
+
+  /**
+   * A hashtable of active {@link Command Commands} to their {@link LinkedListElement}.
+   */
+  private Hashtable<Command, LinkedListElement> m_commandTable = new Hashtable<>();
+  /**
+   * The {@link Set} of all {@link Subsystem Subsystems}.
+   */
+  private Set m_subsystems = new Set();
+  /**
+   * The first {@link Command} in the list.
+   */
+  private LinkedListElement m_firstCommand;
+  /**
+   * The last {@link Command} in the list.
+   */
+  private LinkedListElement m_lastCommand;
+  /**
+   * Whether or not we are currently adding a command.
+   */
+  private boolean m_adding = false;
+  /**
+   * Whether or not we are currently disabled.
+   */
+  private boolean m_disabled = false;
+  /**
+   * A list of all {@link Command Commands} which need to be added.
+   */
+  private Vector<Command> m_additions = new Vector<>();
+  private NetworkTableEntry m_namesEntry;
+  private NetworkTableEntry m_idsEntry;
+  private NetworkTableEntry m_cancelEntry;
+  /**
+   * A list of all {@link edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler Buttons}. It is
+   * created lazily.
+   */
+  private Vector<ButtonScheduler> m_buttons;
+  private boolean m_runningCommandsChanged;
+
+  /**
+   * Instantiates a {@link Scheduler}.
+   */
+  private Scheduler() {
+    HLUsageReporting.reportScheduler();
+    setName("Scheduler");
+  }
+
+  /**
+   * Adds the command to the {@link Scheduler}. This will not add the {@link Command} immediately,
+   * but will instead wait for the proper time in the {@link Scheduler#run()} loop before doing so.
+   * The command returns immediately and does nothing if given null.
+   *
+   * <p> Adding a {@link Command} to the {@link Scheduler} involves the {@link Scheduler} removing
+   * any {@link Command} which has shared requirements. </p>
+   *
+   * @param command the command to add
+   */
+  public void add(Command command) {
+    if (command != null) {
+      m_additions.addElement(command);
+    }
+  }
+
+  /**
+   * Adds a button to the {@link Scheduler}. The {@link Scheduler} will poll the button during its
+   * {@link Scheduler#run()}.
+   *
+   * @param button the button to add
+   */
+  public void addButton(ButtonScheduler button) {
+    if (m_buttons == null) {
+      m_buttons = new Vector<>();
+    }
+    m_buttons.addElement(button);
+  }
+
+  /**
+   * Adds a command immediately to the {@link Scheduler}. This should only be called in the {@link
+   * Scheduler#run()} loop. Any command with conflicting requirements will be removed, unless it is
+   * uninterruptable. Giving <code>null</code> does nothing.
+   *
+   * @param command the {@link Command} to add
+   */
+  @SuppressWarnings("MethodName")
+  private void _add(Command command) {
+    if (command == null) {
+      return;
+    }
+
+    // Check to make sure no adding during adding
+    if (m_adding) {
+      System.err.println("WARNING: Can not start command from cancel method.  Ignoring:" + command);
+      return;
+    }
+
+    // Only add if not already in
+    if (!m_commandTable.containsKey(command)) {
+
+      // Check that the requirements can be had
+      Enumeration requirements = command.getRequirements();
+      while (requirements.hasMoreElements()) {
+        Subsystem lock = (Subsystem) requirements.nextElement();
+        if (lock.getCurrentCommand() != null && !lock.getCurrentCommand().isInterruptible()) {
+          return;
+        }
+      }
+
+      // Give it the requirements
+      m_adding = true;
+      requirements = command.getRequirements();
+      while (requirements.hasMoreElements()) {
+        Subsystem lock = (Subsystem) requirements.nextElement();
+        if (lock.getCurrentCommand() != null) {
+          lock.getCurrentCommand().cancel();
+          remove(lock.getCurrentCommand());
+        }
+        lock.setCurrentCommand(command);
+      }
+      m_adding = false;
+
+      // Add it to the list
+      LinkedListElement element = new LinkedListElement();
+      element.setData(command);
+      if (m_firstCommand == null) {
+        m_firstCommand = m_lastCommand = element;
+      } else {
+        m_lastCommand.add(element);
+        m_lastCommand = element;
+      }
+      m_commandTable.put(command, element);
+
+      m_runningCommandsChanged = true;
+
+      command.startRunning();
+    }
+  }
+
+  /**
+   * Runs a single iteration of the loop. This method should be called often in order to have a
+   * functioning {@link Command} system. The loop has five stages:
+   *
+   * <ol> <li>Poll the Buttons</li> <li>Execute/Remove the Commands</li> <li>Send values to
+   * SmartDashboard</li> <li>Add Commands</li> <li>Add Defaults</li> </ol>
+   */
+  public void run() {
+
+    m_runningCommandsChanged = false;
+
+    if (m_disabled) {
+      return;
+    } // Don't run when m_disabled
+
+    // Get button input (going backwards preserves button priority)
+    if (m_buttons != null) {
+      for (int i = m_buttons.size() - 1; i >= 0; i--) {
+        m_buttons.elementAt(i).execute();
+      }
+    }
+
+    // Call every subsystem's periodic method
+    Enumeration subsystems = m_subsystems.getElements();
+    while (subsystems.hasMoreElements()) {
+      ((Subsystem) subsystems.nextElement()).periodic();
+    }
+
+    // Loop through the commands
+    LinkedListElement element = m_firstCommand;
+    while (element != null) {
+      Command command = element.getData();
+      element = element.getNext();
+      if (!command.run()) {
+        remove(command);
+        m_runningCommandsChanged = true;
+      }
+    }
+
+    // Add the new things
+    for (int i = 0; i < m_additions.size(); i++) {
+      _add(m_additions.elementAt(i));
+    }
+    m_additions.removeAllElements();
+
+    // Add in the defaults
+    Enumeration locks = m_subsystems.getElements();
+    while (locks.hasMoreElements()) {
+      Subsystem lock = (Subsystem) locks.nextElement();
+      if (lock.getCurrentCommand() == null) {
+        _add(lock.getDefaultCommand());
+      }
+      lock.confirmCommand();
+    }
+  }
+
+  /**
+   * Registers a {@link Subsystem} to this {@link Scheduler}, so that the {@link Scheduler} might
+   * know if a default {@link Command} needs to be run. All {@link Subsystem Subsystems} should call
+   * this.
+   *
+   * @param system the system
+   */
+  void registerSubsystem(Subsystem system) {
+    if (system != null) {
+      m_subsystems.add(system);
+    }
+  }
+
+  /**
+   * Removes the {@link Command} from the {@link Scheduler}.
+   *
+   * @param command the command to remove
+   */
+  void remove(Command command) {
+    if (command == null || !m_commandTable.containsKey(command)) {
+      return;
+    }
+    LinkedListElement element = m_commandTable.get(command);
+    m_commandTable.remove(command);
+
+    if (element.equals(m_lastCommand)) {
+      m_lastCommand = element.getPrevious();
+    }
+    if (element.equals(m_firstCommand)) {
+      m_firstCommand = element.getNext();
+    }
+    element.remove();
+
+    Enumeration requirements = command.getRequirements();
+    while (requirements.hasMoreElements()) {
+      ((Subsystem) requirements.nextElement()).setCurrentCommand(null);
+    }
+
+    command.removed();
+  }
+
+  /**
+   * Removes all commands.
+   */
+  public void removeAll() {
+    // TODO: Confirm that this works with "uninteruptible" commands
+    while (m_firstCommand != null) {
+      remove(m_firstCommand.getData());
+    }
+  }
+
+  /**
+   * Disable the command scheduler.
+   */
+  public void disable() {
+    m_disabled = true;
+  }
+
+  /**
+   * Enable the command scheduler.
+   */
+  public void enable() {
+    m_disabled = false;
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Scheduler");
+    m_namesEntry = builder.getEntry("Names");
+    m_idsEntry = builder.getEntry("Ids");
+    m_cancelEntry = builder.getEntry("Cancel");
+    builder.setUpdateTable(() -> {
+      if (m_namesEntry != null && m_idsEntry != null && m_cancelEntry != null) {
+        // Get the commands to cancel
+        double[] toCancel = m_cancelEntry.getDoubleArray(new double[0]);
+        if (toCancel.length > 0) {
+          for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
+            for (double d : toCancel) {
+              if (e.getData().hashCode() == d) {
+                e.getData().cancel();
+              }
+            }
+          }
+          m_cancelEntry.setDoubleArray(new double[0]);
+        }
+
+        if (m_runningCommandsChanged) {
+          // Set the the running commands
+          int number = 0;
+          for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
+            number++;
+          }
+          String[] commands = new String[number];
+          double[] ids = new double[number];
+          number = 0;
+          for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
+            commands[number] = e.getData().getName();
+            ids[number] = e.getData().hashCode();
+            number++;
+          }
+          m_namesEntry.setStringArray(commands);
+          m_idsEntry.setDoubleArray(ids);
+        }
+      }
+    });
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Set.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Set.java
new file mode 100644
index 0000000..4b05467
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Set.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.wpilibj.command;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+@SuppressWarnings("all")
+/**
+ * A set.
+ */
+class Set {
+  private Vector m_set = new Vector();
+
+  public Set() {
+  }
+
+  public void add(Object o) {
+    if (m_set.contains(o)) {
+      return;
+    }
+    m_set.addElement(o);
+  }
+
+  public void add(Set s) {
+    Enumeration stuff = s.getElements();
+    for (Enumeration e = stuff; e.hasMoreElements(); ) {
+      add(e.nextElement());
+    }
+  }
+
+  public void clear() {
+      m_set.clear();
+  }
+
+  public boolean contains(Object o) {
+    return m_set.contains(o);
+  }
+
+  public Enumeration getElements() {
+    return m_set.elements();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/StartCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/StartCommand.java
new file mode 100644
index 0000000..dcd7200
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/StartCommand.java
@@ -0,0 +1,34 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+/**
+ * A {@link StartCommand} will call the {@link Command#start() start()} method of another command
+ * when it is initialized and will finish immediately.
+ */
+public class StartCommand extends InstantCommand {
+  /**
+   * The command to fork.
+   */
+  private Command m_commandToFork;
+
+  /**
+   * Instantiates a {@link StartCommand} which will start the given command whenever its {@link
+   * Command#initialize() initialize()} is called.
+   *
+   * @param commandToStart the {@link Command} to start
+   */
+  public StartCommand(Command commandToStart) {
+    super("Start(" + commandToStart + ")");
+    m_commandToFork = commandToStart;
+  }
+
+  protected void initialize() {
+    m_commandToFork.start();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Subsystem.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Subsystem.java
new file mode 100644
index 0000000..0af2ca7
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/Subsystem.java
@@ -0,0 +1,220 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import java.util.Enumeration;
+
+import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.wpilibj.SendableBase;
+import edu.wpi.first.wpilibj.livewindow.LiveWindow;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * This class defines a major component of the robot.
+ *
+ * <p> A good example of a subsystem is the driveline, or a claw if the robot has one. </p>
+ *
+ * <p> All motors should be a part of a subsystem. For instance, all the wheel motors should be a
+ * part of some kind of "Driveline" subsystem. </p>
+ *
+ * <p> Subsystems are used within the command system as requirements for {@link Command}. Only one
+ * command which requires a subsystem can run at a time. Also, subsystems can have default commands
+ * which are started if there is no command running which requires this subsystem. </p>
+ *
+ * @see Command
+ */
+public abstract class Subsystem extends SendableBase implements Sendable {
+  /**
+   * Whether or not getDefaultCommand() was called.
+   */
+  private boolean m_initializedDefaultCommand = false;
+  /**
+   * The current command.
+   */
+  private Command m_currentCommand;
+  private boolean m_currentCommandChanged;
+
+  /**
+   * The default command.
+   */
+  private Command m_defaultCommand;
+
+  /**
+   * Creates a subsystem with the given name.
+   *
+   * @param name the name of the subsystem
+   */
+  public Subsystem(String name) {
+    setName(name, name);
+    Scheduler.getInstance().registerSubsystem(this);
+  }
+
+  /**
+   * Creates a subsystem. This will set the name to the name of the class.
+   */
+  public Subsystem() {
+    String name = getClass().getName();
+    name = name.substring(name.lastIndexOf('.') + 1);
+    setName(name, name);
+    Scheduler.getInstance().registerSubsystem(this);
+    m_currentCommandChanged = true;
+  }
+
+  /**
+   * Initialize the default command for a subsystem By default subsystems have no default command,
+   * but if they do, the default command is set with this method. It is called on all Subsystems by
+   * CommandBase in the users program after all the Subsystems are created.
+   */
+  protected abstract void initDefaultCommand();
+
+  /**
+   * When the run method of the scheduler is called this method will be called.
+   */
+  public void periodic() {
+    // Override me!
+  }
+
+  /**
+   * Sets the default command. If this is not called or is called with null, then there will be no
+   * default command for the subsystem.
+   *
+   * <p> <b>WARNING:</b> This should <b>NOT</b> be called in a constructor if the subsystem is a
+   * singleton. </p>
+   *
+   * @param command the default command (or null if there should be none)
+   * @throws IllegalUseOfCommandException if the command does not require the subsystem
+   */
+  public void setDefaultCommand(Command command) {
+    if (command == null) {
+      m_defaultCommand = null;
+    } else {
+      boolean found = false;
+      Enumeration requirements = command.getRequirements();
+      while (requirements.hasMoreElements()) {
+        if (requirements.nextElement().equals(this)) {
+          found = true;
+          // } else {
+          // throw new
+          // IllegalUseOfCommandException("A default command cannot require multiple subsystems");
+        }
+      }
+      if (!found) {
+        throw new IllegalUseOfCommandException("A default command must require the subsystem");
+      }
+      m_defaultCommand = command;
+    }
+  }
+
+  /**
+   * Returns the default command (or null if there is none).
+   *
+   * @return the default command
+   */
+  public Command getDefaultCommand() {
+    if (!m_initializedDefaultCommand) {
+      m_initializedDefaultCommand = true;
+      initDefaultCommand();
+    }
+    return m_defaultCommand;
+  }
+
+  /**
+   * Returns the default command name, or empty string is there is none.
+   *
+   * @return the default command name
+   */
+  public String getDefaultCommandName() {
+    Command defaultCommand = getDefaultCommand();
+    if (defaultCommand != null) {
+      return defaultCommand.getName();
+    } else {
+      return "";
+    }
+  }
+
+  /**
+   * Sets the current command.
+   *
+   * @param command the new current command
+   */
+  void setCurrentCommand(Command command) {
+    m_currentCommand = command;
+    m_currentCommandChanged = true;
+  }
+
+  /**
+   * Call this to alert Subsystem that the current command is actually the command. Sometimes, the
+   * {@link Subsystem} is told that it has no command while the {@link Scheduler} is going through
+   * the loop, only to be soon after given a new one. This will avoid that situation.
+   */
+  void confirmCommand() {
+    if (m_currentCommandChanged) {
+      m_currentCommandChanged = false;
+    }
+  }
+
+  /**
+   * Returns the command which currently claims this subsystem.
+   *
+   * @return the command which currently claims this subsystem
+   */
+  public Command getCurrentCommand() {
+    return m_currentCommand;
+  }
+
+  /**
+   * Returns the current command name, or empty string if no current command.
+   *
+   * @return the current command name
+   */
+  public String getCurrentCommandName() {
+    Command currentCommand = getCurrentCommand();
+    if (currentCommand != null) {
+      return currentCommand.getName();
+    } else {
+      return "";
+    }
+  }
+
+  /**
+   * Associate a {@link Sendable} with this Subsystem.
+   * Also update the child's name.
+   *
+   * @param name name to give child
+   * @param child sendable
+   */
+  public void addChild(String name, Sendable child) {
+    child.setName(getSubsystem(), name);
+    LiveWindow.add(child);
+  }
+
+  /**
+   * Associate a {@link Sendable} with this Subsystem.
+   *
+   * @param child sendable
+   */
+  public void addChild(Sendable child) {
+    child.setSubsystem(getSubsystem());
+    LiveWindow.add(child);
+  }
+
+  @Override
+  public String toString() {
+    return getSubsystem();
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("Subsystem");
+
+    builder.addBooleanProperty(".hasDefault", () -> m_defaultCommand != null, null);
+    builder.addStringProperty(".default", this::getDefaultCommandName, null);
+    builder.addBooleanProperty(".hasCommand", () -> m_currentCommand != null, null);
+    builder.addStringProperty(".command", this::getCurrentCommandName, null);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/TimedCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/TimedCommand.java
new file mode 100644
index 0000000..abd3b91
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/TimedCommand.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.command;
+
+/**
+ * A {@link TimedCommand} will wait for a timeout before finishing.
+ * {@link TimedCommand} is used to execute a command for a given amount of time.
+ */
+public class TimedCommand extends Command {
+  /**
+   * Instantiates a TimedCommand with the given name and timeout.
+   *
+   * @param name the name of the command
+   * @param timeout the time the command takes to run (seconds)
+   */
+  public TimedCommand(String name, double timeout) {
+    super(name, timeout);
+  }
+
+  /**
+   * Instantiates a TimedCommand with the given timeout.
+   *
+   * @param timeout the time the command takes to run (seconds)
+   */
+  public TimedCommand(double timeout) {
+    super(timeout);
+  }
+
+  /**
+  * Ends command when timed out.
+  */
+  protected boolean isFinished() {
+    return isTimedOut();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitCommand.java
new file mode 100644
index 0000000..1af7c1f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitCommand.java
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+/**
+ * A {@link WaitCommand} will wait for a certain amount of time before finishing. It is useful if
+ * you want a {@link CommandGroup} to pause for a moment.
+ *
+ * @see CommandGroup
+ */
+public class WaitCommand extends TimedCommand {
+  /**
+   * Instantiates a {@link WaitCommand} with the given timeout.
+   *
+   * @param timeout the time the command takes to run (seconds)
+   */
+  public WaitCommand(double timeout) {
+    this("Wait(" + timeout + ")", timeout);
+  }
+
+  /**
+   * Instantiates a {@link WaitCommand} with the given timeout.
+   *
+   * @param name    the name of the command
+   * @param timeout the time the command takes to run (seconds)
+   */
+  public WaitCommand(String name, double timeout) {
+    super(name, timeout);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitForChildren.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitForChildren.java
new file mode 100644
index 0000000..3fc3da2
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitForChildren.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.wpilibj.command;
+
+/**
+ * This command will only finish if whatever {@link CommandGroup} it is in has no active children.
+ * If it is not a part of a {@link CommandGroup}, then it will finish immediately. If it is itself
+ * an active child, then the {@link CommandGroup} will never end.
+ *
+ * <p>This class is useful for the situation where you want to allow anything running in parallel
+ * to finish, before continuing in the main {@link CommandGroup} sequence.
+ */
+public class WaitForChildren extends Command {
+  protected boolean isFinished() {
+    return getGroup() == null || getGroup().m_children.isEmpty();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitUntilCommand.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitUntilCommand.java
new file mode 100644
index 0000000..508b0e0
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/command/WaitUntilCommand.java
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import edu.wpi.first.wpilibj.Timer;
+
+/**
+ * WaitUntilCommand - waits until an absolute game time. This will wait until the game clock reaches
+ * some value, then continue to the next command.
+ */
+public class WaitUntilCommand extends Command {
+  private double m_time;
+
+  public WaitUntilCommand(double time) {
+    super("WaitUntil(" + time + ")");
+    m_time = time;
+  }
+
+  /**
+   * Check if we've reached the actual finish time.
+   */
+  public boolean isFinished() {
+    return Timer.getMatchTime() >= m_time;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/communication/NIRioStatus.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/communication/NIRioStatus.java
new file mode 100644
index 0000000..071c1ae
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/communication/NIRioStatus.java
@@ -0,0 +1,19 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.communication;
+
+public class NIRioStatus {
+  // TODO: Should this file be auto-generated?
+  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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java
new file mode 100644
index 0000000..74ff519
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java
@@ -0,0 +1,369 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.drive;
+
+import edu.wpi.first.wpilibj.SpeedController;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * A class for driving differential drive/skid-steer drive platforms such as the Kit of Parts drive
+ * base, "tank drive", or West Coast Drive.
+ *
+ * <p>These drive bases typically have drop-center / skid-steer with two or more wheels per side
+ * (e.g., 6WD or 8WD). This class takes a SpeedController per side. For four and
+ * six motor drivetrains, construct and pass in {@link edu.wpi.first.wpilibj.SpeedControllerGroup}
+ * instances as follows.
+ *
+ * <p>Four motor drivetrain:
+ * <pre><code>
+ * public class Robot {
+ *   Spark m_frontLeft = new Spark(1);
+ *   Spark m_rearLeft = new Spark(2);
+ *   SpeedControllerGroup m_left = new SpeedControllerGroup(m_frontLeft, m_rearLeft);
+ *
+ *   Spark m_frontRight = new Spark(3);
+ *   Spark m_rearRight = new Spark(4);
+ *   SpeedControllerGroup m_right = new SpeedControllerGroup(m_frontRight, m_rearRight);
+ *
+ *   DifferentialDrive m_drive = new DifferentialDrive(m_left, m_right);
+ * }
+ * </code></pre>
+ *
+ * <p>Six motor drivetrain:
+ * <pre><code>
+ * public class Robot {
+ *   Spark m_frontLeft = new Spark(1);
+ *   Spark m_midLeft = new Spark(2);
+ *   Spark m_rearLeft = new Spark(3);
+ *   SpeedControllerGroup m_left = new SpeedControllerGroup(m_frontLeft, m_midLeft, m_rearLeft);
+ *
+ *   Spark m_frontRight = new Spark(4);
+ *   Spark m_midRight = new Spark(5);
+ *   Spark m_rearRight = new Spark(6);
+ *   SpeedControllerGroup m_right = new SpeedControllerGroup(m_frontRight, m_midRight, m_rearRight);
+ *
+ *   DifferentialDrive m_drive = new DifferentialDrive(m_left, m_right);
+ * }
+ * </code></pre>
+ *
+ * <p>A differential drive robot has left and right wheels separated by an arbitrary width.
+ *
+ * <p>Drive base diagram:
+ * <pre>
+ * |_______|
+ * | |   | |
+ *   |   |
+ * |_|___|_|
+ * |       |
+ * </pre>
+ *
+ * <p>Each drive() function provides different inverse kinematic relations for a differential drive
+ * robot. Motor outputs for the right side are negated, so motor direction inversion by the user is
+ * usually unnecessary.
+ *
+ * <p>This library uses the NED axes convention (North-East-Down as external reference in the world
+ * frame): http://www.nuclearprojects.com/ins/images/axis_big.png.
+ *
+ * <p>The positive X axis points ahead, the positive Y axis points right, and the positive Z axis
+ * points down. Rotations follow the right-hand rule, so clockwise rotation around the Z axis is
+ * positive.
+ *
+ * <p>Inputs smaller then {@value edu.wpi.first.wpilibj.drive.RobotDriveBase#kDefaultDeadband} will
+ * be set to 0, and larger values will be scaled so that the full range is still used. This
+ * deadband value can be changed with {@link #setDeadband}.
+ *
+ * <p>RobotDrive porting guide:
+ * <br>{@link #tankDrive(double, double)} is equivalent to
+ * {@link edu.wpi.first.wpilibj.RobotDrive#tankDrive(double, double)} if a deadband of 0 is used.
+ * <br>{@link #arcadeDrive(double, double)} is equivalent to
+ * {@link edu.wpi.first.wpilibj.RobotDrive#arcadeDrive(double, double)} if a deadband of 0 is used
+ * and the the rotation input is inverted eg arcadeDrive(y, -rotation)
+ * <br>{@link #curvatureDrive(double, double, boolean)} is similar in concept to
+ * {@link edu.wpi.first.wpilibj.RobotDrive#drive(double, double)} with the addition of a quick turn
+ * mode. However, it is not designed to give exactly the same response.
+ */
+public class DifferentialDrive extends RobotDriveBase {
+  public static final double kDefaultQuickStopThreshold = 0.2;
+  public static final double kDefaultQuickStopAlpha = 0.1;
+
+  private static int instances = 0;
+
+  private SpeedController m_leftMotor;
+  private SpeedController m_rightMotor;
+
+  private double m_quickStopThreshold = kDefaultQuickStopThreshold;
+  private double m_quickStopAlpha = kDefaultQuickStopAlpha;
+  private double m_quickStopAccumulator = 0.0;
+  private boolean m_reported = false;
+
+  /**
+   * Construct a DifferentialDrive.
+   *
+   * <p>To pass multiple motors per side, use a {@link SpeedControllerGroup}. If a motor needs to be
+   * inverted, do so before passing it in.
+   */
+  public DifferentialDrive(SpeedController leftMotor, SpeedController rightMotor) {
+    m_leftMotor = leftMotor;
+    m_rightMotor = rightMotor;
+    addChild(m_leftMotor);
+    addChild(m_rightMotor);
+    instances++;
+    setName("DifferentialDrive", instances);
+  }
+
+  /**
+   * Arcade drive method for differential drive platform.
+   * The calculated values will be squared to decrease sensitivity at low speeds.
+   *
+   * @param xSpeed    The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                  positive.
+   */
+  @SuppressWarnings("ParameterName")
+  public void arcadeDrive(double xSpeed, double zRotation) {
+    arcadeDrive(xSpeed, zRotation, true);
+  }
+
+  /**
+   * Arcade drive method for differential drive platform.
+   *
+   * @param xSpeed        The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation     The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                      positive.
+   * @param squaredInputs If set, decreases the input sensitivity at low speeds.
+   */
+  @SuppressWarnings("ParameterName")
+  public void arcadeDrive(double xSpeed, double zRotation, boolean squaredInputs) {
+    if (!m_reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, 2, tInstances.kRobotDrive_ArcadeStandard);
+      m_reported = true;
+    }
+
+    xSpeed = limit(xSpeed);
+    xSpeed = applyDeadband(xSpeed, m_deadband);
+
+    zRotation = limit(zRotation);
+    zRotation = applyDeadband(zRotation, m_deadband);
+
+    // Square the inputs (while preserving the sign) to increase fine control
+    // while permitting full power.
+    if (squaredInputs) {
+      xSpeed = Math.copySign(xSpeed * xSpeed, xSpeed);
+      zRotation = Math.copySign(zRotation * zRotation, zRotation);
+    }
+
+    double leftMotorOutput;
+    double rightMotorOutput;
+
+    double maxInput = Math.copySign(Math.max(Math.abs(xSpeed), Math.abs(zRotation)), xSpeed);
+
+    if (xSpeed >= 0.0) {
+      // First quadrant, else second quadrant
+      if (zRotation >= 0.0) {
+        leftMotorOutput = maxInput;
+        rightMotorOutput = xSpeed - zRotation;
+      } else {
+        leftMotorOutput = xSpeed + zRotation;
+        rightMotorOutput = maxInput;
+      }
+    } else {
+      // Third quadrant, else fourth quadrant
+      if (zRotation >= 0.0) {
+        leftMotorOutput = xSpeed + zRotation;
+        rightMotorOutput = maxInput;
+      } else {
+        leftMotorOutput = maxInput;
+        rightMotorOutput = xSpeed - zRotation;
+      }
+    }
+
+    m_leftMotor.set(limit(leftMotorOutput) * m_maxOutput);
+    m_rightMotor.set(-limit(rightMotorOutput) * m_maxOutput);
+
+    m_safetyHelper.feed();
+  }
+
+  /**
+   * Curvature drive method for differential drive platform.
+   *
+   * <p>The rotation argument controls the curvature of the robot's path rather than its rate of
+   * heading change. This makes the robot more controllable at high speeds. Also handles the
+   * robot's quick turn functionality - "quick turn" overrides constant-curvature turning for
+   * turn-in-place maneuvers.
+   *
+   * @param xSpeed      The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation   The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                    positive.
+   * @param isQuickTurn If set, overrides constant-curvature turning for
+   *                    turn-in-place maneuvers.
+   */
+  @SuppressWarnings("ParameterName")
+  public void curvatureDrive(double xSpeed, double zRotation, boolean isQuickTurn) {
+    if (!m_reported) {
+      // HAL.report(tResourceType.kResourceType_RobotDrive, 2, tInstances.kRobotDrive_Curvature);
+      m_reported = true;
+    }
+
+    xSpeed = limit(xSpeed);
+    xSpeed = applyDeadband(xSpeed, m_deadband);
+
+    zRotation = limit(zRotation);
+    zRotation = applyDeadband(zRotation, m_deadband);
+
+    double angularPower;
+    boolean overPower;
+
+    if (isQuickTurn) {
+      if (Math.abs(xSpeed) < m_quickStopThreshold) {
+        m_quickStopAccumulator = (1 - m_quickStopAlpha) * m_quickStopAccumulator
+            + m_quickStopAlpha * limit(zRotation) * 2;
+      }
+      overPower = true;
+      angularPower = zRotation;
+    } else {
+      overPower = false;
+      angularPower = Math.abs(xSpeed) * zRotation - m_quickStopAccumulator;
+
+      if (m_quickStopAccumulator > 1) {
+        m_quickStopAccumulator -= 1;
+      } else if (m_quickStopAccumulator < -1) {
+        m_quickStopAccumulator += 1;
+      } else {
+        m_quickStopAccumulator = 0.0;
+      }
+    }
+
+    double leftMotorOutput = xSpeed + angularPower;
+    double rightMotorOutput = xSpeed - angularPower;
+
+    // If rotation is overpowered, reduce both outputs to within acceptable range
+    if (overPower) {
+      if (leftMotorOutput > 1.0) {
+        rightMotorOutput -= leftMotorOutput - 1.0;
+        leftMotorOutput = 1.0;
+      } else if (rightMotorOutput > 1.0) {
+        leftMotorOutput -= rightMotorOutput - 1.0;
+        rightMotorOutput = 1.0;
+      } else if (leftMotorOutput < -1.0) {
+        rightMotorOutput -= leftMotorOutput + 1.0;
+        leftMotorOutput = -1.0;
+      } else if (rightMotorOutput < -1.0) {
+        leftMotorOutput -= rightMotorOutput + 1.0;
+        rightMotorOutput = -1.0;
+      }
+    }
+
+    m_leftMotor.set(leftMotorOutput * m_maxOutput);
+    m_rightMotor.set(-rightMotorOutput * m_maxOutput);
+
+    m_safetyHelper.feed();
+  }
+
+  /**
+   * Tank drive method for differential drive platform.
+   * The calculated values will be squared to decrease sensitivity at low speeds.
+   *
+   * @param leftSpeed  The robot's left side speed along the X axis [-1.0..1.0]. Forward is
+   *                   positive.
+   * @param rightSpeed The robot's right side speed along the X axis [-1.0..1.0]. Forward is
+   *                   positive.
+   */
+  public void tankDrive(double leftSpeed, double rightSpeed) {
+    tankDrive(leftSpeed, rightSpeed, true);
+  }
+
+  /**
+   * Tank drive method for differential drive platform.
+   *
+   * @param leftSpeed     The robot left side's speed along the X axis [-1.0..1.0]. Forward is
+   *                      positive.
+   * @param rightSpeed    The robot right side's speed along the X axis [-1.0..1.0]. Forward is
+   *                      positive.
+   * @param squaredInputs If set, decreases the input sensitivity at low speeds.
+   */
+  public void tankDrive(double leftSpeed, double rightSpeed, boolean squaredInputs) {
+    if (!m_reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, 2, tInstances.kRobotDrive_Tank);
+      m_reported = true;
+    }
+
+    leftSpeed = limit(leftSpeed);
+    leftSpeed = applyDeadband(leftSpeed, m_deadband);
+
+    rightSpeed = limit(rightSpeed);
+    rightSpeed = applyDeadband(rightSpeed, m_deadband);
+
+    // Square the inputs (while preserving the sign) to increase fine control
+    // while permitting full power.
+    if (squaredInputs) {
+      leftSpeed = Math.copySign(leftSpeed * leftSpeed, leftSpeed);
+      rightSpeed = Math.copySign(rightSpeed * rightSpeed, rightSpeed);
+    }
+
+    m_leftMotor.set(leftSpeed * m_maxOutput);
+    m_rightMotor.set(-rightSpeed * m_maxOutput);
+
+    m_safetyHelper.feed();
+  }
+
+  /**
+   * Sets the QuickStop speed threshold in curvature drive.
+   *
+   * <p>QuickStop compensates for the robot's moment of inertia when stopping after a QuickTurn.
+   *
+   * <p>While QuickTurn is enabled, the QuickStop accumulator takes on the rotation rate value
+   * outputted by the low-pass filter when the robot's speed along the X axis is below the
+   * threshold. When QuickTurn is disabled, the accumulator's value is applied against the computed
+   * angular power request to slow the robot's rotation.
+   *
+   * @param threshold X speed below which quick stop accumulator will receive rotation rate values
+   *                  [0..1.0].
+   */
+  public void setQuickStopThreshold(double threshold) {
+    m_quickStopThreshold = threshold;
+  }
+
+  /**
+   * Sets the low-pass filter gain for QuickStop in curvature drive.
+   *
+   * <p>The low-pass filter filters incoming rotation rate commands to smooth out high frequency
+   * changes.
+   *
+   * @param alpha Low-pass filter gain [0.0..2.0]. Smaller values result in slower output changes.
+   *              Values between 1.0 and 2.0 result in output oscillation. Values below 0.0 and
+   *              above 2.0 are unstable.
+   */
+  public void setQuickStopAlpha(double alpha) {
+    m_quickStopAlpha = alpha;
+  }
+
+  @Override
+  public void stopMotor() {
+    m_leftMotor.stopMotor();
+    m_rightMotor.stopMotor();
+    m_safetyHelper.feed();
+  }
+
+  @Override
+  public String getDescription() {
+    return "DifferentialDrive";
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("DifferentialDrive");
+    builder.addDoubleProperty("Left Motor Speed", m_leftMotor::get, m_leftMotor::set);
+    builder.addDoubleProperty(
+        "Right Motor Speed",
+        () -> -m_rightMotor.get(),
+        x -> m_rightMotor.set(-x));
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java
new file mode 100644
index 0000000..558e0e7
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java
@@ -0,0 +1,211 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.drive;
+
+import edu.wpi.first.wpilibj.SpeedController;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+// import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+// import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+// import edu.wpi.first.wpilibj.hal.HAL;
+
+/**
+ * A class for driving Killough drive platforms.
+ *
+ * <p>Killough drives are triangular with one omni wheel on each corner.
+ *
+ * <p>Drive base diagram:
+ * <pre>
+ *  /_____\
+ * / \   / \
+ *    \ /
+ *    ---
+ * </pre>
+ *
+ * <p>Each drive() function provides different inverse kinematic relations for a Killough drive. The
+ * default wheel vectors are parallel to their respective opposite sides, but can be overridden. See
+ * the constructor for more information.
+ *
+ * <p>This library uses the NED axes convention (North-East-Down as external reference in the world
+ * frame): http://www.nuclearprojects.com/ins/images/axis_big.png.
+ *
+ * <p>The positive X axis points ahead, the positive Y axis points right, and the positive Z axis
+ * points down. Rotations follow the right-hand rule, so clockwise rotation around the Z axis is
+ * positive.
+ */
+public class KilloughDrive extends RobotDriveBase {
+  public static final double kDefaultLeftMotorAngle = 60.0;
+  public static final double kDefaultRightMotorAngle = 120.0;
+  public static final double kDefaultBackMotorAngle = 270.0;
+
+  private static int instances = 0;
+
+  private SpeedController m_leftMotor;
+  private SpeedController m_rightMotor;
+  private SpeedController m_backMotor;
+
+  private Vector2d m_leftVec;
+  private Vector2d m_rightVec;
+  private Vector2d m_backVec;
+
+  private boolean m_reported = false;
+
+  /**
+   * Construct a Killough drive with the given motors and default motor angles.
+   *
+   * <p>The default motor angles make the wheels on each corner parallel to their respective
+   * opposite sides.
+   *
+   * <p>If a motor needs to be inverted, do so before passing it in.
+   *
+   * @param leftMotor  The motor on the left corner.
+   * @param rightMotor The motor on the right corner.
+   * @param backMotor  The motor on the back corner.
+   */
+  public KilloughDrive(SpeedController leftMotor, SpeedController rightMotor,
+                       SpeedController backMotor) {
+    this(leftMotor, rightMotor, backMotor, kDefaultLeftMotorAngle, kDefaultRightMotorAngle,
+        kDefaultBackMotorAngle);
+  }
+
+  /**
+   * Construct a Killough drive with the given motors.
+   *
+   * <p>Angles are measured in degrees clockwise from the positive X axis.
+   *
+   * @param leftMotor       The motor on the left corner.
+   * @param rightMotor      The motor on the right corner.
+   * @param backMotor       The motor on the back corner.
+   * @param leftMotorAngle  The angle of the left wheel's forward direction of travel.
+   * @param rightMotorAngle The angle of the right wheel's forward direction of travel.
+   * @param backMotorAngle  The angle of the back wheel's forward direction of travel.
+   */
+  public KilloughDrive(SpeedController leftMotor, SpeedController rightMotor,
+                       SpeedController backMotor, double leftMotorAngle, double rightMotorAngle,
+                       double backMotorAngle) {
+    m_leftMotor = leftMotor;
+    m_rightMotor = rightMotor;
+    m_backMotor = backMotor;
+    m_leftVec = new Vector2d(Math.cos(leftMotorAngle * (Math.PI / 180.0)),
+                             Math.sin(leftMotorAngle * (Math.PI / 180.0)));
+    m_rightVec = new Vector2d(Math.cos(rightMotorAngle * (Math.PI / 180.0)),
+                              Math.sin(rightMotorAngle * (Math.PI / 180.0)));
+    m_backVec = new Vector2d(Math.cos(backMotorAngle * (Math.PI / 180.0)),
+                             Math.sin(backMotorAngle * (Math.PI / 180.0)));
+    addChild(m_leftMotor);
+    addChild(m_rightMotor);
+    addChild(m_backMotor);
+    instances++;
+    setName("KilloughDrive", instances);
+  }
+
+  /**
+   * Drive method for Killough platform.
+   *
+   * <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
+   * from its angle or rotation rate.
+   *
+   * @param ySpeed    The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+   * @param xSpeed    The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                  positive.
+   */
+  @SuppressWarnings("ParameterName")
+  public void driveCartesian(double ySpeed, double xSpeed, double zRotation) {
+    driveCartesian(ySpeed, xSpeed, zRotation, 0.0);
+  }
+
+  /**
+   * Drive method for Killough platform.
+   *
+   * <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
+   * from its angle or rotation rate.
+   *
+   * @param ySpeed    The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+   * @param xSpeed    The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                  positive.
+   * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use
+   *                  this to implement field-oriented controls.
+   */
+  @SuppressWarnings("ParameterName")
+  public void driveCartesian(double ySpeed, double xSpeed, double zRotation,
+                             double gyroAngle) {
+    if (!m_reported) {
+      // HAL.report(tResourceType.kResourceType_RobotDrive, 3,
+      //            tInstances.kRobotDrive_KilloughCartesian);
+      m_reported = true;
+    }
+
+    ySpeed = limit(ySpeed);
+    ySpeed = applyDeadband(ySpeed, m_deadband);
+
+    xSpeed = limit(xSpeed);
+    xSpeed = applyDeadband(xSpeed, m_deadband);
+
+    // Compensate for gyro angle.
+    Vector2d input = new Vector2d(ySpeed, xSpeed);
+    input.rotate(-gyroAngle);
+
+    double[] wheelSpeeds = new double[3];
+    wheelSpeeds[MotorType.kLeft.value] = input.scalarProject(m_leftVec) + zRotation;
+    wheelSpeeds[MotorType.kRight.value] = input.scalarProject(m_rightVec) + zRotation;
+    wheelSpeeds[MotorType.kBack.value] = input.scalarProject(m_backVec) + zRotation;
+
+    normalize(wheelSpeeds);
+
+    m_leftMotor.set(wheelSpeeds[MotorType.kLeft.value] * m_maxOutput);
+    m_rightMotor.set(wheelSpeeds[MotorType.kRight.value] * m_maxOutput);
+    m_backMotor.set(wheelSpeeds[MotorType.kBack.value] * m_maxOutput);
+
+    m_safetyHelper.feed();
+  }
+
+  /**
+   * Drive method for Killough platform.
+   *
+   * <p>Angles are measured counter-clockwise from straight ahead. The speed at which the robot
+   * drives (translation) is independent from its angle or rotation rate.
+   *
+   * @param magnitude The robot's speed at a given angle [-1.0..1.0]. Forward is positive.
+   * @param angle     The angle around the Z axis at which the robot drives in degrees [-180..180].
+   * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                  positive.
+   */
+  @SuppressWarnings("ParameterName")
+  public void drivePolar(double magnitude, double angle, double zRotation) {
+    if (!m_reported) {
+      // HAL.report(tResourceType.kResourceType_RobotDrive, 3,
+      //            tInstances.kRobotDrive_KilloughPolar);
+      m_reported = true;
+    }
+
+    driveCartesian(magnitude * Math.sin(angle * (Math.PI / 180.0)),
+                   magnitude * Math.cos(angle * (Math.PI / 180.0)), zRotation, 0.0);
+  }
+
+  @Override
+  public void stopMotor() {
+    m_leftMotor.stopMotor();
+    m_rightMotor.stopMotor();
+    m_backMotor.stopMotor();
+    m_safetyHelper.feed();
+  }
+
+  @Override
+  public String getDescription() {
+    return "KilloughDrive";
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("KilloughDrive");
+    builder.addDoubleProperty("Left Motor Speed", m_leftMotor::get, m_leftMotor::set);
+    builder.addDoubleProperty("Right Motor Speed", m_rightMotor::get, m_rightMotor::set);
+    builder.addDoubleProperty("Back Motor Speed", m_backMotor::get, m_backMotor::set);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java
new file mode 100644
index 0000000..087a51c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java
@@ -0,0 +1,199 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.drive;
+
+import edu.wpi.first.wpilibj.SpeedController;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+
+/**
+ * A class for driving Mecanum drive platforms.
+ *
+ * <p>Mecanum drives are rectangular with one wheel on each corner. Each wheel has rollers toed in
+ * 45 degrees toward the front or back. When looking at the wheels from the top, the roller axles
+ * should form an X across the robot. Each drive() function provides different inverse kinematic
+ * relations for a Mecanum drive robot.
+ *
+ * <p>Drive base diagram:
+ * <pre>
+ * \\_______/
+ * \\ |   | /
+ *   |   |
+ * /_|___|_\\
+ * /       \\
+ * </pre>
+ *
+ * <p>Each drive() function provides different inverse kinematic relations for a Mecanum drive
+ * robot. Motor outputs for the right side are negated, so motor direction inversion by the user is
+ * usually unnecessary.
+ *
+ * <p>This library uses the NED axes convention (North-East-Down as external reference in the world
+ * frame): http://www.nuclearprojects.com/ins/images/axis_big.png.
+ *
+ * <p>The positive X axis points ahead, the positive Y axis points right, and the positive Z axis
+ * points down. Rotations follow the right-hand rule, so clockwise rotation around the Z axis is
+ * positive.
+ *
+ * <p>Inputs smaller then {@value edu.wpi.first.wpilibj.drive.RobotDriveBase#kDefaultDeadband} will
+ * be set to 0, and larger values will be scaled so that the full range is still used. This
+ * deadband value can be changed with {@link #setDeadband}.
+ *
+ * <p>RobotDrive porting guide:
+ * <br>In MecanumDrive, the right side speed controllers are automatically inverted, while in
+ * RobotDrive, no speed controllers are automatically inverted.
+ * <br>{@link #driveCartesian(double, double, double, double)} is equivalent to
+ * {@link edu.wpi.first.wpilibj.RobotDrive#mecanumDrive_Cartesian(double, double, double, double)}
+ * if a deadband of 0 is used, and the ySpeed and gyroAngle values are inverted compared to
+ * RobotDrive (eg driveCartesian(xSpeed, -ySpeed, zRotation, -gyroAngle).
+ * <br>{@link #drivePolar(double, double, double)} is equivalent to
+ * {@link edu.wpi.first.wpilibj.RobotDrive#mecanumDrive_Polar(double, double, double)} if a
+ * deadband of 0 is used.
+ */
+public class MecanumDrive extends RobotDriveBase {
+  private static int instances = 0;
+
+  private SpeedController m_frontLeftMotor;
+  private SpeedController m_rearLeftMotor;
+  private SpeedController m_frontRightMotor;
+  private SpeedController m_rearRightMotor;
+
+  private boolean m_reported = false;
+
+  /**
+   * Construct a MecanumDrive.
+   *
+   * <p>If a motor needs to be inverted, do so before passing it in.
+   */
+  public MecanumDrive(SpeedController frontLeftMotor, SpeedController rearLeftMotor,
+                      SpeedController frontRightMotor, SpeedController rearRightMotor) {
+    m_frontLeftMotor = frontLeftMotor;
+    m_rearLeftMotor = rearLeftMotor;
+    m_frontRightMotor = frontRightMotor;
+    m_rearRightMotor = rearRightMotor;
+    addChild(m_frontLeftMotor);
+    addChild(m_rearLeftMotor);
+    addChild(m_frontRightMotor);
+    addChild(m_rearRightMotor);
+    instances++;
+    setName("MecanumDrive", instances);
+  }
+
+  /**
+   * Drive method for Mecanum platform.
+   *
+   * <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
+   * from its angle or rotation rate.
+   *
+   * @param ySpeed    The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+   * @param xSpeed    The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                  positive.
+   */
+  @SuppressWarnings("ParameterName")
+  public void driveCartesian(double ySpeed, double xSpeed, double zRotation) {
+    driveCartesian(ySpeed, xSpeed, zRotation, 0.0);
+  }
+
+  /**
+   * Drive method for Mecanum platform.
+   *
+   * <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
+   * from its angle or rotation rate.
+   *
+   * @param ySpeed    The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+   * @param xSpeed    The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                  positive.
+   * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use
+   *                  this to implement field-oriented controls.
+   */
+  @SuppressWarnings("ParameterName")
+  public void driveCartesian(double ySpeed, double xSpeed, double zRotation, double gyroAngle) {
+    if (!m_reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, 4,
+                 tInstances.kRobotDrive_MecanumCartesian);
+      m_reported = true;
+    }
+
+    ySpeed = limit(ySpeed);
+    ySpeed = applyDeadband(ySpeed, m_deadband);
+
+    xSpeed = limit(xSpeed);
+    xSpeed = applyDeadband(xSpeed, m_deadband);
+
+    // Compensate for gyro angle.
+    Vector2d input = new Vector2d(ySpeed, xSpeed);
+    input.rotate(-gyroAngle);
+
+    double[] wheelSpeeds = new double[4];
+    wheelSpeeds[MotorType.kFrontLeft.value] = input.x + input.y + zRotation;
+    wheelSpeeds[MotorType.kFrontRight.value] = input.x - input.y + zRotation;
+    wheelSpeeds[MotorType.kRearLeft.value] = -input.x + input.y + zRotation;
+    wheelSpeeds[MotorType.kRearRight.value] = -input.x - input.y + zRotation;
+
+    normalize(wheelSpeeds);
+
+    m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft.value] * m_maxOutput);
+    m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight.value] * m_maxOutput);
+    m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft.value] * m_maxOutput);
+    m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight.value] * m_maxOutput);
+
+    m_safetyHelper.feed();
+  }
+
+  /**
+   * Drive method for Mecanum platform.
+   *
+   * <p>Angles are measured counter-clockwise from straight ahead. The speed at which the robot
+   * drives (translation) is independent from its angle or rotation rate.
+   *
+   * @param magnitude The robot's speed at a given angle [-1.0..1.0]. Forward is positive.
+   * @param angle     The angle around the Z axis at which the robot drives in degrees [-180..180].
+   * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+   *                  positive.
+   */
+  @SuppressWarnings("ParameterName")
+  public void drivePolar(double magnitude, double angle, double zRotation) {
+    if (!m_reported) {
+      HAL.report(tResourceType.kResourceType_RobotDrive, 4, tInstances.kRobotDrive_MecanumPolar);
+      m_reported = true;
+    }
+
+    driveCartesian(magnitude * Math.sin(angle * (Math.PI / 180.0)),
+                   magnitude * Math.cos(angle * (Math.PI / 180.0)), zRotation, 0.0);
+  }
+
+  @Override
+  public void stopMotor() {
+    m_frontLeftMotor.stopMotor();
+    m_frontRightMotor.stopMotor();
+    m_rearLeftMotor.stopMotor();
+    m_rearRightMotor.stopMotor();
+    m_safetyHelper.feed();
+  }
+
+  @Override
+  public String getDescription() {
+    return "MecanumDrive";
+  }
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("MecanumDrive");
+    builder.addDoubleProperty("Front Left Motor Speed", m_frontLeftMotor::get,
+        m_frontLeftMotor::set);
+    builder.addDoubleProperty("Front Right Motor Speed", m_frontRightMotor::get,
+        m_frontRightMotor::set);
+    builder.addDoubleProperty("Rear Left Motor Speed", m_rearLeftMotor::get,
+        m_rearLeftMotor::set);
+    builder.addDoubleProperty("Rear Right Motor Speed", m_rearRightMotor::get,
+        m_rearRightMotor::set);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java
new file mode 100644
index 0000000..1cc140c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java
@@ -0,0 +1,148 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.drive;
+
+import edu.wpi.first.wpilibj.MotorSafety;
+import edu.wpi.first.wpilibj.MotorSafetyHelper;
+import edu.wpi.first.wpilibj.SendableBase;
+
+/**
+ * Common base class for drive platforms.
+ */
+public abstract class RobotDriveBase extends SendableBase implements MotorSafety {
+  public static final double kDefaultDeadband = 0.02;
+  public static final double kDefaultMaxOutput = 1.0;
+
+  protected double m_deadband = kDefaultDeadband;
+  protected double m_maxOutput = kDefaultMaxOutput;
+  protected MotorSafetyHelper m_safetyHelper = new MotorSafetyHelper(this);
+
+  /**
+   * The location of a motor on the robot for the purpose of driving.
+   */
+  public enum MotorType {
+    kFrontLeft(0), kFrontRight(1), kRearLeft(2), kRearRight(3), kLeft(0),
+    kRight(1), kBack(2);
+
+    @SuppressWarnings("MemberName")
+    public final int value;
+
+    MotorType(int value) {
+      this.value = value;
+    }
+  }
+
+  public RobotDriveBase() {
+    m_safetyHelper.setSafetyEnabled(true);
+    setName("RobotDriveBase");
+  }
+
+  /**
+   * Change the default value for deadband scaling. The default value is
+   * {@value #kDefaultDeadband}. Values smaller then the deadband are set to 0, while values
+   * larger then the deadband are scaled from 0.0 to 1.0. See {@link #applyDeadband}.
+   *
+   * @param deadband The deadband to set.
+   */
+  public void setDeadband(double deadband) {
+    m_deadband = deadband;
+  }
+
+  /**
+   * Configure the scaling factor for using drive methods with motor controllers in a mode other
+   * than PercentVbus or to limit the maximum output.
+   *
+   * <p>The default value is {@value #kDefaultMaxOutput}.
+   *
+   * @param maxOutput Multiplied with the output percentage computed by the drive functions.
+   */
+  public void setMaxOutput(double maxOutput) {
+    m_maxOutput = maxOutput;
+  }
+
+  @Override
+  public void setExpiration(double timeout) {
+    m_safetyHelper.setExpiration(timeout);
+  }
+
+  @Override
+  public double getExpiration() {
+    return m_safetyHelper.getExpiration();
+  }
+
+  @Override
+  public boolean isAlive() {
+    return m_safetyHelper.isAlive();
+  }
+
+  @Override
+  public abstract void stopMotor();
+
+  @Override
+  public boolean isSafetyEnabled() {
+    return m_safetyHelper.isSafetyEnabled();
+  }
+
+  @Override
+  public void setSafetyEnabled(boolean enabled) {
+    m_safetyHelper.setSafetyEnabled(enabled);
+  }
+
+  @Override
+  public abstract String getDescription();
+
+  /**
+   * Limit motor values to the -1.0 to +1.0 range.
+   */
+  protected double limit(double value) {
+    if (value > 1.0) {
+      return 1.0;
+    }
+    if (value < -1.0) {
+      return -1.0;
+    }
+    return value;
+  }
+
+  /**
+   * Returns 0.0 if the given value is within the specified range around zero. The remaining range
+   * between the deadband and 1.0 is scaled from 0.0 to 1.0.
+   *
+   * @param value    value to clip
+   * @param deadband range around zero
+   */
+  protected double applyDeadband(double value, double deadband) {
+    if (Math.abs(value) > deadband) {
+      if (value > 0.0) {
+        return (value - deadband) / (1.0 - deadband);
+      } else {
+        return (value + deadband) / (1.0 - deadband);
+      }
+    } else {
+      return 0.0;
+    }
+  }
+
+  /**
+   * Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
+   */
+  protected void normalize(double[] wheelSpeeds) {
+    double maxMagnitude = Math.abs(wheelSpeeds[0]);
+    for (int i = 1; i < wheelSpeeds.length; i++) {
+      double temp = Math.abs(wheelSpeeds[i]);
+      if (maxMagnitude < temp) {
+        maxMagnitude = temp;
+      }
+    }
+    if (maxMagnitude > 1.0) {
+      for (int i = 0; i < wheelSpeeds.length; i++) {
+        wheelSpeeds[i] = wheelSpeeds[i] / maxMagnitude;
+      }
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/Vector2d.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/Vector2d.java
new file mode 100644
index 0000000..fb27fb1
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/Vector2d.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.drive;
+
+/**
+ * This is a 2D vector struct that supports basic vector operations.
+ */
+@SuppressWarnings("MemberName")
+public class Vector2d {
+  public double x = 0.0;
+  public double y = 0.0;
+
+  public Vector2d() {}
+
+  @SuppressWarnings("ParameterName")
+  public Vector2d(double x, double y) {
+    this.x = x;
+    this.y = y;
+  }
+
+  /**
+   * Rotate a vector in Cartesian space.
+   *
+   * @param angle angle in degrees by which to rotate vector counter-clockwise.
+   */
+  public void rotate(double angle) {
+    double cosA = Math.cos(angle * (Math.PI / 180.0));
+    double sinA = Math.sin(angle * (Math.PI / 180.0));
+    double[] out = new double[2];
+    out[0] = x * cosA - y * sinA;
+    out[1] = x * sinA + y * cosA;
+    x = out[0];
+    y = out[1];
+  }
+
+  /**
+   * Returns dot product of this vector with argument.
+   *
+   * @param vec Vector with which to perform dot product.
+   */
+  public double dot(Vector2d vec) {
+    return x * vec.x + y * vec.y;
+  }
+
+  /**
+   * Returns magnitude of vector.
+   */
+  public double magnitude() {
+    return Math.sqrt(x * x + y * y);
+  }
+
+  /**
+   * Returns scalar projection of this vector onto argument.
+   *
+   * @param vec Vector onto which to project this vector.
+   */
+  public double scalarProject(Vector2d vec) {
+    return dot(vec) / vec.magnitude();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/Filter.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/Filter.java
new file mode 100644
index 0000000..9e174b5
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/Filter.java
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.filters;
+
+import edu.wpi.first.wpilibj.PIDSource;
+import edu.wpi.first.wpilibj.PIDSourceType;
+
+/**
+ * Superclass for filters.
+ */
+public abstract class Filter implements PIDSource {
+  private PIDSource m_source;
+
+  public Filter(PIDSource source) {
+    m_source = source;
+  }
+
+  @Override
+  public void setPIDSourceType(PIDSourceType pidSource) {
+    m_source.setPIDSourceType(pidSource);
+  }
+
+  @Override
+  public PIDSourceType getPIDSourceType() {
+    return m_source.getPIDSourceType();
+  }
+
+  @Override
+  public abstract double pidGet();
+
+  /**
+   * Returns the current filter estimate without also inserting new data as pidGet() would do.
+   *
+   * @return The current filter estimate
+   */
+  public abstract double get();
+
+  /**
+   * Reset the filter state.
+   */
+  public abstract void reset();
+
+  /**
+   * Calls PIDGet() of source.
+   *
+   * @return Current value of source
+   */
+  protected double pidGetSource() {
+    return m_source.pidGet();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/LinearDigitalFilter.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/LinearDigitalFilter.java
new file mode 100644
index 0000000..b473a24
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/LinearDigitalFilter.java
@@ -0,0 +1,183 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.filters;
+
+import edu.wpi.first.wpilibj.CircularBuffer;
+import edu.wpi.first.wpilibj.PIDSource;
+
+/**
+ * This class implements a linear, digital filter. All types of FIR and IIR filters are supported.
+ * Static factory methods are provided to create commonly used types of filters.
+ *
+ * <p>Filters are of the form: y[n] = (b0*x[n] + b1*x[n-1] + ... + bP*x[n-P]) - (a0*y[n-1] +
+ * a2*y[n-2] + ... + aQ*y[n-Q])
+ *
+ * <p>Where: y[n] is the output at time "n" x[n] is the input at time "n" y[n-1] is the output from
+ * the LAST time step ("n-1") x[n-1] is the input from the LAST time step ("n-1") b0...bP are the
+ * "feedforward" (FIR) gains a0...aQ are the "feedback" (IIR) gains IMPORTANT! Note the "-" sign in
+ * front of the feedback term! This is a common convention in signal processing.
+ *
+ * <p>What can linear filters do? Basically, they can filter, or diminish, the effects of
+ * undesirable input frequencies. High frequencies, or rapid changes, can be indicative of sensor
+ * noise or be otherwise undesirable. A "low pass" filter smooths out the signal, reducing the
+ * impact of these high frequency components.  Likewise, a "high pass" filter gets rid of
+ * slow-moving signal components, letting you detect large changes more easily.
+ *
+ * <p>Example FRC applications of filters: - Getting rid of noise from an analog sensor input (note:
+ * the roboRIO's FPGA can do this faster in hardware) - Smoothing out joystick input to prevent the
+ * wheels from slipping or the robot from tipping - Smoothing motor commands so that unnecessary
+ * strain isn't put on electrical or mechanical components - If you use clever gains, you can make a
+ * PID controller out of this class!
+ *
+ * <p>For more on filters, I highly recommend the following articles: http://en.wikipedia
+ * .org/wiki/Linear_filter http://en.wikipedia.org/wiki/Iir_filter http://en.wikipedia
+ * .org/wiki/Fir_filter
+ *
+ * <p>Note 1: PIDGet() should be called by the user on a known, regular period. You can set up a
+ * Notifier to do this (look at the WPILib PIDController class), or do it "inline" with code in a
+ * periodic function.
+ *
+ * <p>Note 2: For ALL filters, gains are necessarily a function of frequency. If you make a filter
+ * that works well for you at, say, 100Hz, you will most definitely need to adjust the gains if you
+ * then want to run it at 200Hz! Combining this with Note 1 - the impetus is on YOU as a developer
+ * to make sure PIDGet() gets called at the desired, constant frequency!
+ */
+public class LinearDigitalFilter extends Filter {
+  private CircularBuffer m_inputs;
+  private CircularBuffer m_outputs;
+  private double[] m_inputGains;
+  private double[] m_outputGains;
+
+  /**
+   * Create a linear FIR or IIR filter.
+   *
+   * @param source  The PIDSource object that is used to get values
+   * @param ffGains The "feed forward" or FIR gains
+   * @param fbGains The "feed back" or IIR gains
+   */
+  public LinearDigitalFilter(PIDSource source, double[] ffGains,
+                             double[] fbGains) {
+    super(source);
+    m_inputs = new CircularBuffer(ffGains.length);
+    m_outputs = new CircularBuffer(fbGains.length);
+    m_inputGains = ffGains;
+    m_outputGains = fbGains;
+  }
+
+  /**
+   * Creates a one-pole IIR low-pass filter of the form: y[n] = (1-gain)*x[n] + gain*y[n-1] where
+   * gain = e^(-dt / T), T is the time constant in seconds.
+   *
+   * <p>This filter is stable for time constants greater than zero.
+   *
+   * @param source       The PIDSource object that is used to get values
+   * @param timeConstant The discrete-time time constant in seconds
+   * @param period       The period in seconds between samples taken by the user
+   */
+  public static LinearDigitalFilter singlePoleIIR(PIDSource source,
+                                                  double timeConstant,
+                                                  double period) {
+    double gain = Math.exp(-period / timeConstant);
+    double[] ffGains = {1.0 - gain};
+    double[] fbGains = {-gain};
+
+    return new LinearDigitalFilter(source, ffGains, fbGains);
+  }
+
+  /**
+   * Creates a first-order high-pass filter of the form: y[n] = gain*x[n] + (-gain)*x[n-1] +
+   * gain*y[n-1] where gain = e^(-dt / T), T is the time constant in seconds.
+   *
+   * <p>This filter is stable for time constants greater than zero.
+   *
+   * @param source       The PIDSource object that is used to get values
+   * @param timeConstant The discrete-time time constant in seconds
+   * @param period       The period in seconds between samples taken by the user
+   */
+  public static LinearDigitalFilter highPass(PIDSource source,
+                                             double timeConstant,
+                                             double period) {
+    double gain = Math.exp(-period / timeConstant);
+    double[] ffGains = {gain, -gain};
+    double[] fbGains = {-gain};
+
+    return new LinearDigitalFilter(source, ffGains, fbGains);
+  }
+
+  /**
+   * Creates a K-tap FIR moving average filter of the form: y[n] = 1/k * (x[k] + x[k-1] + ... +
+   * x[0]).
+   *
+   * <p>This filter is always stable.
+   *
+   * @param source The PIDSource object that is used to get values
+   * @param taps   The number of samples to average over. Higher = smoother but slower
+   * @throws IllegalArgumentException if number of taps is less than 1
+   */
+  public static LinearDigitalFilter movingAverage(PIDSource source, int taps) {
+    if (taps <= 0) {
+      throw new IllegalArgumentException("Number of taps was not at least 1");
+    }
+
+    double[] ffGains = new double[taps];
+    for (int i = 0; i < ffGains.length; i++) {
+      ffGains[i] = 1.0 / taps;
+    }
+
+    double[] fbGains = new double[0];
+
+    return new LinearDigitalFilter(source, ffGains, fbGains);
+  }
+
+  @Override
+  public double get() {
+    double retVal = 0.0;
+
+    // Calculate the new value
+    for (int i = 0; i < m_inputGains.length; i++) {
+      retVal += m_inputs.get(i) * m_inputGains[i];
+    }
+    for (int i = 0; i < m_outputGains.length; i++) {
+      retVal -= m_outputs.get(i) * m_outputGains[i];
+    }
+
+    return retVal;
+  }
+
+  @Override
+  public void reset() {
+    m_inputs.clear();
+    m_outputs.clear();
+  }
+
+  /**
+   * Calculates the next value of the filter.
+   *
+   * @return The filtered value at this step
+   */
+  @Override
+  public double pidGet() {
+    double retVal = 0.0;
+
+    // Rotate the inputs
+    m_inputs.addFirst(pidGetSource());
+
+    // Calculate the new value
+    for (int i = 0; i < m_inputGains.length; i++) {
+      retVal += m_inputs.get(i) * m_inputGains[i];
+    }
+    for (int i = 0; i < m_outputGains.length; i++) {
+      retVal -= m_outputs.get(i) * m_outputGains[i];
+    }
+
+    // Rotate the outputs
+    m_outputs.addFirst(retVal);
+
+    return retVal;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AccelerometerJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AccelerometerJNI.java
new file mode 100644
index 0000000..763f26a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AllianceStationID.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AllianceStationID.java
new file mode 100644
index 0000000..5f4bea9
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.hal;
+
+public enum AllianceStationID {
+  Red1, Red2, Red3, Blue1, Blue2, Blue3
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AnalogGyroJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AnalogGyroJNI.java
new file mode 100644
index 0000000..df85536
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AnalogJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AnalogJNI.java
new file mode 100644
index 0000000..9745547
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/AnalogJNI.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.hal;
+
+import edu.wpi.first.wpilibj.AccumulatorResult;
+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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/CompressorJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/CompressorJNI.java
new file mode 100644
index 0000000..756a23d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/ConstantsJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/ConstantsJNI.java
new file mode 100644
index 0000000..44b86ec
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.hal;
+
+public class ConstantsJNI extends JNIWrapper {
+  public static native int getSystemClockTicksPerMicrosecond();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/ControlWord.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/ControlWord.java
new file mode 100644
index 0000000..a821ba4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/CounterJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/CounterJNI.java
new file mode 100644
index 0000000..6f9faa8
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/DIOJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/DIOJNI.java
new file mode 100644
index 0000000..c861621
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/DIOJNI.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.wpilibj.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);
+
+  public static native void setDIO(int dioPortHandle, short value);
+
+  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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/DigitalGlitchFilterJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/DigitalGlitchFilterJNI.java
new file mode 100644
index 0000000..83eedef
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/EncoderJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/EncoderJNI.java
new file mode 100644
index 0000000..f8318b4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/FRCNetComm.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/FRCNetComm.java
new file mode 100644
index 0000000..ebcd1fe
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/FRCNetComm.java
@@ -0,0 +1,160 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.hal;
+
+/**
+ * JNI wrapper for library <b>FRC_NetworkCommunication</b><br>.
+ */
+@SuppressWarnings("MethodName")
+public class FRCNetComm extends JNIWrapper {
+  /**
+   * Module type from LoadOut.h
+   */
+  @SuppressWarnings("TypeName")
+  public interface tModuleType {
+    int kModuleType_Unknown = 0x00;
+    int kModuleType_Analog = 0x01;
+    int kModuleType_Digital = 0x02;
+    int kModuleType_Solenoid = 0x03;
+  }
+
+  /**
+   * Target class from LoadOut.h
+   */
+  @SuppressWarnings("TypeName")
+  public interface tTargetClass {
+    int kTargetClass_Unknown = 0x00;
+    int kTargetClass_FRC1 = 0x10;
+    int kTargetClass_FRC2 = 0x20;
+    int kTargetClass_FRC3 = 0x30;
+    int kTargetClass_RoboRIO = 0x40;
+    int kTargetClass_FRC2_Analog = kTargetClass_FRC2 | tModuleType.kModuleType_Analog;
+    int kTargetClass_FRC2_Digital = kTargetClass_FRC2 | tModuleType.kModuleType_Digital;
+    int kTargetClass_FRC2_Solenoid = kTargetClass_FRC2 | tModuleType.kModuleType_Solenoid;
+    int kTargetClass_FamilyMask = 0xF0;
+    int kTargetClass_ModuleMask = 0x0F;
+  }
+
+  /**
+   * Resource type from UsageReporting.h
+   */
+  @SuppressWarnings("TypeName")
+  public interface tResourceType {
+    int kResourceType_Controller = 0;
+    int kResourceType_Module = 1;
+    int kResourceType_Language = 2;
+    int kResourceType_CANPlugin = 3;
+    int kResourceType_Accelerometer = 4;
+    int kResourceType_ADXL345 = 5;
+    int kResourceType_AnalogChannel = 6;
+    int kResourceType_AnalogTrigger = 7;
+    int kResourceType_AnalogTriggerOutput = 8;
+    int kResourceType_CANJaguar = 9;
+    int kResourceType_Compressor = 10;
+    int kResourceType_Counter = 11;
+    int kResourceType_Dashboard = 12;
+    int kResourceType_DigitalInput = 13;
+    int kResourceType_DigitalOutput = 14;
+    int kResourceType_DriverStationCIO = 15;
+    int kResourceType_DriverStationEIO = 16;
+    int kResourceType_DriverStationLCD = 17;
+    int kResourceType_Encoder = 18;
+    int kResourceType_GearTooth = 19;
+    int kResourceType_Gyro = 20;
+    int kResourceType_I2C = 21;
+    int kResourceType_Framework = 22;
+    int kResourceType_Jaguar = 23;
+    int kResourceType_Joystick = 24;
+    int kResourceType_Kinect = 25;
+    int kResourceType_KinectStick = 26;
+    int kResourceType_PIDController = 27;
+    int kResourceType_Preferences = 28;
+    int kResourceType_PWM = 29;
+    int kResourceType_Relay = 30;
+    int kResourceType_RobotDrive = 31;
+    int kResourceType_SerialPort = 32;
+    int kResourceType_Servo = 33;
+    int kResourceType_Solenoid = 34;
+    int kResourceType_SPI = 35;
+    int kResourceType_Task = 36;
+    int kResourceType_Ultrasonic = 37;
+    int kResourceType_Victor = 38;
+    int kResourceType_Button = 39;
+    int kResourceType_Command = 40;
+    int kResourceType_AxisCamera = 41;
+    int kResourceType_PCVideoServer = 42;
+    int kResourceType_SmartDashboard = 43;
+    int kResourceType_Talon = 44;
+    int kResourceType_HiTechnicColorSensor = 45;
+    int kResourceType_HiTechnicAccel = 46;
+    int kResourceType_HiTechnicCompass = 47;
+    int kResourceType_SRF08 = 48;
+    int kResourceType_AnalogOutput = 49;
+    int kResourceType_VictorSP = 50;
+    int kResourceType_PWMTalonSRX = 51;
+    int kResourceType_CANTalonSRX = 52;
+    int kResourceType_ADXL362 = 53;
+    int kResourceType_ADXRS450 = 54;
+    int kResourceType_RevSPARK = 55;
+    int kResourceType_MindsensorsSD540 = 56;
+    int kResourceType_DigitalFilter = 57;
+    int kResourceType_ADIS16448 = 58;
+    int kResourceType_PDP = 59;
+    int kResourceType_PCM = 60;
+    int kResourceType_PigeonIMU = 61;
+    int kResourceType_NidecBrushless = 62;
+  }
+
+  /**
+   * Instances from UsageReporting.h
+   */
+  @SuppressWarnings("TypeName")
+  public interface tInstances {
+    int kLanguage_LabVIEW = 1;
+    int kLanguage_CPlusPlus = 2;
+    int kLanguage_Java = 3;
+    int kLanguage_Python = 4;
+
+    int kCANPlugin_BlackJagBridge = 1;
+    int kCANPlugin_2CAN = 2;
+
+    int kFramework_Iterative = 1;
+    int kFramework_Simple = 2;
+    int kFramework_CommandControl = 3;
+
+    int kRobotDrive_ArcadeStandard = 1;
+    int kRobotDrive_ArcadeButtonSpin = 2;
+    int kRobotDrive_ArcadeRatioCurve = 3;
+    int kRobotDrive_Tank = 4;
+    int kRobotDrive_MecanumPolar = 5;
+    int kRobotDrive_MecanumCartesian = 6;
+
+    int kDriverStationCIO_Analog = 1;
+    int kDriverStationCIO_DigitalIn = 2;
+    int kDriverStationCIO_DigitalOut = 3;
+
+    int kDriverStationEIO_Acceleration = 1;
+    int kDriverStationEIO_AnalogIn = 2;
+    int kDriverStationEIO_AnalogOut = 3;
+    int kDriverStationEIO_Button = 4;
+    int kDriverStationEIO_LED = 5;
+    int kDriverStationEIO_DigitalIn = 6;
+    int kDriverStationEIO_DigitalOut = 7;
+    int kDriverStationEIO_FixedDigitalOut = 8;
+    int kDriverStationEIO_PWM = 9;
+    int kDriverStationEIO_Encoder = 10;
+    int kDriverStationEIO_TouchSlider = 11;
+
+    int kADXL345_SPI = 1;
+    int kADXL345_I2C = 2;
+
+    int kCommand_Scheduler = 1;
+
+    int kSmartDashboard_Instance = 1;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/HAL.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/HAL.java
new file mode 100644
index 0000000..2516a40
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/HAL.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.hal;
+
+import java.nio.ByteBuffer;
+
+/**
+ * JNI Wrapper for HAL<br>.
+ */
+@SuppressWarnings({"AbbreviationAsWordInName", "MethodName"})
+public 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);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/HALUtil.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/HALUtil.java
new file mode 100644
index 0000000..a68255c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/HALUtil.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public 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());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/I2CJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/I2CJNI.java
new file mode 100644
index 0000000..8aeac27
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/InterruptJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/InterruptJNI.java
new file mode 100644
index 0000000..6973c63
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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 double readInterruptRisingTimestamp(int interruptHandle);
+
+  public static native double 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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/JNIWrapper.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/JNIWrapper.java
new file mode 100644
index 0000000..e352382
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/JNIWrapper.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.hal;
+
+import edu.wpi.first.wpiutil.RuntimeDetector;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Base class for all JNI wrappers.
+ */
+public class JNIWrapper {
+  static boolean libraryLoaded = false;
+  static File jniLibrary = null;
+
+  static {
+    if (!libraryLoaded) {
+      String jniFileName = "wpilibJNI";
+      try {
+        System.loadLibrary(jniFileName);
+      } catch (UnsatisfiedLinkError ule) {
+        try {
+          String resname = RuntimeDetector.getLibraryResource(jniFileName);
+          InputStream is = JNIWrapper.class.getResourceAsStream(resname);
+          if (is != null) {
+            // create temporary file
+            if (System.getProperty("os.name").startsWith("Windows")) {
+              jniLibrary = File.createTempFile(jniFileName, ".dll");
+            } else if (System.getProperty("os.name").startsWith("Mac")) {
+              jniLibrary = File.createTempFile(jniFileName, ".dylib");
+            } else {
+              jniLibrary = File.createTempFile(jniFileName, ".so");
+            }
+            // flag for delete on exit
+            jniLibrary.deleteOnExit();
+            OutputStream os = new FileOutputStream(jniLibrary);
+
+            byte[] buffer = new byte[1024];
+            int readBytes;
+            try {
+              while ((readBytes = is.read(buffer)) != -1) {
+                os.write(buffer, 0, readBytes);
+              }
+            } finally {
+              os.close();
+              is.close();
+            }
+            System.load(jniLibrary.getAbsolutePath());
+          } else {
+            System.loadLibrary(jniFileName);
+          }
+        } catch (IOException ex) {
+          ex.printStackTrace();
+          System.exit(1);
+        }
+      }
+      libraryLoaded = true;
+    }
+  }
+
+  public static native int getPortWithModule(byte module, byte channel);
+
+  public static native int getPort(byte channel);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/MatchInfoData.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/MatchInfoData.java
new file mode 100644
index 0000000..79a3cf9
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/NotifierJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/NotifierJNI.java
new file mode 100644
index 0000000..43e218a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/OSSerialPortJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/OSSerialPortJNI.java
new file mode 100644
index 0000000..b7b043b
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/OSSerialPortJNI.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.wpilibj.hal;
+
+public class OSSerialPortJNI extends JNIWrapper {
+  public static native void serialInitializePort(byte port);
+
+  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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PDPJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PDPJNI.java
new file mode 100644
index 0000000..970168c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class PDPJNI extends JNIWrapper {
+  public static native void initializePDP(int module);
+
+  public static native boolean checkPDPModule(int module);
+
+  public static native boolean checkPDPChannel(int channel);
+
+  public static native double getPDPTemperature(int module);
+
+  public static native double getPDPVoltage(int module);
+
+  public static native double getPDPChannelCurrent(byte channel, int module);
+
+  public static native double getPDPTotalCurrent(int module);
+
+  public static native double getPDPTotalPower(int module);
+
+  public static native double getPDPTotalEnergy(int module);
+
+  public static native void resetPDPTotalEnergy(int module);
+
+  public static native void clearPDPStickyFaults(int module);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PWMJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PWMJNI.java
new file mode 100644
index 0000000..33eb91e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PWMJNI.java
@@ -0,0 +1,51 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.hal;
+
+import edu.wpi.first.wpilibj.PWMConfigDataResult;
+
+@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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PortsJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PortsJNI.java
new file mode 100644
index 0000000..aadf3f3
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PowerJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/PowerJNI.java
new file mode 100644
index 0000000..887b914
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/RelayJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/RelayJNI.java
new file mode 100644
index 0000000..aa2bf7a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SPIJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SPIJNI.java
new file mode 100644
index 0000000..9bcca72
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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, byte[] buffer, int numToRead,
+                                                   double timeout);
+
+  public static native int spiGetAutoDroppedCount(int port);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SerialPortJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SerialPortJNI.java
new file mode 100644
index 0000000..f626dc0
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SerialPortJNI.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.wpilibj.hal;
+
+public class SerialPortJNI extends JNIWrapper {
+  public static native void serialInitializePort(byte port);
+
+  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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SolenoidJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SolenoidJNI.java
new file mode 100644
index 0000000..fcde112
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/ThreadsJNI.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/ThreadsJNI.java
new file mode 100644
index 0000000..2667d3a
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Accelerometer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Accelerometer.java
new file mode 100644
index 0000000..81086d4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Accelerometer.java
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2014-2018 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be 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.wpilibj.interfaces;
+
+/**
+ * Interface for 3-axis accelerometers.
+ */
+public interface Accelerometer {
+  enum Range {
+    k2G, k4G, k8G, k16G
+  }
+
+  /**
+   * Common interface for setting the measuring range of an accelerometer.
+   *
+   * @param range The maximum acceleration, positive or negative, that the accelerometer will
+   *              measure. Not all accelerometers support all ranges.
+   */
+  void setRange(Range range);
+
+  /**
+   * Common interface for getting the x axis acceleration.
+   *
+   * @return The acceleration along the x axis in g-forces
+   */
+  double getX();
+
+  /**
+   * Common interface for getting the y axis acceleration.
+   *
+   * @return The acceleration along the y axis in g-forces
+   */
+  double getY();
+
+  /**
+   * Common interface for getting the z axis acceleration.
+   *
+   * @return The acceleration along the z axis in g-forces
+   */
+  double getZ();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Gyro.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Gyro.java
new file mode 100644
index 0000000..4277425
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Gyro.java
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2014-2018 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be 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.wpilibj.interfaces;
+
+/**
+ * Interface for yaw rate gyros.
+ */
+public interface Gyro {
+  /**
+   * Calibrate the gyro by running for a number of samples and computing the center value. Then use
+   * the center value as the Accumulator center value for subsequent measurements. It's important to
+   * make sure that the robot is not moving while the centering calculations are in progress, this
+   * is typically done when the robot is first turned on while it's sitting at rest before the
+   * competition starts.
+   */
+  void calibrate();
+
+  /**
+   * Reset the gyro. Resets the gyro to a heading of zero. This can be used if there is significant
+   * drift in the gyro and it needs to be recalibrated after it has been running.
+   */
+  void reset();
+
+  /**
+   * Return the actual angle in degrees that the robot is currently facing.
+   *
+   * <p>The angle is based on the current accumulator value corrected by the oversampling rate, the
+   * gyro type and the A/D calibration values. The angle is continuous, that is it will continue
+   * from 360 to 361 degrees. This allows algorithms that wouldn't want to see a discontinuity in
+   * the gyro output as it sweeps past from 360 to 0 on the second time around.
+   *
+   * <p>This heading is based on integration of the returned rate from the gyro.
+   *
+   * @return the current heading of the robot in degrees.
+   */
+  double getAngle();
+
+  /**
+   * Return the rate of rotation of the gyro.
+   *
+   * <p>The rate is based on the most recent reading of the gyro analog value
+   *
+   * @return the current rate in degrees per second
+   */
+  double getRate();
+
+  /**
+   * Free the resources used by the gyro.
+   */
+  void free();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Potentiometer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Potentiometer.java
new file mode 100644
index 0000000..ea5c1e6
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Potentiometer.java
@@ -0,0 +1,17 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.interfaces;
+
+import edu.wpi.first.wpilibj.PIDSource;
+
+/**
+ * Interface for a Potentiometer.
+ */
+public interface Potentiometer extends PIDSource {
+  double get();
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/internal/HardwareHLUsageReporting.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/internal/HardwareHLUsageReporting.java
new file mode 100644
index 0000000..c2865b3
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/internal/HardwareHLUsageReporting.java
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.internal;
+
+import edu.wpi.first.wpilibj.HLUsageReporting;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
+import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.wpilibj.hal.HAL;
+
+public class HardwareHLUsageReporting implements HLUsageReporting.Interface {
+  @Override
+  public void reportScheduler() {
+    HAL.report(tResourceType.kResourceType_Command, tInstances.kCommand_Scheduler);
+  }
+
+  @Override
+  public void reportPIDController(int num) {
+    HAL.report(tResourceType.kResourceType_PIDController, num);
+  }
+
+  @Override
+  public void reportSmartDashboard() {
+    HAL.report(tResourceType.kResourceType_SmartDashboard, 0);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/internal/HardwareTimer.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/internal/HardwareTimer.java
new file mode 100644
index 0000000..19b09f4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/internal/HardwareTimer.java
@@ -0,0 +1,138 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.internal;
+
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.RobotController;
+import edu.wpi.first.wpilibj.Timer;
+
+/**
+ * Timer objects measure accumulated time in milliseconds. The timer object functions like a
+ * stopwatch. It can be started, stopped, and cleared. When the timer is running its value counts
+ * up in milliseconds. When stopped, the timer holds the current value. The implementation simply
+ * records the time when started and subtracts the current time whenever the value is requested.
+ */
+public class HardwareTimer implements Timer.StaticInterface {
+  /**
+   * Pause the thread for a specified time. Pause the execution of the thread for a specified period
+   * of time given in seconds. Motors will continue to run at their last assigned values, and
+   * sensors will continue to update. Only the task containing the wait will pause until the wait
+   * time is expired.
+   *
+   * @param seconds Length of time to pause
+   */
+  @Override
+  public void delay(final double seconds) {
+    try {
+      Thread.sleep((long) (seconds * 1e3));
+    } catch (final InterruptedException ex) {
+      Thread.currentThread().interrupt();
+    }
+  }
+
+  /**
+   * Return the system clock time in seconds. Return the time from the FPGA hardware clock in
+   * seconds since the FPGA started.
+   *
+   * @return Robot running time in seconds.
+   */
+  @Override
+  public double getFPGATimestamp() {
+    return RobotController.getFPGATime() / 1000000.0;
+  }
+
+  @Override
+  public double getMatchTime() {
+    return DriverStation.getInstance().getMatchTime();
+  }
+
+  @Override
+  public Timer.Interface newTimer() {
+    return new TimerImpl();
+  }
+
+  class TimerImpl implements Timer.Interface {
+    private double m_startTime;
+    private double m_accumulatedTime;
+    private boolean m_running;
+
+    /**
+     * Create a new timer object. Create a new timer object and reset the time to zero. The timer is
+     * initially not running and must be started.
+     */
+    TimerImpl() {
+      reset();
+    }
+
+    private double getMsClock() {
+      return RobotController.getFPGATime() / 1000.0;
+    }
+
+    /**
+     * Get the current time from the timer. If the clock is running it is derived from the current
+     * system clock the start time stored in the timer class. If the clock is not running, then
+     * return the time when it was last stopped.
+     *
+     * @return Current time value for this timer in seconds
+     */
+    public synchronized double get() {
+      if (m_running) {
+        return ((getMsClock() - m_startTime) + m_accumulatedTime) / 1000.0;
+      } else {
+        return m_accumulatedTime;
+      }
+    }
+
+    /**
+     * Reset the timer by setting the time to 0. Make the timer start time the current time so new
+     * requests will be relative now
+     */
+    public synchronized void reset() {
+      m_accumulatedTime = 0;
+      m_startTime = getMsClock();
+    }
+
+    /**
+     * Start the timer running. Just set the running flag to true indicating that all time
+     * requests should be relative to the system clock.
+     */
+    public synchronized void start() {
+      m_startTime = getMsClock();
+      m_running = true;
+    }
+
+    /**
+     * Stop the timer. This computes the time as of now and clears the running flag, causing all
+     * subsequent time requests to be read from the accumulated time rather than looking at the
+     * system clock.
+     */
+    public synchronized void stop() {
+      final double temp = get();
+      m_accumulatedTime = temp;
+      m_running = false;
+    }
+
+    /**
+     * Check if the period specified has passed and if it has, advance the start time by that
+     * period. This is useful to decide if it's time to do periodic work without drifting later by
+     * the time it took to get around to checking.
+     *
+     * @param period The period to check for (in seconds).
+     * @return If the period has passed.
+     */
+    public synchronized boolean hasPeriodPassed(double period) {
+      if (get() > period) {
+        // Advance the start time by the period.
+        // Don't set it to the current time... we want to avoid drift.
+        m_startTime += period * 1000;
+        return true;
+      }
+      return false;
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindow.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindow.java
new file mode 100644
index 0000000..8a6410e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindow.java
@@ -0,0 +1,288 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.livewindow;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import edu.wpi.first.wpilibj.command.Scheduler;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilderImpl;
+import edu.wpi.first.wpilibj.Sendable;
+
+
+/**
+ * The LiveWindow class is the public interface for putting sensors and actuators on the
+ * LiveWindow.
+ */
+public class LiveWindow {
+  private static class Component {
+    Component(Sendable sendable, Sendable parent) {
+      m_sendable = sendable;
+      m_parent = parent;
+    }
+
+    final Sendable m_sendable;
+    Sendable m_parent;
+    final SendableBuilderImpl m_builder = new SendableBuilderImpl();
+    boolean m_firstTime = true;
+    boolean m_telemetryEnabled = true;
+  }
+
+  private static final Map<Object, Component> components = new HashMap<>();
+  private static final NetworkTable liveWindowTable =
+      NetworkTableInstance.getDefault().getTable("LiveWindow");
+  private static final NetworkTable statusTable = liveWindowTable.getSubTable(".status");
+  private static final NetworkTableEntry enabledEntry = statusTable.getEntry("LW Enabled");
+  private static boolean startLiveWindow = false;
+  private static boolean liveWindowEnabled = false;
+  private static boolean telemetryEnabled = true;
+
+  public static synchronized boolean isEnabled() {
+    return liveWindowEnabled;
+  }
+
+  /**
+   * Set the enabled state of LiveWindow. If it's being enabled, turn off the scheduler and remove
+   * all the commands from the queue and enable all the components registered for LiveWindow. If
+   * it's being disabled, stop all the registered components and reenable the scheduler. TODO: add
+   * code to disable PID loops when enabling LiveWindow. The commands should reenable the PID loops
+   * themselves when they get rescheduled. This prevents arms from starting to move around, etc.
+   * after a period of adjusting them in LiveWindow mode.
+   */
+  public static synchronized void setEnabled(boolean enabled) {
+    if (liveWindowEnabled != enabled) {
+      Scheduler scheduler = Scheduler.getInstance();
+      if (enabled) {
+        System.out.println("Starting live window mode.");
+        scheduler.disable();
+        scheduler.removeAll();
+      } else {
+        System.out.println("stopping live window mode.");
+        for (Component component : components.values()) {
+          component.m_builder.stopLiveWindowMode();
+        }
+        scheduler.enable();
+      }
+      startLiveWindow = enabled;
+      liveWindowEnabled = enabled;
+      enabledEntry.setBoolean(enabled);
+    }
+  }
+
+  /**
+   * The run method is called repeatedly to keep the values refreshed on the screen in test mode.
+   * @deprecated No longer required
+   */
+  @Deprecated
+  public static void run() {
+    updateValues();
+  }
+
+  /**
+   * Add a Sensor associated with the subsystem and with call it by the given name.
+   *
+   * @param subsystem The subsystem this component is part of.
+   * @param name      The name of this component.
+   * @param component A LiveWindowSendable component that represents a sensor.
+   * @deprecated Use {@link Sendable#setName(String, String)} instead.
+   */
+  @Deprecated
+  public static synchronized void addSensor(String subsystem, String name, Sendable component) {
+    add(component);
+    component.setName(subsystem, name);
+  }
+
+  /**
+   * Add Sensor to LiveWindow. The components are shown with the type and channel like this: Gyro[1]
+   * for a gyro object connected to the first analog channel.
+   *
+   * @param moduleType A string indicating the type of the module used in the naming (above)
+   * @param channel    The channel number the device is connected to
+   * @param component  A reference to the object being added
+   * @deprecated Use {@link edu.wpi.first.wpilibj.SensorBase#setName(String, int)} instead.
+   */
+  @Deprecated
+  public static void addSensor(String moduleType, int channel, Sendable component) {
+    add(component);
+    component.setName("Ungrouped", moduleType + "[" + channel + "]");
+  }
+
+  /**
+   * Add an Actuator associated with the subsystem and with call it by the given name.
+   *
+   * @param subsystem The subsystem this component is part of.
+   * @param name      The name of this component.
+   * @param component A LiveWindowSendable component that represents a actuator.
+   * @deprecated Use {@link Sendable#setName(String, String)} instead.
+   */
+  @Deprecated
+  public static synchronized void addActuator(String subsystem, String name, Sendable component) {
+    add(component);
+    component.setName(subsystem, name);
+  }
+
+  /**
+   * Add Actuator to LiveWindow. The components are shown with the module type, slot and channel
+   * like this: Servo[1,2] for a servo object connected to the first digital module and PWM port 2.
+   *
+   * @param moduleType A string that defines the module name in the label for the value
+   * @param channel    The channel number the device is plugged into (usually PWM)
+   * @param component  The reference to the object being added
+   * @deprecated Use {@link edu.wpi.first.wpilibj.SensorBase#setName(String, int)} instead.
+   */
+  @Deprecated
+  public static void addActuator(String moduleType, int channel, Sendable component) {
+    add(component);
+    component.setName("Ungrouped", moduleType + "[" + channel + "]");
+  }
+
+  /**
+   * Add Actuator to LiveWindow. The components are shown with the module type, slot and channel
+   * like this: Servo[1,2] for a servo object connected to the first digital module and PWM port 2.
+   *
+   * @param moduleType   A string that defines the module name in the label for the value
+   * @param moduleNumber The number of the particular module type
+   * @param channel      The channel number the device is plugged into (usually PWM)
+   * @param component    The reference to the object being added
+   * @deprecated Use {@link edu.wpi.first.wpilibj.SensorBase#setName(String, int, int)} instead.
+   */
+  @Deprecated
+  public static void addActuator(String moduleType, int moduleNumber, int channel,
+                                 Sendable component) {
+    add(component);
+    component.setName("Ungrouped", moduleType + "[" + moduleNumber + "," + channel + "]");
+  }
+
+  /**
+   * Add a component to the LiveWindow.
+   *
+   * @param sendable component to add
+   */
+  public static synchronized void add(Sendable sendable) {
+    components.putIfAbsent(sendable, new Component(sendable, null));
+  }
+
+  /**
+   * Add a child component to a component.
+   *
+   * @param parent parent component
+   * @param child child component
+   */
+  public static synchronized void addChild(Sendable parent, Object child) {
+    Component component = components.get(child);
+    if (component == null) {
+      component = new Component(null, parent);
+      components.put(child, component);
+    } else {
+      component.m_parent = parent;
+    }
+    component.m_telemetryEnabled = false;
+  }
+
+  /**
+   * Remove a component from the LiveWindow.
+   *
+   * @param sendable component to remove
+   */
+  public static synchronized void remove(Sendable sendable) {
+    Component component = components.remove(sendable);
+    if (component != null && isEnabled()) {
+      component.m_builder.stopLiveWindowMode();
+    }
+  }
+
+  /**
+   * Enable telemetry for a single component.
+   *
+   * @param sendable component
+   */
+  public static synchronized void enableTelemetry(Sendable sendable) {
+    // Re-enable global setting in case disableAllTelemetry() was called.
+    telemetryEnabled = true;
+    Component component = components.get(sendable);
+    if (component != null) {
+      component.m_telemetryEnabled = true;
+    }
+  }
+
+  /**
+   * Disable telemetry for a single component.
+   *
+   * @param sendable component
+   */
+  public static synchronized void disableTelemetry(Sendable sendable) {
+    Component component = components.get(sendable);
+    if (component != null) {
+      component.m_telemetryEnabled = false;
+    }
+  }
+
+  /**
+   * Disable ALL telemetry.
+   */
+  public static synchronized void disableAllTelemetry() {
+    telemetryEnabled = false;
+    for (Component component : components.values()) {
+      component.m_telemetryEnabled = false;
+    }
+  }
+
+  /**
+   * Tell all the sensors to update (send) their values.
+   *
+   * <p>Actuators are handled through callbacks on their value changing from the
+   * SmartDashboard widgets.
+   */
+  public static synchronized void updateValues() {
+    // Only do this if either LiveWindow mode or telemetry is enabled.
+    if (!liveWindowEnabled && !telemetryEnabled) {
+      return;
+    }
+
+    for (Component component : components.values()) {
+      if (component.m_sendable != null && component.m_parent == null
+          && (liveWindowEnabled || component.m_telemetryEnabled)) {
+        if (component.m_firstTime) {
+          // By holding off creating the NetworkTable entries, it allows the
+          // components to be redefined. This allows default sensor and actuator
+          // values to be created that are replaced with the custom names from
+          // users calling setName.
+          String name = component.m_sendable.getName();
+          if (name.isEmpty()) {
+            continue;
+          }
+          String subsystem = component.m_sendable.getSubsystem();
+          NetworkTable ssTable = liveWindowTable.getSubTable(subsystem);
+          NetworkTable table;
+          // Treat name==subsystem as top level of subsystem
+          if (name.equals(subsystem)) {
+            table = ssTable;
+          } else {
+            table = ssTable.getSubTable(name);
+          }
+          table.getEntry(".name").setString(name);
+          component.m_builder.setTable(table);
+          component.m_sendable.initSendable(component.m_builder);
+          ssTable.getEntry(".type").setString("LW Subsystem");
+
+          component.m_firstTime = false;
+        }
+
+        if (startLiveWindow) {
+          component.m_builder.startLiveWindowMode();
+        }
+        component.m_builder.updateTable();
+      }
+    }
+
+    startLiveWindow = false;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindowSendable.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindowSendable.java
new file mode 100644
index 0000000..ecb45ba
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindowSendable.java
@@ -0,0 +1,57 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.livewindow;
+
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+import edu.wpi.first.wpilibj.Sendable;
+
+/**
+ * Live Window Sendable is a special type of object sendable to the live window.
+ * @deprecated Use Sendable directly instead
+ */
+@Deprecated
+public interface LiveWindowSendable extends Sendable {
+  /**
+   * Update the table for this sendable object with the latest values.
+   */
+  void updateTable();
+
+  /**
+   * Start having this sendable object automatically respond to value changes reflect the value on
+   * the table.
+   */
+  void startLiveWindowMode();
+
+  /**
+   * Stop having this sendable object automatically respond to value changes.
+   */
+  void stopLiveWindowMode();
+
+  @Override
+  default String getName() {
+    return "";
+  }
+
+  @Override
+  default void setName(String name) {
+  }
+
+  @Override
+  default String getSubsystem() {
+    return "";
+  }
+
+  @Override
+  default void setSubsystem(String subsystem) {
+  }
+
+  @Override
+  default void initSendable(SendableBuilder builder) {
+    builder.setUpdateTable(this::updateTable);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/package.html b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/package.html
new file mode 100644
index 0000000..c22bf27
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/package.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+    <title>WPI Robotics library</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=MacRoman">
+</head>
+<body>
+The WPI Robotics library (WPILibJ) is a set of Java classes that interfaces to the hardware in the
+FRC control system and your robot. There are classes to handle sensors, motors, the driver
+station, and a number of other utility functions like timing and field management.
+The library is designed to:
+<ul>
+    <li>Deal with all the low level interfacing to these components so you can concentrate on
+        solving this year's "robot problem". This is a philosophical decision to let you focus
+        on the higher-level design of your robot rather than deal with the details of the
+        processor and the operating system.
+    </li>
+    <li>Understand everything at all levels by making the full source code of the library
+        available. You can study (and modify) the algorithms used by the gyro class for
+        oversampling and integration of the input signal or just ask the class for the current
+        robot heading. You can work at any level.
+    </li>
+</ul>
+</body>
+</html>
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilder.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilder.java
new file mode 100644
index 0000000..c9ef492
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilder.java
@@ -0,0 +1,143 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.smartdashboard;
+
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableValue;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.Supplier;
+
+public interface SendableBuilder {
+  /**
+   * Set the string representation of the named data type that will be used
+   * by the smart dashboard for this sendable.
+   *
+   * @param type    data type
+   */
+  void setSmartDashboardType(String type);
+
+  /**
+   * Set the function that should be called to set the Sendable into a safe
+   * state.  This is called when entering and exiting Live Window mode.
+   *
+   * @param func    function
+   */
+  void setSafeState(Runnable func);
+
+  /**
+   * Set the function that should be called to update the network table
+   * for things other than properties.  Note this function is not passed
+   * the network table object; instead it should use the entry handles
+   * returned by getEntry().
+   *
+   * @param func    function
+   */
+  void setUpdateTable(Runnable func);
+
+  /**
+   * Add a property without getters or setters.  This can be used to get
+   * entry handles for the function called by setUpdateTable().
+   *
+   * @param key   property name
+   * @return Network table entry
+   */
+  NetworkTableEntry getEntry(String key);
+
+  /**
+   * Represents an operation that accepts a single boolean-valued argument and
+   * returns no result. This is the primitive type specialization of Consumer
+   * for boolean. Unlike most other functional interfaces, BooleanConsumer is
+   * expected to operate via side-effects.
+   *
+   * <p>This is a functional interface whose functional method is accept(boolean).
+   */
+  @FunctionalInterface
+  interface BooleanConsumer {
+    /**
+     * Performs the operation on the given value.
+     * @param value the value
+     */
+    void accept(boolean value);
+  }
+
+  /**
+   * Add a boolean property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter);
+
+  /**
+   * Add a double property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter);
+
+  /**
+   * Add a string property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter);
+
+  /**
+   * Add a boolean array property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addBooleanArrayProperty(String key, Supplier<boolean[]> getter, Consumer<boolean[]> setter);
+
+  /**
+   * Add a double array property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addDoubleArrayProperty(String key, Supplier<double[]> getter, Consumer<double[]> setter);
+
+  /**
+   * Add a string array property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addStringArrayProperty(String key, Supplier<String[]> getter, Consumer<String[]> setter);
+
+  /**
+   * Add a raw property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addRawProperty(String key, Supplier<byte[]> getter, Consumer<byte[]> setter);
+
+  /**
+   * Add a NetworkTableValue property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  void addValueProperty(String key, Supplier<NetworkTableValue> getter,
+                        Consumer<NetworkTableValue> setter);
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilderImpl.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilderImpl.java
new file mode 100644
index 0000000..95d2e6c
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilderImpl.java
@@ -0,0 +1,362 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.smartdashboard;
+
+import edu.wpi.first.networktables.EntryListenerFlags;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableValue;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SendableBuilderImpl implements SendableBuilder {
+  private static class Property {
+    Property(NetworkTable table, String key) {
+      m_entry = table.getEntry(key);
+    }
+
+    @Override
+    @SuppressWarnings("NoFinalizer")
+    public synchronized void finalize() {
+      stopListener();
+    }
+
+    void startListener() {
+      if (m_entry.isValid() && m_listener == 0 && m_createListener != null) {
+        m_listener = m_createListener.apply(m_entry);
+      }
+    }
+
+    void stopListener() {
+      if (m_entry.isValid() && m_listener != 0) {
+        m_entry.removeListener(m_listener);
+        m_listener = 0;
+      }
+    }
+
+    final NetworkTableEntry m_entry;
+    int m_listener = 0;
+    Consumer<NetworkTableEntry> m_update;
+    Function<NetworkTableEntry, Integer> m_createListener;
+  }
+
+  private final List<Property> m_properties = new ArrayList<>();
+  private Runnable m_safeState;
+  private Runnable m_updateTable;
+  private NetworkTable m_table;
+
+  /**
+   * Set the network table.  Must be called prior to any Add* functions being
+   * called.
+   * @param table Network table
+   */
+  public void setTable(NetworkTable table) {
+    m_table = table;
+  }
+
+  /**
+   * Get the network table.
+   * @return The network table
+   */
+  public NetworkTable getTable() {
+    return m_table;
+  }
+
+  /**
+   * Update the network table values by calling the getters for all properties.
+   */
+  public void updateTable() {
+    for (Property property : m_properties) {
+      if (property.m_update != null) {
+        property.m_update.accept(property.m_entry);
+      }
+    }
+    if (m_updateTable != null) {
+      m_updateTable.run();
+    }
+  }
+
+  /**
+   * Hook setters for all properties.
+   */
+  public void startListeners() {
+    for (Property property : m_properties) {
+      property.startListener();
+    }
+  }
+
+  /**
+   * Unhook setters for all properties.
+   */
+  public void stopListeners() {
+    for (Property property : m_properties) {
+      property.stopListener();
+    }
+  }
+
+  /**
+   * Start LiveWindow mode by hooking the setters for all properties.  Also
+   * calls the safeState function if one was provided.
+   */
+  public void startLiveWindowMode() {
+    if (m_safeState != null) {
+      m_safeState.run();
+    }
+    startListeners();
+  }
+
+  /**
+   * Stop LiveWindow mode by unhooking the setters for all properties.  Also
+   * calls the safeState function if one was provided.
+   */
+  public void stopLiveWindowMode() {
+    stopListeners();
+    if (m_safeState != null) {
+      m_safeState.run();
+    }
+  }
+
+  /**
+   * Set the string representation of the named data type that will be used
+   * by the smart dashboard for this sendable.
+   *
+   * @param type    data type
+   */
+  @Override
+  public void setSmartDashboardType(String type) {
+    m_table.getEntry(".type").setString(type);
+  }
+
+  /**
+   * Set the function that should be called to set the Sendable into a safe
+   * state.  This is called when entering and exiting Live Window mode.
+   *
+   * @param func    function
+   */
+  @Override
+  public void setSafeState(Runnable func) {
+    m_safeState = func;
+  }
+
+  /**
+   * Set the function that should be called to update the network table
+   * for things other than properties.  Note this function is not passed
+   * the network table object; instead it should use the entry handles
+   * returned by getEntry().
+   *
+   * @param func    function
+   */
+  @Override
+  public void setUpdateTable(Runnable func) {
+    m_updateTable = func;
+  }
+
+  /**
+   * Add a property without getters or setters.  This can be used to get
+   * entry handles for the function called by setUpdateTable().
+   *
+   * @param key   property name
+   * @return Network table entry
+   */
+  @Override
+  public NetworkTableEntry getEntry(String key) {
+    return m_table.getEntry(key);
+  }
+
+  /**
+   * Add a boolean property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setBoolean(getter.getAsBoolean());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        if (event.value.isBoolean()) {
+          setter.accept(event.value.getBoolean());
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+
+  /**
+   * Add a double property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setDouble(getter.getAsDouble());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        if (event.value.isDouble()) {
+          setter.accept(event.value.getDouble());
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+
+  /**
+   * Add a string property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setString(getter.get());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        if (event.value.isString()) {
+          setter.accept(event.value.getString());
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+
+  /**
+   * Add a boolean array property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addBooleanArrayProperty(String key, Supplier<boolean[]> getter,
+                                      Consumer<boolean[]> setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setBooleanArray(getter.get());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        if (event.value.isBooleanArray()) {
+          setter.accept(event.value.getBooleanArray());
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+
+  /**
+   * Add a double array property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addDoubleArrayProperty(String key, Supplier<double[]> getter,
+                                     Consumer<double[]> setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setDoubleArray(getter.get());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        if (event.value.isDoubleArray()) {
+          setter.accept(event.value.getDoubleArray());
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+
+  /**
+   * Add a string array property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addStringArrayProperty(String key, Supplier<String[]> getter,
+                                     Consumer<String[]> setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setStringArray(getter.get());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        if (event.value.isStringArray()) {
+          setter.accept(event.value.getStringArray());
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+
+  /**
+   * Add a raw property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addRawProperty(String key, Supplier<byte[]> getter, Consumer<byte[]> setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setRaw(getter.get());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        if (event.value.isRaw()) {
+          setter.accept(event.value.getRaw());
+        }
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+
+  /**
+   * Add a NetworkTableValue property.
+   *
+   * @param key     property name
+   * @param getter  getter function (returns current value)
+   * @param setter  setter function (sets new value)
+   */
+  @Override
+  public void addValueProperty(String key, Supplier<NetworkTableValue> getter,
+                               Consumer<NetworkTableValue> setter) {
+    Property property = new Property(m_table, key);
+    if (getter != null) {
+      property.m_update = (entry) -> entry.setValue(getter.get());
+    }
+    if (setter != null) {
+      property.m_createListener = (entry) -> entry.addListener((event) -> {
+        setter.accept(event.value);
+      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+    }
+    m_properties.add(property);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java
new file mode 100644
index 0000000..0a1b1bc
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java
@@ -0,0 +1,109 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.smartdashboard;
+
+import java.util.LinkedHashMap;
+
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.wpilibj.SendableBase;
+import edu.wpi.first.wpilibj.command.Command;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * The {@link SendableChooser} class is a useful tool for presenting a selection of options to the
+ * {@link SmartDashboard}.
+ *
+ * <p>For instance, you may wish to be able to select between multiple autonomous modes. You can do
+ * this by putting every possible {@link Command} you want to run as an autonomous into a {@link
+ * SendableChooser} and then put it into the {@link SmartDashboard} to have a list of options appear
+ * on the laptop. Once autonomous starts, simply ask the {@link SendableChooser} what the selected
+ * value is.
+ *
+ * @param <V> The type of the values to be stored
+ */
+public class SendableChooser<V> extends SendableBase implements Sendable {
+  /**
+   * The key for the default value.
+   */
+  private static final String DEFAULT = "default";
+  /**
+   * The key for the selected option.
+   */
+  private static final String SELECTED = "selected";
+  /**
+   * The key for the option array.
+   */
+  private static final String OPTIONS = "options";
+  /**
+   * A map linking strings to the objects the represent.
+   */
+  private final LinkedHashMap<String, V> m_map = new LinkedHashMap<>();
+  private String m_defaultChoice = "";
+
+  /**
+   * Instantiates a {@link SendableChooser}.
+   */
+  public SendableChooser() {
+  }
+
+  /**
+   * Adds the given object to the list of options. On the {@link SmartDashboard} on the desktop, the
+   * object will appear as the given name.
+   *
+   * @param name   the name of the option
+   * @param object the option
+   */
+  public void addObject(String name, V object) {
+    m_map.put(name, object);
+  }
+
+  /**
+   * Add the given object to the list of options and marks it as the default. Functionally, this is
+   * very close to {@link #addObject(String, Object)} except that it will use this as the default
+   * option if none other is explicitly selected.
+   *
+   * @param name   the name of the option
+   * @param object the option
+   */
+  public void addDefault(String name, V object) {
+    requireNonNull(name, "Provided name was null");
+
+    m_defaultChoice = name;
+    addObject(name, object);
+  }
+
+  /**
+   * Returns the selected option. If there is none selected, it will return the default. If there is
+   * none selected and no default, then it will return {@code null}.
+   *
+   * @return the option selected
+   */
+  public V getSelected() {
+    String selected = m_defaultChoice;
+    if (m_tableSelected != null) {
+      selected = m_tableSelected.getString(m_defaultChoice);
+    }
+    return m_map.get(selected);
+  }
+
+  private NetworkTableEntry m_tableSelected;
+
+  @Override
+  public void initSendable(SendableBuilder builder) {
+    builder.setSmartDashboardType("String Chooser");
+    builder.addStringProperty(DEFAULT, () -> {
+      return m_defaultChoice;
+    }, null);
+    builder.addStringArrayProperty(OPTIONS, () -> {
+      return m_map.keySet().toArray(new String[0]);
+    }, null);
+    m_tableSelected = builder.getEntry(SELECTED);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboard.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboard.java
new file mode 100644
index 0000000..e8ab5fd
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboard.java
@@ -0,0 +1,525 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.smartdashboard;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import edu.wpi.first.wpilibj.HLUsageReporting;
+import edu.wpi.first.wpilibj.Sendable;
+
+/**
+ * The {@link SmartDashboard} class is the bridge between robot programs and the SmartDashboard on
+ * the laptop.
+ *
+ * <p>When a value is put into the SmartDashboard here, it pops up on the SmartDashboard on the
+ * laptop. Users can put values into and get values from the SmartDashboard.
+ */
+public class SmartDashboard {
+  /**
+   * The {@link NetworkTable} used by {@link SmartDashboard}.
+   */
+  private static final NetworkTable table =
+      NetworkTableInstance.getDefault().getTable("SmartDashboard");
+
+  private static class Data {
+    Data(Sendable sendable) {
+      m_sendable = sendable;
+    }
+
+    final Sendable m_sendable;
+    final SendableBuilderImpl m_builder = new SendableBuilderImpl();
+  }
+
+  /**
+   * A table linking tables in the SmartDashboard to the {@link Sendable} objects they
+   * came from.
+   */
+  private static final Map<String, Data> tablesToData = new HashMap<>();
+
+  static {
+    HLUsageReporting.reportSmartDashboard();
+  }
+
+  /**
+   * Maps the specified key to the specified value in this table. The key can not be null. The value
+   * can be retrieved by calling the get method with a key that is equal to the original key.
+   *
+   * @param key  the key
+   * @param data the value
+   * @throws IllegalArgumentException If key is null
+   */
+  public static synchronized void putData(String key, Sendable data) {
+    Data sddata = tablesToData.get(key);
+    if (sddata == null || sddata.m_sendable != data) {
+      if (sddata != null) {
+        sddata.m_builder.stopListeners();
+      }
+      sddata = new Data(data);
+      tablesToData.put(key, sddata);
+      NetworkTable dataTable = table.getSubTable(key);
+      sddata.m_builder.setTable(dataTable);
+      data.initSendable(sddata.m_builder);
+      sddata.m_builder.updateTable();
+      sddata.m_builder.startListeners();
+      dataTable.getEntry(".name").setString(key);
+    }
+  }
+
+  /**
+   * Maps the specified key (where the key is the name of the {@link NamedSendable}
+   * to the specified value in this table. The value can be retrieved by
+   * calling the get method with a key that is equal to the original key.
+   *
+   * @param value the value
+   * @throws IllegalArgumentException If key is null
+   */
+  public static void putData(Sendable value) {
+    putData(value.getName(), value);
+  }
+
+  /**
+   * Returns the value at the specified key.
+   *
+   * @param key the key
+   * @return the value
+   * @throws IllegalArgumentException  if the key is null
+   */
+  public static synchronized Sendable getData(String key) {
+    Data data = tablesToData.get(key);
+    if (data == null) {
+      throw new IllegalArgumentException("SmartDashboard data does not exist: " + key);
+    } else {
+      return data.m_sendable;
+    }
+  }
+
+  /**
+   * Gets the entry for the specified key.
+   * @param key the key name
+   * @return Network table entry.
+   */
+  public static NetworkTableEntry getEntry(String key) {
+    return table.getEntry(key);
+  }
+
+  /**
+   * Checks the table and tells if it contains the specified key.
+   *
+   * @param key the key to search for
+   * @return true if the table as a value assigned to the given key
+   */
+  public static boolean containsKey(String key) {
+    return table.containsKey(key);
+  }
+
+  /**
+   * Get the keys stored in the SmartDashboard table of NetworkTables.
+   *
+   * @param types bitmask of types; 0 is treated as a "don't care".
+   * @return keys currently in the table
+   */
+  public static Set<String> getKeys(int types) {
+    return table.getKeys(types);
+  }
+
+  /**
+   * Get the keys stored in the SmartDashboard table of NetworkTables.
+   *
+   * @return keys currently in the table.
+   */
+  public static Set<String> getKeys() {
+    return table.getKeys();
+  }
+
+  /**
+   * Makes a key's value persistent through program restarts.
+   * The key cannot be null.
+   *
+   * @param key the key name
+   */
+  public static void setPersistent(String key) {
+    getEntry(key).setPersistent();
+  }
+
+  /**
+   * Stop making a key's value persistent through program restarts.
+   * The key cannot be null.
+   *
+   * @param key the key name
+   */
+  public static void clearPersistent(String key) {
+    getEntry(key).clearPersistent();
+  }
+
+  /**
+   * Returns whether the value is persistent through program restarts.
+   * The key cannot be null.
+   *
+   * @param key the key name
+   * @return True if the value is persistent.
+   */
+  public static boolean isPersistent(String key) {
+    return getEntry(key).isPersistent();
+  }
+
+  /**
+   * Sets flags on the specified key in this table. The key can
+   * not be null.
+   *
+   * @param key the key name
+   * @param flags the flags to set (bitmask)
+   */
+  public static void setFlags(String key, int flags) {
+    getEntry(key).setFlags(flags);
+  }
+
+  /**
+   * Clears flags on the specified key in this table. The key can
+   * not be null.
+   *
+   * @param key the key name
+   * @param flags the flags to clear (bitmask)
+   */
+  public static void clearFlags(String key, int flags) {
+    getEntry(key).clearFlags(flags);
+  }
+
+  /**
+   * Returns the flags for the specified key.
+   *
+   * @param key the key name
+   * @return the flags, or 0 if the key is not defined
+   */
+  public static int getFlags(String key) {
+    return getEntry(key).getFlags();
+  }
+
+  /**
+   * Deletes the specified key in this table. The key can
+   * not be null.
+   *
+   * @param key the key name
+   */
+  public static void delete(String key) {
+    table.delete(key);
+  }
+
+  /**
+   * Put a boolean in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putBoolean(String key, boolean value) {
+    return getEntry(key).setBoolean(value);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultBoolean(String key, boolean defaultValue) {
+    return getEntry(key).setDefaultBoolean(defaultValue);
+  }
+
+  /**
+   * Returns the boolean the key maps to. If the key does not exist or is of
+   *     different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static boolean getBoolean(String key, boolean defaultValue) {
+    return getEntry(key).getBoolean(defaultValue);
+  }
+
+  /**
+   * Put a number in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putNumber(String key, double value) {
+    return getEntry(key).setDouble(value);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultNumber(String key, double defaultValue) {
+    return getEntry(key).setDefaultDouble(defaultValue);
+  }
+
+  /**
+   * Returns the number the key maps to. If the key does not exist or is of
+   *     different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static double getNumber(String key, double defaultValue) {
+    return getEntry(key).getDouble(defaultValue);
+  }
+
+  /**
+   * Put a string in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putString(String key, String value) {
+    return getEntry(key).setString(value);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultString(String key, String defaultValue) {
+    return getEntry(key).setDefaultString(defaultValue);
+  }
+
+  /**
+   * Returns the string the key maps to. If the key does not exist or is of
+   *     different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static String getString(String key, String defaultValue) {
+    return getEntry(key).getString(defaultValue);
+  }
+
+  /**
+   * Put a boolean array in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putBooleanArray(String key, boolean[] value) {
+    return getEntry(key).setBooleanArray(value);
+  }
+
+  /**
+   * Put a boolean array in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putBooleanArray(String key, Boolean[] value) {
+    return getEntry(key).setBooleanArray(value);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultBooleanArray(String key, boolean[] defaultValue) {
+    return getEntry(key).setDefaultBooleanArray(defaultValue);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultBooleanArray(String key, Boolean[] defaultValue) {
+    return getEntry(key).setDefaultBooleanArray(defaultValue);
+  }
+
+  /**
+   * Returns the boolean array the key maps to. If the key does not exist or is
+   *     of different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static boolean[] getBooleanArray(String key, boolean[] defaultValue) {
+    return getEntry(key).getBooleanArray(defaultValue);
+  }
+
+  /**
+   * Returns the boolean array the key maps to. If the key does not exist or is
+   *     of different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static Boolean[] getBooleanArray(String key, Boolean[] defaultValue) {
+    return getEntry(key).getBooleanArray(defaultValue);
+  }
+
+  /**
+   * Put a number array in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putNumberArray(String key, double[] value) {
+    return getEntry(key).setDoubleArray(value);
+  }
+
+  /**
+   * Put a number array in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putNumberArray(String key, Double[] value) {
+    return getEntry(key).setNumberArray(value);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultNumberArray(String key, double[] defaultValue) {
+    return getEntry(key).setDefaultDoubleArray(defaultValue);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultNumberArray(String key, Double[] defaultValue) {
+    return getEntry(key).setDefaultNumberArray(defaultValue);
+  }
+
+  /**
+   * Returns the number array the key maps to. If the key does not exist or is
+   *     of different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static double[] getNumberArray(String key, double[] defaultValue) {
+    return getEntry(key).getDoubleArray(defaultValue);
+  }
+
+  /**
+   * Returns the number array the key maps to. If the key does not exist or is
+   *     of different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static Double[] getNumberArray(String key, Double[] defaultValue) {
+    return getEntry(key).getDoubleArray(defaultValue);
+  }
+
+  /**
+   * Put a string array in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putStringArray(String key, String[] value) {
+    return getEntry(key).setStringArray(value);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultStringArray(String key, String[] defaultValue) {
+    return getEntry(key).setDefaultStringArray(defaultValue);
+  }
+
+  /**
+   * Returns the string array the key maps to. If the key does not exist or is
+   *     of different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static String[] getStringArray(String key, String[] defaultValue) {
+    return getEntry(key).getStringArray(defaultValue);
+  }
+
+  /**
+   * Put a raw value (byte array) in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putRaw(String key, byte[] value) {
+    return getEntry(key).setRaw(value);
+  }
+
+  /**
+   * Put a raw value (bytes from a byte buffer) in the table.
+   * @param key the key to be assigned to
+   * @param value the value that will be assigned
+   * @param len the length of the value
+   * @return False if the table key already exists with a different type
+   */
+  public static boolean putRaw(String key, ByteBuffer value, int len) {
+    return getEntry(key).setRaw(value, len);
+  }
+
+  /**
+   * Gets the current value in the table, setting it if it does not exist.
+   * @param key the key
+   * @param defaultValue the default value to set if key does not exist.
+   * @return False if the table key exists with a different type
+   */
+  public static boolean setDefaultRaw(String key, byte[] defaultValue) {
+    return getEntry(key).setDefaultRaw(defaultValue);
+  }
+
+  /**
+   * Returns the raw value (byte array) the key maps to. If the key does not
+   *     exist or is of different type, it will return the default value.
+   * @param key the key to look up
+   * @param defaultValue the value to be returned if no value is found
+   * @return the value associated with the given key or the given default value
+   *     if there is no value associated with the key
+   */
+  public static byte[] getRaw(String key, byte[] defaultValue) {
+    return getEntry(key).getRaw(defaultValue);
+  }
+
+  /**
+   * Puts all sendable data to the dashboard.
+   */
+  public static synchronized void updateValues() {
+    for (Data data : tablesToData.values()) {
+      data.m_builder.updateTable();
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/AllocationException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/AllocationException.java
new file mode 100644
index 0000000..54112a0
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/BaseSystemNotInitializedException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/BaseSystemNotInitializedException.java
new file mode 100644
index 0000000..5467782
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/BaseSystemNotInitializedException.java
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.util;
+
+
+/**
+ * Thrown if there is an error caused by a basic system or setting not being properly initialized
+ * before being used.
+ */
+public class BaseSystemNotInitializedException extends RuntimeException {
+  /**
+   * Create a new BaseSystemNotInitializedException.
+   *
+   * @param message the message to attach to the exception
+   */
+  public BaseSystemNotInitializedException(String message) {
+    super(message);
+  }
+
+  /**
+   * Create a new BaseSystemNotInitializedException using the offending class that was not set and
+   * the class that was affected.
+   *
+   * @param offender The class or interface that was not properly initialized.
+   * @param affected The class that was was affected by this missing initialization.
+   */
+  public BaseSystemNotInitializedException(Class<?> offender, Class<?> affected) {
+    super("The " + offender.getSimpleName() + " for the " + affected.getSimpleName()
+        + " was never set.");
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/BoundaryException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/BoundaryException.java
new file mode 100644
index 0000000..e348c28
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/CheckedAllocationException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/CheckedAllocationException.java
new file mode 100644
index 0000000..8f201ac
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/HalHandleException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/HalHandleException.java
new file mode 100644
index 0000000..12e5a70
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/SortedVector.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/SortedVector.java
new file mode 100644
index 0000000..999dd4f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/SortedVector.java
@@ -0,0 +1,81 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.util;
+
+import java.util.Vector;
+
+/**
+ * A vector that is sorted.
+ */
+public class SortedVector<E> extends Vector<E> {
+  /**
+   * Interface used to determine the order to place sorted objects.
+   */
+  public interface Comparator {
+
+    /**
+     * Compare the given two objects.
+     *
+     * <p>Should return -1, 0, or 1 if the first object is less than, equal to, or greater than the
+     * second, respectively.
+     *
+     * @param object1 First object to compare
+     * @param object2 Second object to compare
+     * @return -1, 0, or 1.
+     */
+    int compare(Object object1, Object object2);
+  }
+
+  private final Comparator m_comparator;
+
+  /**
+   * Create a new sorted vector and use the given comparator to determine order.
+   *
+   * @param comparator The comparator to use to determine what order to place the elements in this
+   *                   vector.
+   */
+  public SortedVector(Comparator comparator) {
+    m_comparator = comparator;
+  }
+
+  /**
+   * Adds an element in the Vector, sorted from greatest to least.
+   *
+   * @param element The element to add to the Vector
+   */
+  public void addElement(E element) {
+    int highBound = size();
+    int lowBound = 0;
+    while (highBound - lowBound > 0) {
+      int index = (highBound + lowBound) / 2;
+      int result = m_comparator.compare(element, elementAt(index));
+      if (result < 0) {
+        lowBound = index + 1;
+      } else if (result > 0) {
+        highBound = index;
+      } else {
+        lowBound = index;
+        highBound = index;
+      }
+    }
+    insertElementAt(element, lowBound);
+  }
+
+  /**
+   * Sort the vector.
+   */
+  @SuppressWarnings("unchecked")
+  public void sort() {
+    Object[] array = new Object[size()];
+    copyInto(array);
+    removeAllElements();
+    for (Object o : array) {
+      addElement((E) o);
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/UncleanStatusException.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/UncleanStatusException.java
new file mode 100644
index 0000000..1a91b82
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/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.wpilibj.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/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionPipeline.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionPipeline.java
new file mode 100644
index 0000000..2dda3f9
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionPipeline.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.vision;
+
+import org.opencv.core.Mat;
+
+/**
+ * A vision pipeline is responsible for running a group of
+ * OpenCV algorithms to extract data from an image.
+ *
+ * @see VisionRunner
+ * @see VisionThread
+ */
+public interface VisionPipeline {
+
+  /**
+   * Processes the image input and sets the result objects.
+   * Implementations should make these objects accessible.
+   */
+  void process(Mat image);
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionRunner.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionRunner.java
new file mode 100644
index 0000000..be32db6
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionRunner.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.vision;
+
+import edu.wpi.cscore.CvSink;
+import edu.wpi.cscore.VideoSource;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.RobotBase;
+import org.opencv.core.Mat;
+
+/**
+ * A vision runner is a convenient wrapper object to make it easy to run vision pipelines
+ * from robot code. The easiest  way to use this is to run it in a {@link VisionThread}
+ * and use the listener to take snapshots of the pipeline's outputs.
+ *
+ * @see VisionPipeline
+ * @see VisionThread
+ * @see edu.wpi.first.wpilibj.vision
+ */
+public class VisionRunner<P extends VisionPipeline> {
+  private final CvSink m_cvSink = new CvSink("VisionRunner CvSink");
+  private final P m_pipeline;
+  private final Mat m_image = new Mat();
+  private final Listener<? super P> m_listener;
+  private volatile boolean m_enabled = true;
+
+  /**
+   * Listener interface for a callback that should run after a pipeline has processed its input.
+   *
+   * @param <P> the type of the pipeline this listener is for
+   */
+  @FunctionalInterface
+  public interface Listener<P extends VisionPipeline> {
+
+    /**
+     * Called when the pipeline has run. This shouldn't take much time to run because it will delay
+     * later calls to the pipeline's {@link VisionPipeline#process process} method. Copying the
+     * outputs and code that uses the copies should be <i>synchronized</i> on the same mutex to
+     * prevent multiple threads from reading and writing to the same memory at the same time.
+     *
+     * @param pipeline the vision pipeline that ran
+     */
+    void copyPipelineOutputs(P pipeline);
+
+  }
+
+  /**
+   * Creates a new vision runner. It will take images from the {@code videoSource}, send them to
+   * the {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert
+   * user code when it is safe to access the pipeline's outputs.
+   *
+   * @param videoSource the video source to use to supply images for the pipeline
+   * @param pipeline    the vision pipeline to run
+   * @param listener    a function to call after the pipeline has finished running
+   */
+  public VisionRunner(VideoSource videoSource, P pipeline, Listener<? super P> listener) {
+    this.m_pipeline = pipeline;
+    this.m_listener = listener;
+    m_cvSink.setSource(videoSource);
+  }
+
+  /**
+   * Runs the pipeline one time, giving it the next image from the video source specified
+   * in the constructor. This will block until the source either has an image or throws an error.
+   * If the source successfully supplied a frame, the pipeline's image input will be set,
+   * the pipeline will run, and the listener specified in the constructor will be called to notify
+   * it that the pipeline ran.
+   *
+   * <p>This method is exposed to allow teams to add additional functionality or have their own
+   * ways to run the pipeline. Most teams, however, should just use {@link #runForever} in its own
+   * thread using a {@link VisionThread}.</p>
+   */
+  public void runOnce() {
+    if (Thread.currentThread().getId() == RobotBase.MAIN_THREAD_ID) {
+      throw new IllegalStateException(
+          "VisionRunner.runOnce() cannot be called from the main robot thread");
+    }
+    long frameTime = m_cvSink.grabFrame(m_image);
+    if (frameTime == 0) {
+      // There was an error, report it
+      String error = m_cvSink.getError();
+      DriverStation.reportError(error, true);
+    } else {
+      // No errors, process the image
+      m_pipeline.process(m_image);
+      m_listener.copyPipelineOutputs(m_pipeline);
+    }
+  }
+
+  /**
+   * A convenience method that calls {@link #runOnce()} in an infinite loop. This must
+   * be run in a dedicated thread, and cannot be used in the main robot thread because
+   * it will freeze the robot program.
+   *
+   * <p><strong>Do not call this method directly from the main thread.</strong></p>
+   *
+   * @throws IllegalStateException if this is called from the main robot thread
+   * @see VisionThread
+   */
+  public void runForever() {
+    if (Thread.currentThread().getId() == RobotBase.MAIN_THREAD_ID) {
+      throw new IllegalStateException(
+          "VisionRunner.runForever() cannot be called from the main robot thread");
+    }
+    while (m_enabled && !Thread.interrupted()) {
+      runOnce();
+    }
+  }
+
+  /**
+   * Stop a RunForever() loop.
+   */
+  public void stop() {
+    m_enabled = false;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionThread.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionThread.java
new file mode 100644
index 0000000..5eeece8
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionThread.java
@@ -0,0 +1,47 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.vision;
+
+import edu.wpi.cscore.VideoSource;
+
+/**
+ * A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread;
+ * it does not prevent the program from exiting when all other non-daemon threads
+ * have finished running.
+ *
+ * @see VisionPipeline
+ * @see VisionRunner
+ * @see Thread#setDaemon(boolean)
+ */
+public class VisionThread extends Thread {
+  /**
+   * Creates a vision thread that continuously runs a {@link VisionPipeline}.
+   *
+   * @param visionRunner the runner for a vision pipeline
+   */
+  public VisionThread(VisionRunner<?> visionRunner) {
+    super(visionRunner::runForever, "WPILib Vision Thread");
+    setDaemon(true);
+  }
+
+  /**
+   * Creates a new vision thread that continuously runs the given vision pipeline. This is
+   * equivalent to {@code new VisionThread(new VisionRunner<>(videoSource, pipeline, listener))}.
+   *
+   * @param videoSource the source for images the pipeline should process
+   * @param pipeline    the pipeline to run
+   * @param listener    the listener to copy outputs from the pipeline after it runs
+   * @param <P>         the type of the pipeline
+   */
+  public <P extends VisionPipeline> VisionThread(VideoSource videoSource,
+                                                 P pipeline,
+                                                 VisionRunner.Listener<? super P> listener) {
+    this(new VisionRunner<>(videoSource, pipeline, listener));
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/package-info.java b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/package-info.java
new file mode 100644
index 0000000..94d7101
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/package-info.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Classes in the {@code edu.wpi.first.wpilibj.vision} package are designed to
+ * simplify using OpenCV vision processing code from a robot program.
+ *
+ * <p>An example use case for grabbing a yellow tote from 2015 in autonomous:
+ * <br>
+ * <pre><code>
+ * public class Robot extends IterativeRobot
+ *     implements VisionRunner.Listener&lt;MyFindTotePipeline&gt; {
+ *
+ *      // A USB camera connected to the roboRIO.
+ *      private {@link edu.wpi.cscore.VideoSource VideoSource} usbCamera;
+ *
+ *      // A vision pipeline. This could be handwritten or generated by GRIP.
+ *      // This has to implement {@link edu.wpi.first.wpilibj.vision.VisionPipeline}.
+ *      // For this example, assume that it's perfect and will always see the tote.
+ *      private MyFindTotePipeline findTotePipeline;
+ *      private {@link edu.wpi.first.wpilibj.vision.VisionThread} findToteThread;
+ *
+ *      // The object to synchronize on to make sure the vision thread doesn't
+ *      // write to variables the main thread is using.
+ *      private final Object visionLock = new Object();
+ *
+ *      // The pipeline outputs we want
+ *      private boolean pipelineRan = false; // lets us know when the pipeline has actually run
+ *      private double angleToTote = 0;
+ *      private double distanceToTote = 0;
+ *
+ *     {@literal @}Override
+ *      public void {@link edu.wpi.first.wpilibj.vision.VisionRunner.Listener#copyPipelineOutputs
+ *          copyPipelineOutputs(MyFindTotePipeline pipeline)} {
+ *          synchronized (visionLock) {
+ *              // Take a snapshot of the pipeline's output because
+ *              // it may have changed the next time this method is called!
+ *              this.pipelineRan = true;
+ *              this.angleToTote = pipeline.getAngleToTote();
+ *              this.distanceToTote = pipeline.getDistanceToTote();
+ *          }
+ *      }
+ *
+ *     {@literal @}Override
+ *      public void robotInit() {
+ *          usbCamera = CameraServer.getInstance().startAutomaticCapture(0);
+ *          findTotePipeline = new MyFindTotePipeline();
+ *          findToteThread = new VisionThread(usbCamera, findTotePipeline, this);
+ *      }
+ *
+ *     {@literal @}Override
+ *      public void autonomousInit() {
+ *          findToteThread.start();
+ *      }
+ *
+ *     {@literal @}Override
+ *      public void autonomousPeriodic() {
+ *          double angle;
+ *          double distance;
+ *          synchronized (visionLock) {
+ *              if (!pipelineRan) {
+ *                  // Wait until the pipeline has run
+ *                  return;
+ *              }
+ *              // Copy the outputs to make sure they're all from the same run
+ *              angle = this.angleToTote;
+ *              distance = this.distanceToTote;
+ *          }
+ *          if (!aimedAtTote()) {
+ *              turnToAngle(angle);
+ *          } else if (!droveToTote()) {
+ *              driveDistance(distance);
+ *          } else if (!grabbedTote()) {
+ *              grabTote();
+ *          } else {
+ *              // Tote was grabbed and we're done!
+ *              return;
+ *          }
+ *      }
+ *
+ * }
+ * </code></pre>
+ */
+package edu.wpi.first.wpilibj.vision;
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/.styleguide b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/.styleguide
new file mode 100644
index 0000000..44ae5fb
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/.styleguide
@@ -0,0 +1,40 @@
+cppHeaderFileInclude {
+  \.h$
+  \.hpp$
+  \.inc$
+}
+
+cppSrcFileInclude {
+  \.cpp$
+}
+
+generatedFileExclude {
+  gmock/
+  ni-libraries/include/
+  ni-libraries/lib/
+  hal/src/main/native/athena/ctre/
+  hal/src/main/native/athena/frccansae/
+  hal/src/main/native/athena/visa/
+  hal/src/main/native/include/ctre/
+  UsageReporting\.h$
+}
+
+modifiableFileExclude {
+  wpilibj/src/arm-linux-jni/
+  wpilibj/src/main/native/cpp/
+  \.patch$
+  \.png$
+  \.py$
+  \.so$
+}
+
+includeOtherLibs {
+  ^HAL/
+  ^llvm/
+  ^opencv2/
+  ^support/
+}
+
+includeProject {
+  ^ctre/
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AccelerometerJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AccelerometerJNI.cpp
new file mode 100644
index 0000000..d67c084
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AccelerometerJNI.cpp
@@ -0,0 +1,69 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <jni.h>
+#include "edu_wpi_first_wpilibj_hal_AccelerometerJNI.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_AccelerometerJNI
+ * Method:    setAccelerometerActive
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_AccelerometerJNI_setAccelerometerActive(
+    JNIEnv *, jclass, jboolean active) {
+  HAL_SetAccelerometerActive(active);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_AccelerometerJNI
+ * Method:    setAccelerometerRange
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_AccelerometerJNI_setAccelerometerRange(
+    JNIEnv *, jclass, jint range) {
+  HAL_SetAccelerometerRange((HAL_AccelerometerRange)range);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_AccelerometerJNI
+ * Method:    getAccelerometerX
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_AccelerometerJNI_getAccelerometerX(
+    JNIEnv *, jclass) {
+  return HAL_GetAccelerometerX();
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_AccelerometerJNI
+ * Method:    getAccelerometerY
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_AccelerometerJNI_getAccelerometerY(
+    JNIEnv *, jclass) {
+  return HAL_GetAccelerometerY();
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_AccelerometerJNI
+ * Method:    getAccelerometerZ
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_AccelerometerJNI_getAccelerometerZ(
+    JNIEnv *, jclass) {
+  return HAL_GetAccelerometerZ();
+}
+
+}  // extern "C"
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AnalogGyroJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AnalogGyroJNI.cpp
new file mode 100644
index 0000000..f5e019f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AnalogGyroJNI.cpp
@@ -0,0 +1,219 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_AnalogGyroJNI.h"
+
+#include "HAL/AnalogGyro.h"
+#include "HALUtil.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_wpilibj_hal_AnalogGyroJNI
+ * Method:    initializeAnalogGyro
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    setupAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    freeAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    setAnalogGyroParameters
+ * Signature: (IDDI)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    setAnalogGyroVoltsPerDegreePerSecond
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    resetAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    calibrateAnalogGyro
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    setAnalogGyroDeadband
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroAngle
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroRate
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroOffset
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogGyroJNI
+ * Method:    getAnalogGyroCenter
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AnalogJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AnalogJNI.cpp
new file mode 100644
index 0000000..51a126e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/AnalogJNI.cpp
@@ -0,0 +1,656 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_AnalogJNI.h"
+
+#include "HAL/AnalogInput.h"
+#include "HAL/AnalogOutput.h"
+#include "HAL/AnalogAccumulator.h"
+#include "HAL/AnalogTrigger.h"
+#include "HAL/Ports.h"
+#include "HALUtil.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_wpilibj_hal_AnalogJNI
+ * Method:    initializeAnalogInputPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    freeAnalogInputPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    initializeAnalogOutputPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    freeAnalogOutputPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_AnalogJNI_freeAnalogOutputPort(
+    JNIEnv *env, jclass, jint id) {
+  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << id;
+  HAL_FreeAnalogOutputPort((HAL_AnalogOutputHandle)id);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_AnalogJNI
+ * Method:    checkAnalogModule
+ * Signature: (B)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    checkAnalogInputChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    checkAnalogOutputChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogOutput
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogOutput
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogSampleRate
+ * Signature: (D)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogSampleRate
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogAverageBits
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogAverageBits
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogOversampleBits
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogOversampleBits
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogValue
+ * Signature: (I)S
+ */
+JNIEXPORT jshort JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogAverageValue
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogVoltsToValue
+ * Signature: (ID)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogAverageVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogLSBWeight
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogOffset
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    isAccumulatorChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    initAccumulator
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    resetAccumulator
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAccumulatorCenter
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAccumulatorDeadband
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAccumulatorValue
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAccumulatorCount
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAccumulatorOutput
+ * Signature: (ILedu/wpi/first/wpilibj/AccumulatorResult;)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    initializeAnalogTrigger
+ * Signature: (ILjava/nio/IntBuffer;)J
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_AnalogJNI_initializeAnalogTrigger(
+    JNIEnv *env, jclass, jint id, jobject index) {
+  ANALOGJNI_LOG(logDEBUG) << "Port Handle = " << (HAL_AnalogInputHandle)id;
+  jint *indexHandle = (jint *)env->GetDirectBufferAddress(index);
+  ANALOGJNI_LOG(logDEBUG) << "Index Ptr = " << indexHandle;
+  int32_t status = 0;
+  HAL_AnalogTriggerHandle analogTrigger =
+      HAL_InitializeAnalogTrigger((HAL_AnalogInputHandle)id, (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_wpilibj_hal_AnalogJNI
+ * Method:    cleanAnalogTrigger
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogTriggerLimitsRaw
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogTriggerLimitsVoltage
+ * Signature: (IDD)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogTriggerAveraged
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    setAnalogTriggerFiltered
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogTriggerInWindow
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogTriggerTriggerState
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_AnalogJNI
+ * Method:    getAnalogTriggerOutput
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CANJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CANJNI.cpp
new file mode 100644
index 0000000..8b2ec9e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CANJNI.cpp
@@ -0,0 +1,153 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+
+#include "HAL/cpp/Log.h"
+#include "HAL/CAN.h"
+#include "HALUtil.h"
+#include "edu_wpi_first_wpilibj_can_CANJNI.h"
+#include "llvm/SmallString.h"
+#include "llvm/raw_ostream.h"
+#include "support/jni_util.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_wpilibj_can_CANJNI
+ * Method:    FRCNetCommCANSessionMuxSendMessage
+ * Signature: (I[BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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) {
+      llvm::SmallString<128> buf;
+      llvm::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_wpilibj_can_CANJNI
+ * Method:    FRCNetCommCANSessionMuxReceiveMessage
+ * Signature: (Ljava/nio/IntBuffer;ILjava/nio/ByteBuffer;)[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_edu_wpi_first_wpilibj_can_CANJNI_FRCNetCommCANSessionMuxReceiveMessage(
+    JNIEnv *env, jclass, jobject messageID, jint messageIDMask,
+    jobject timeStamp) {
+
+  CANJNI_LOG(logDEBUG)
+      << "Calling CANJNI FRCNetCommCANSessionMuxReceiveMessage";
+
+  uint32_t *messageIDPtr = (uint32_t *)env->GetDirectBufferAddress(messageID);
+  uint32_t *timeStampPtr = (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) {
+    llvm::SmallString<128> buf;
+    llvm::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, llvm::StringRef{reinterpret_cast<const char*>(buffer), 
+                        static_cast<size_t>(dataSize)});
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_can_CANJNI
+ * Method:    GetCANStatus
+ * Signature: (Ledu/wpi/first/wpilibj/can/CANStatus;)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CompressorJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CompressorJNI.cpp
new file mode 100644
index 0000000..31cc8d8
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CompressorJNI.cpp
@@ -0,0 +1,211 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 "HAL/Ports.h"
+#include "HAL/Solenoid.h"
+#include "HALUtil.h"
+#include "HAL/cpp/Log.h"
+#include "edu_wpi_first_wpilibj_hal_CompressorJNI.h"
+
+using namespace frc;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_CompressorJNI
+ * Method:    initializeCompressor
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    checkCompressorModule
+ * Signature: (B)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_CompressorJNI_checkCompressorModule(
+    JNIEnv *env, jclass, jbyte module) {
+  return HAL_CheckCompressorModule(module);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_CompressorJNI
+ * Method:    getCompressor
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    setCompressorClosedLoopControl
+ * Signature: (JZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorClosedLoopControl
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorPressureSwitch
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorCurrent
+ * Signature: (J)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorCurrentTooHighFault
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorCurrentTooHighStickyFault
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorShortedStickyFault
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorShortedFault
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorNotConnectedStickyFault
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    getCompressorNotConnectedFault
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CompressorJNI
+ * Method:    clearAllPCMStickyFaults
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_CompressorJNI_clearAllPCMStickyFaults(
+    JNIEnv *env, jclass, jbyte module) {
+  int32_t status = 0;
+  HAL_ClearAllPCMStickyFaults((uint8_t)module, &status);
+  CheckStatus(env, status);
+}
+
+}  // extern "C"
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/ConstantsJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/ConstantsJNI.cpp
new file mode 100644
index 0000000..e1eb416
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/ConstantsJNI.cpp
@@ -0,0 +1,42 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_ConstantsJNI.h"
+
+#include "HAL/Constants.h"
+#include "HALUtil.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_wpilibj_hal_ConstantsJNI
+ * Method:    getSystemClockTicksPerMicrosecond
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_ConstantsJNI_getSystemClockTicksPerMicrosecond(
+    JNIEnv *env, jclass) {
+  CONSTANTSJNI_LOG(logDEBUG) << "Calling ConstantsJNI getSystemClockTicksPerMicrosecond";
+  jint value = HAL_GetSystemClockTicksPerMicrosecond();
+  CONSTANTSJNI_LOG(logDEBUG) << "Value = " << value;
+  return value;
+}
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CounterJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CounterJNI.cpp
new file mode 100644
index 0000000..d43bb78
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/CounterJNI.cpp
@@ -0,0 +1,443 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_CounterJNI.h"
+
+#include "HAL/Counter.h"
+#include "HAL/Errors.h"
+#include "HALUtil.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_wpilibj_hal_CounterJNI
+ * Method:    initializeCounter
+ * Signature: (ILjava/nio/IntBuffer;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_CounterJNI_initializeCounter(
+    JNIEnv* env, jclass, jint mode, jobject index) {
+  COUNTERJNI_LOG(logDEBUG) << "Calling COUNTERJNI initializeCounter";
+  COUNTERJNI_LOG(logDEBUG) << "Mode = " << mode;
+  jint* indexPtr = (jint*)env->GetDirectBufferAddress(index);
+  COUNTERJNI_LOG(logDEBUG) << "Index Ptr = " << (int32_t*)indexPtr;
+  int32_t status = 0;
+  auto counter = HAL_InitializeCounter((HAL_Counter_Mode)mode, (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_wpilibj_hal_CounterJNI
+ * Method:    freeCounter
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterAverageSize
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterUpSource
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterUpSourceEdge
+ * Signature: (IZZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    clearCounterUpSource
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterDownSource
+ * Signature: (IIZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterDownSourceEdge
+ * Signature: (IZZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    clearCounterDownSource
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterUpDownMode
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterExternalDirectionMode
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterSemiPeriodMode
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterPulseLengthMode
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    getCounterSamplesToAverage
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterSamplesToAverage
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    resetCounter
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    getCounter
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    getCounterPeriod
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterMaxPeriod
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterUpdateWhenEmpty
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    getCounterStopped
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    getCounterDirection
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_CounterJNI
+ * Method:    setCounterReverseDirection
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/DIOJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/DIOJNI.cpp
new file mode 100644
index 0000000..16048df
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/DIOJNI.cpp
@@ -0,0 +1,273 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_DIOJNI.h"
+
+#include "HAL/DIO.h"
+#include "HAL/PWM.h"
+#include "HALUtil.h"
+#include "HAL/Ports.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_wpilibj_hal_DIOJNI
+ * Method:    initializeDIOPort
+ * Signature: (IZ)I;
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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, (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_wpilibj_hal_DIOJNI
+ * Method:    checkDIOChannel
+ * Signature: (I)Z;
+*/
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    freeDIOPort
+ * Signature: (I)V;
+*/
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    setDIO
+ * Signature: (IS)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    getDIO
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    getDIODirection
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    pulse
+ * Signature: (JD)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    isPulsing
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    isAnyPulsing
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    getLoopTiming
+ * Signature: ()S
+ */
+JNIEXPORT jshort JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    allocateDigitalPWM
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    freeDigitalPWM
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    setDigitalPWMRate
+ * Signature: (D)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    setDigitalPWMDutyCycle
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+ * Method:    setDigitalPWMOutputChannel
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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, (uint32_t)value, &status);
+  DIOJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+}  // extern "C"
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/DigitalGlitchFilterJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/DigitalGlitchFilterJNI.cpp
new file mode 100644
index 0000000..8e5ed23
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/DigitalGlitchFilterJNI.cpp
@@ -0,0 +1,70 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 "HAL/DIO.h"
+#include "HALUtil.h"
+
+#include "edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI.h"
+
+using namespace frc;
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI
+ * Method:    setFilterSelect
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DigitalGlitchFilterJNI
+ * Method:    getFilterSelect
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DigitalGlitchFilterJNI
+ * Method:    setFilterPeriod
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DigitalGlitchFilterJNI
+ * Method:    getFilterPeriod
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/EncoderJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/EncoderJNI.cpp
new file mode 100644
index 0000000..9a0791e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/EncoderJNI.cpp
@@ -0,0 +1,454 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_EncoderJNI.h"
+
+#include "HAL/Encoder.h"
+#include "HAL/Errors.h"
+#include "HALUtil.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_wpilibj_hal_EncoderJNI
+ * Method:    initializeEncoder
+ * Signature: (IIIIZI)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    freeEncoder
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderRaw
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncodingScaleFactor
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    resetEncoder
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderPeriod
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    setEncoderMaxPeriod
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderStopped
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderDirection
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderDistance
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderRate
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    setEncoderMinRate
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    setEncoderDistancePerPulse
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    setEncoderReverseDirection
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    setEncoderSamplesToAverage
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderSamplesToAverage
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    setEncoderIndexSource
+ * Signature: (IIII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderFPGAIndex
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderEncodingScale
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderDecodingScaleFactor
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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;
+  jint 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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderDistancePerPulse
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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;
+  jint 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_wpilibj_hal_EncoderJNI
+ * Method:    getEncoderEncodingType
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HAL.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HAL.cpp
new file mode 100644
index 0000000..6634e9e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HAL.cpp
@@ -0,0 +1,402 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "HAL/HAL.h"
+#include "HAL/DriverStation.h"
+#include "edu_wpi_first_wpilibj_hal_HAL.h"
+#include "HALUtil.h"
+#include "support/jni_util.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_wpilibj_hal_HAL
+ * Method:    Initialize
+ * Signature: (Z)II
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_initialize(JNIEnv*, jclass, jint timeout, jint mode) {
+  return HAL_Initialize(timeout, mode);
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    observeUserProgramStarting
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_observeUserProgramStarting(JNIEnv*, jclass) {
+  HAL_ObserveUserProgramStarting();
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    observeUserProgramDisabled
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_observeUserProgramDisabled(JNIEnv*, jclass) {
+  HAL_ObserveUserProgramDisabled();
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    observeUserProgramAutonomous
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_observeUserProgramAutonomous(
+    JNIEnv*, jclass) {
+  HAL_ObserveUserProgramAutonomous();
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    observeUserProgramTeleop
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_observeUserProgramTeleop(JNIEnv*, jclass) {
+  HAL_ObserveUserProgramTeleop();
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    observeUserProgramTest
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_observeUserProgramTest(JNIEnv*, jclass) {
+  HAL_ObserveUserProgramTest();
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_Report
+ * Signature: (IIILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HAL
+ * Method:    NativeGetControlWord
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HAL
+ * Method:    NativeGetAllianceStation
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HAL
+ * Method:    HAL_GetJoystickAxes
+ * Signature: (B[F)S
+ */
+JNIEXPORT jshort JNICALL
+Java_edu_wpi_first_wpilibj_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)
+  {
+    ThrowIllegalArgumentException(env, "Native array size larger then passed in java array size");
+  }
+
+  env->SetFloatArrayRegion(axesArray, 0, axes.count, axes.axes);
+
+  return axes.count;
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_GetJoystickPOVs
+ * Signature: (B[S)S
+ */
+JNIEXPORT jshort JNICALL
+Java_edu_wpi_first_wpilibj_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)
+  {
+    ThrowIllegalArgumentException(env, "Native array size larger then passed in java array size");
+  }
+
+  env->SetShortArrayRegion(povsArray, 0, povs.count, povs.povs);
+
+  return povs.count;
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_GetJoystickButtons
+ * Signature: (BL)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getJoystickButtons(JNIEnv* env, jclass,
+                                                      jbyte joystickNum,
+                                                      jobject count) {
+  NETCOMM_LOG(logDEBUG) << "Calling HALJoystickButtons";
+  HAL_JoystickButtons joystickButtons;
+  HAL_GetJoystickButtons(joystickNum, &joystickButtons);
+  jbyte *countPtr = (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_wpilibj_hal_HAL
+ * Method:    HAL_SetJoystickOutputs
+ * Signature: (BISS)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HAL
+ * Method:    HAL_GetJoystickIsXbox
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getJoystickIsXbox(JNIEnv*, jclass,
+                                                     jbyte port) {
+  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickIsXbox";
+  return HAL_GetJoystickIsXbox(port);
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_GetJoystickType
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getJoystickType(JNIEnv*, jclass,
+                                                   jbyte port) {
+  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickType";
+  return HAL_GetJoystickType(port);
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_GetJoystickName
+ * Signature: (B)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HAL
+ * Method:    HAL_GetJoystickAxisType
+ * Signature: (BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getJoystickAxisType(JNIEnv*, jclass,
+                                                       jbyte joystickNum,
+                                                       jbyte axis) {
+  NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickAxisType";
+  return HAL_GetJoystickAxisType(joystickNum, axis);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_HAL
+ * Method:    isNewControlData
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_isNewControlData(JNIEnv *, jclass) {
+  return static_cast<jboolean>(HAL_IsNewControlData());
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    waitForDSData
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_waitForDSData(JNIEnv* env, jclass) {
+  HAL_WaitForDSData();
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    releaseDSMutex
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_releaseDSMutex(JNIEnv* env, jclass) {
+  HAL_ReleaseDSMutex();
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_HAL
+ * Method:    waitForDSDataTimeout
+ * Signature: (D)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_waitForDSDataTimeout(JNIEnv *, jclass,
+                                                        jdouble timeout) {
+  return static_cast<jboolean>(HAL_WaitForDSDataTimeout(timeout));
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_GetMatchTime
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getMatchTime(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  return HAL_GetMatchTime(&status);
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_GetSystemActive
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getSystemActive(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  bool val = HAL_GetSystemActive(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_GetBrownedOut
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getBrownedOut(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  bool val = HAL_GetBrownedOut(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_HAL
+ * Method:    getMatchInfo
+ * Signature: (Ledu/wpi/first/wpilibj/hal/MatchInfoData;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_HAL_getMatchInfo
+(JNIEnv * env, jclass, jobject info) {
+  HAL_MatchInfo matchInfo;
+  auto status = HAL_GetMatchInfo(&matchInfo);
+  if (status == 0) {
+    SetMatchInfoObject(env, info, matchInfo);
+  }
+  HAL_FreeMatchInfo(&matchInfo);
+  return status;
+}
+
+/*
+ * Class: edu_wpi_first_wpilibj_hal_HAL
+ * Method:    HAL_SendError
+ * Signature: (ZIZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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;
+}
+
+}  // extern "C"
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HALUtil.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HALUtil.cpp
new file mode 100644
index 0000000..2680422
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HALUtil.cpp
@@ -0,0 +1,445 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <errno.h>
+#include <jni.h>
+
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+#include "HAL/CAN.h"
+#include "HAL/HAL.h"
+#include "HAL/DriverStation.h"
+#include "HAL/Errors.h"
+#include "HAL/cpp/Log.h"
+#include "edu_wpi_first_wpilibj_hal_HALUtil.h"
+#include "llvm/SmallString.h"
+#include "llvm/raw_ostream.h"
+#include "support/jni_util.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
+
+JavaVM *jvm = nullptr;
+static JException runtimeExCls;
+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;
+
+namespace frc {
+
+void ThrowAllocationException(JNIEnv *env, int32_t minRange, int32_t maxRange,
+    int32_t requestedValue, int32_t status) {
+  const char *message = HAL_GetErrorMessage(status);
+  llvm::SmallString<1024> buf;
+  llvm::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);
+  llvm::SmallString<1024> buf;
+  llvm::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) {
+    llvm::SmallString<1024> buf;
+    llvm::raw_svector_ostream oss(buf);
+    oss << " Code: " << status << ". " << message;
+    runtimeExCls.Throw(env, buf.c_str());
+  } 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);
+  llvm::SmallString<1024> buf;
+  llvm::raw_svector_ostream oss(buf);
+  oss << " Code: " << status << ". " << message;
+  runtimeExCls.Throw(env, buf.c_str());
+}
+
+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: {
+      llvm::SmallString<100> buf;
+      llvm::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: {
+      llvm::SmallString<100> buf;
+      llvm::raw_svector_ostream oss(buf);
+      oss << "Fatal status code detected: " << status;
+      uncleanStatusExCls.Throw(env, buf.c_str());
+      break;
+    }
+  }
+}
+
+void ThrowIllegalArgumentException(JNIEnv *env, const char *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->CallObjectMethod(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->CallObjectMethod(matchStatus, func,
+      MakeJString(env, matchInfo.eventName),
+      MakeJString(env, matchInfo.gameSpecificMessage),
+      (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->CallObjectMethod(accumulatorResult, func, (jlong)value, (jlong)count);
+}
+
+}  // namespace frc
+
+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;
+
+  runtimeExCls = JException(env, "java/lang/RuntimeException");
+  if (!runtimeExCls) return JNI_ERR;
+
+  illegalArgExCls = JException(env, "java/lang/IllegalArgumentException");
+  if (!illegalArgExCls) return JNI_ERR;
+
+  boundaryExCls = JException(env, "edu/wpi/first/wpilibj/util/BoundaryException");
+  if (!boundaryExCls) return JNI_ERR;
+
+  allocationExCls = JException(env, "edu/wpi/first/wpilibj/util/AllocationException");
+  if (!allocationExCls) return JNI_ERR;
+
+  halHandleExCls = JException(env, "edu/wpi/first/wpilibj/util/HalHandleException");
+  if (!halHandleExCls) return JNI_ERR;
+
+  canInvalidBufferExCls = JException(env, "edu/wpi/first/wpilibj/can/CANInvalidBufferException");
+  if (!canInvalidBufferExCls) return JNI_ERR;
+
+  canMessageNotFoundExCls = JException(env, "edu/wpi/first/wpilibj/can/CANMessageNotFoundException");
+  if (!canMessageNotFoundExCls) return JNI_ERR;
+
+  canMessageNotAllowedExCls = JException(env, "edu/wpi/first/wpilibj/can/CANMessageNotAllowedException");
+  if (!canMessageNotAllowedExCls) return JNI_ERR;
+
+  canNotInitializedExCls = JException(env, "edu/wpi/first/wpilibj/can/CANNotInitializedException");
+  if (!canNotInitializedExCls) return JNI_ERR;
+
+  uncleanStatusExCls = JException(env,"edu/wpi/first/wpilibj/util/UncleanStatusException");
+  if (!uncleanStatusExCls) return JNI_ERR;
+
+  pwmConfigDataResultCls = JClass(env, "edu/wpi/first/wpilibj/PWMConfigDataResult");
+  if (!pwmConfigDataResultCls) return JNI_ERR;
+
+  canStatusCls = JClass(env, "edu/wpi/first/wpilibj/can/CANStatus");
+  if (!canStatusCls) return JNI_ERR;
+
+  matchInfoDataCls = JClass(env, "edu/wpi/first/wpilibj/hal/MatchInfoData");
+  if (!matchInfoDataCls) return JNI_ERR;
+
+  accumulatorResultCls = JClass(env, "edu/wpi/first/wpilibj/AccumulatorResult");
+  if (!accumulatorResultCls) return JNI_ERR;
+
+  return JNI_VERSION_1_6;
+}
+
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
+  JNIEnv *env;
+  if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK)
+    return;
+  // Delete global references
+  runtimeExCls.free(env);
+  illegalArgExCls.free(env);
+  boundaryExCls.free(env);
+  allocationExCls.free(env);
+  halHandleExCls.free(env);
+  canInvalidBufferExCls.free(env);
+  canMessageNotFoundExCls.free(env);
+  canMessageNotAllowedExCls.free(env);
+  canNotInitializedExCls.free(env);
+  uncleanStatusExCls.free(env);
+  pwmConfigDataResultCls.free(env);
+  canStatusCls.free(env);
+  matchInfoDataCls.free(env);
+  jvm = nullptr;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_HALUtil
+ * Method:    getFPGAVersion
+ * Signature: ()S
+ */
+JNIEXPORT jshort JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HALUtil
+ * Method:    getFPGARevision
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HALUtil
+ * Method:    getFPGATime
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HALUtil
+ * Method:    getHALRuntimeType
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HALUtil
+ * Method:    getFPGAButton
+ * Signature: ()I
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HALUtil
+ * Method:    getHALErrorMessage
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_HALUtil
+ * Method:    getHALErrno
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_HALUtil_getHALErrno(JNIEnv *, jclass) {
+  return errno;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_HALUtil
+ * Method:    getHALstrerror
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_edu_wpi_first_wpilibj_hal_HALUtil_getHALstrerror(
+    JNIEnv *env, jclass, jint errorCode) {
+  const char *msg = strerror(errno);
+  HALUTIL_LOG(logDEBUG) << "Calling HALUtil getHALstrerror errorCode="
+                        << errorCode << " msg=" << msg;
+  return MakeJString(env, msg);
+}
+
+}  // extern "C"
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HALUtil.h b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HALUtil.h
new file mode 100644
index 0000000..9feed50
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/HALUtil.h
@@ -0,0 +1,71 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 HALUTIL_H
+#define HALUTIL_H
+
+#include <stdint.h>
+
+#include <jni.h>
+
+extern JavaVM *jvm;
+
+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, const char *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);
+
+}  // namespace frc
+
+#endif  // HALUTIL_H
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/I2CJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/I2CJNI.cpp
new file mode 100644
index 0000000..771f9e4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/I2CJNI.cpp
@@ -0,0 +1,196 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_I2CJNI.h"
+
+#include "HAL/I2C.h"
+#include "HALUtil.h"
+#include "support/jni_util.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_wpilibj_hal_I2CJNI
+ * Method:    i2cInitialize
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_I2CJNI
+ * Method:    i2CTransaction
+ * Signature: (IBLjava/nio/ByteBuffer;BLjava/nio/ByteBuffer;B)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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 = (uint8_t*)env->GetDirectBufferAddress(dataToSend);
+  }
+  I2CJNI_LOG(logDEBUG) << "DataToSendPtr = " << (jint*)dataToSendPtr;
+  I2CJNI_LOG(logDEBUG) << "SendSize = " << (jint)sendSize;
+  uint8_t* dataReceivedPtr =
+      (uint8_t*)env->GetDirectBufferAddress(dataReceived);
+  I2CJNI_LOG(logDEBUG) << "DataReceivedPtr = " << (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_wpilibj_hal_I2CJNI
+ * Method:    i2CTransactionB
+ * Signature: (IB[BB[BB)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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;
+  llvm::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_wpilibj_hal_I2CJNI
+ * Method:    i2CWrite
+ * Signature: (IBLjava/nio/ByteBuffer;B)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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 = (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_wpilibj_hal_I2CJNI
+ * Method:    i2CWriteB
+ * Signature: (IB[BB)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_I2CJNI
+ * Method:    i2CRead
+ * Signature: (IBLjava/nio/ByteBuffer;B)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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 =
+      (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_wpilibj_hal_I2CJNI
+ * Method:    i2CReadB
+ * Signature: (IB[BB)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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;
+  llvm::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_wpilibj_hal_I2CJNI
+ * Method:    i2CClose
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/InterruptJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/InterruptJNI.cpp
new file mode 100644
index 0000000..6150116
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/InterruptJNI.cpp
@@ -0,0 +1,347 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include <atomic>
+#include <thread>
+
+#include <support/mutex.h>
+
+#include "HAL/cpp/Log.h"
+
+#include "HAL/Interrupts.h"
+#include "HALUtil.h"
+#include "edu_wpi_first_wpilibj_hal_InterruptJNI.h"
+#include "support/SafeThread.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 = jvm->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);
+
+  jvm->DetachCurrentThread();
+}
+
+void interruptHandler(uint32_t mask, void* param) {
+  static_cast<InterruptJNI*>(param)->Notify(mask);
+}
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_InterruptJNI
+ * Method:    initializeInterrupts
+ * Signature: (Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_InterruptJNI_initializeInterrupts(
+    JNIEnv* env, jclass, jboolean watcher) {
+  INTERRUPTJNI_LOG(logDEBUG) << "Calling INTERRUPTJNI initializeInterrupts";
+  INTERRUPTJNI_LOG(logDEBUG) << "watcher = " << (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_wpilibj_hal_InterruptJNI
+ * Method:    cleanInterrupts
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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;
+  HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle, &status);
+
+  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
+
+  // ignore status, as an invalid handle just needs to be ignored.
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_InterruptJNI
+ * Method:    waitForInterrupt
+ * Signature: (JD)V
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_InterruptJNI
+ * Method:    enableInterrupts
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_InterruptJNI
+ * Method:    disableInterrupts
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_InterruptJNI
+ * Method:    readInterruptRisingTimestamp
+ * Signature: (J)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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;
+  jdouble timeStamp = HAL_ReadInterruptRisingTimestamp((HAL_InterruptHandle)interruptHandle, &status);
+
+  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+  return timeStamp;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_InterruptJNI
+ * Method:    readInterruptFallingTimestamp
+ * Signature: (J)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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;
+  jdouble timeStamp = HAL_ReadInterruptFallingTimestamp((HAL_InterruptHandle)interruptHandle, &status);
+
+  INTERRUPTJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+  return timeStamp;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_InterruptJNI
+ * Method:    requestInterrupts
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_InterruptJNI
+ * Method:    attachInterruptHandler
+ * Signature:
+ * (JLedu/wpi/first/wpilibj/hal/InterruptJNI/InterruptHandlerFunction;Ljava/nio/ByteBuffer;)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_InterruptJNI
+ * Method:    setInterruptUpSourceEdge
+ * Signature: (JZZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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 = " << (bool)risingEdge;
+  INTERRUPTJNI_LOG(logDEBUG) << "Falling Edge = " << (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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/JNIWrapper.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/JNIWrapper.cpp
new file mode 100644
index 0000000..bf3e717
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/JNIWrapper.cpp
@@ -0,0 +1,48 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_JNIWrapper.h"
+
+#include "HAL/HAL.h"
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_JNIWrapper
+ * Method:    getPortWithModule
+ * Signature: (BB)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_JNIWrapper_getPortWithModule(
+    JNIEnv* env, jclass, jbyte module, jbyte channel) {
+  // FILE_LOG(logDEBUG) << "Calling JNIWrapper 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_wpilibj_hal_JNIWrapper
+ * Method:    getPort
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_JNIWrapper_getPort(
+    JNIEnv* env, jclass, jbyte channel) {
+  // FILE_LOG(logDEBUG) << "Calling JNIWrapper 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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/NotifierJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/NotifierJNI.cpp
new file mode 100644
index 0000000..b55bddc
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/NotifierJNI.cpp
@@ -0,0 +1,147 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include <stdio.h>
+#include "HALUtil.h"
+#include "HAL/cpp/Log.h"
+#include "edu_wpi_first_wpilibj_hal_NotifierJNI.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_wpilibj_hal_NotifierJNI
+ * Method:    initializeNotifier
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_NotifierJNI
+ * Method:    stopNotifier
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_NotifierJNI
+ * Method:    cleanNotifier
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_NotifierJNI
+ * Method:    updateNotifierAlarm
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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, (uint64_t)triggerTime, &status);
+  NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_NotifierJNI
+ * Method:    cancelNotifierAlarm
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_NotifierJNI
+ * Method:    waitForNotifierAlarm
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/OSSerialPortJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/OSSerialPortJNI.cpp
new file mode 100644
index 0000000..375e5bc
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/OSSerialPortJNI.cpp
@@ -0,0 +1,322 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_OSSerialPortJNI.h"
+
+#include "HAL/OSSerialPort.h"
+#include "HALUtil.h"
+#include "support/jni_util.h"
+
+using namespace frc;
+using namespace wpi::java;
+
+// set the logging level
+TLogLevel osserialJNILogLevel = logWARNING;
+
+#define SERIALJNI_LOG(level)       \
+  if (level > osserialJNILogLevel) \
+    ;                              \
+  else                             \
+  Log().Get(level)
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialInitializePort
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialInitializePort(
+    JNIEnv* env, jclass, jbyte port) {
+  SERIALJNI_LOG(logDEBUG) << "Calling Serial Initialize";
+  SERIALJNI_LOG(logDEBUG) << "Port = " << (jint)port;
+  int32_t status = 0;
+  HAL_InitializeOSSerialPort(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatusForceThrow(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetBaudRate
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_SetOSSerialBaudRate(static_cast<HAL_SerialPort>(port), rate, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetDataBits
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_SetOSSerialDataBits(static_cast<HAL_SerialPort>(port), bits, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetParity
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialSetParity(
+    JNIEnv* env, jclass, jbyte port, jbyte parity) {
+  SERIALJNI_LOG(logDEBUG) << "Setting Serial Parity";
+  SERIALJNI_LOG(logDEBUG) << "Parity: " << parity;
+  int32_t status = 0;
+  HAL_SetOSSerialParity(static_cast<HAL_SerialPort>(port), parity, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetStopBits
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_SetOSSerialStopBits(static_cast<HAL_SerialPort>(port), bits, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetWriteMode
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_SetOSSerialWriteMode(static_cast<HAL_SerialPort>(port), mode, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetFlowControl
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_SetOSSerialFlowControl(static_cast<HAL_SerialPort>(port), flow, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetTimeout
+ * Signature: (BD)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialSetTimeout(
+    JNIEnv* env, jclass, jbyte port, jdouble timeout) {
+  SERIALJNI_LOG(logDEBUG) << "Setting Serial Timeout";
+  SERIALJNI_LOG(logDEBUG) << "Timeout: " << timeout;
+  int32_t status = 0;
+  HAL_SetOSSerialTimeout(static_cast<HAL_SerialPort>(port), timeout, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialEnableTermination
+ * Signature: (BC)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_EnableOSSerialTermination(static_cast<HAL_SerialPort>(port), terminator, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialDisableTermination
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialDisableTermination(
+    JNIEnv* env, jclass, jbyte port) {
+  SERIALJNI_LOG(logDEBUG) << "Setting Serial Disable termination";
+  int32_t status = 0;
+  HAL_DisableOSSerialTermination(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetReadBufferSize
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_SetOSSerialReadBufferSize(static_cast<HAL_SerialPort>(port), size, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialSetWriteBufferSize
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_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_SetOSSerialWriteBufferSize(static_cast<HAL_SerialPort>(port), size, &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialGetBytesReceived
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialGetBytesReceived(
+    JNIEnv* env, jclass, jbyte port) {
+  SERIALJNI_LOG(logDEBUG) << "Serial Get Bytes Received";
+  int32_t status = 0;
+  jint retVal = HAL_GetOSSerialBytesReceived(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+  return retVal;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialRead
+ * Signature: (B[BI)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialRead(
+    JNIEnv* env, jclass, jbyte port, jbyteArray dataReceived, jint size) {
+  SERIALJNI_LOG(logDEBUG) << "Serial Read";
+  llvm::SmallVector<char, 128> recvBuf;
+  recvBuf.resize(size);
+  int32_t status = 0;
+  jint retVal = HAL_ReadOSSerial(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_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialWrite
+ * Signature: (B[BI)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialWrite(
+    JNIEnv* env, jclass, jbyte port, jbyteArray dataToSend, jint size) {
+  SERIALJNI_LOG(logDEBUG) << "Serial Write";
+  int32_t status = 0;
+  jint retVal =
+      HAL_WriteOSSerial(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_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialFlush
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialFlush(
+    JNIEnv* env, jclass, jbyte port) {
+  SERIALJNI_LOG(logDEBUG) << "Serial Flush";
+  int32_t status = 0;
+  HAL_FlushOSSerial(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialClear
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialClear(
+    JNIEnv* env, jclass, jbyte port) {
+  SERIALJNI_LOG(logDEBUG) << "Serial Clear";
+  int32_t status = 0;
+  HAL_ClearOSSerial(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_OSSerialPortJNI
+ * Method:    serialClose
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_OSSerialPortJNI_serialClose(
+    JNIEnv* env, jclass, jbyte port) {
+  SERIALJNI_LOG(logDEBUG) << "Serial Close";
+  int32_t status = 0;
+  HAL_CloseOSSerial(static_cast<HAL_SerialPort>(port), &status);
+  SERIALJNI_LOG(logDEBUG) << "Status = " << status;
+  CheckStatus(env, status);
+}
+
+}  // extern "C"
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PDPJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PDPJNI.cpp
new file mode 100644
index 0000000..54ea857
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PDPJNI.cpp
@@ -0,0 +1,158 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 "HAL/Ports.h"
+#include "HALUtil.h"
+#include "edu_wpi_first_wpilibj_hal_PDPJNI.h"
+
+using namespace frc;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    getPDPTemperature
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_PDPJNI_initializePDP(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  HAL_InitializePDP(module, &status);
+  CheckStatusRange(env, status, 0, HAL_GetNumPDPModules(), module);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    checkPDPChannel
+ * Signature: (I)Z;
+*/
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_hal_PDPJNI_checkPDPChannel(
+    JNIEnv *env, jclass, jint channel) {
+  return HAL_CheckPDPChannel(channel);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    checkPDPModule
+ * Signature: (I)Z;
+*/
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_hal_PDPJNI_checkPDPModule(
+    JNIEnv *env, jclass, jint module) {
+  return HAL_CheckPDPModule(module);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    getPDPTemperature
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PDPJNI_getPDPTemperature(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  double temperature = HAL_GetPDPTemperature(module, &status);
+  CheckStatus(env, status, false);
+  return temperature;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    getPDPVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL Java_edu_wpi_first_wpilibj_hal_PDPJNI_getPDPVoltage(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  double voltage = HAL_GetPDPVoltage(module, &status);
+  CheckStatus(env, status, false);
+  return voltage;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    getPDPChannelCurrent
+ * Signature: (BI)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PDPJNI_getPDPChannelCurrent(
+    JNIEnv *env, jclass, jbyte channel, jint module) {
+  int32_t status = 0;
+  double current = HAL_GetPDPChannelCurrent(module, channel, &status);
+  CheckStatus(env, status, false);
+  return current;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    getPDPTotalCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PDPJNI_getPDPTotalCurrent(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  double current = HAL_GetPDPTotalCurrent(module, &status);
+  CheckStatus(env, status, false);
+  return current;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    getPDPTotalPower
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PDPJNI_getPDPTotalPower(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  double power = HAL_GetPDPTotalPower(module, &status);
+  CheckStatus(env, status, false);
+  return power;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    resetPDPTotalEnergy
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PDPJNI_getPDPTotalEnergy(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  double energy = HAL_GetPDPTotalEnergy(module, &status);
+  CheckStatus(env, status, false);
+  return energy;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    resetPDPTotalEnergy
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_PDPJNI_resetPDPTotalEnergy(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  HAL_ResetPDPTotalEnergy(module, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PDPJNI
+ * Method:    clearStickyFaults
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_PDPJNI_clearPDPStickyFaults(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  HAL_ClearPDPStickyFaults(module, &status);
+  CheckStatus(env, status, false);
+}
+
+}  // extern "C"
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PWMJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PWMJNI.cpp
new file mode 100644
index 0000000..3869176
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PWMJNI.cpp
@@ -0,0 +1,300 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_PWMJNI.h"
+
+#include "HAL/DIO.h"
+#include "HAL/PWM.h"
+#include "HAL/Ports.h"
+#include "HALUtil.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_wpilibj_hal_PWMJNI
+ * Method:    initializePWMPort
+ * Signature: (I)I;
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    checkPWMChannel
+ * Signature: (I)Z;
+*/
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+* Method:    freeDIOPort
+* Signature: (I)V;
+*/
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+* Method:    setPWMConfigRaw
+* Signature: (IIIIII)V;
+*/
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+* Method:    setPWMConfig
+* Signature: (IDDDDD)V;
+*/
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_DIOJNI
+* Method:    getPWMConfigRaw
+* Signature: (I)Ledu/wpi/first/wpilibj/PWMConfigDataResult;
+*/
+JNIEXPORT jobject JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    setPWMEliminateDeadband
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    getPWMEliminateDeadband
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    setPWMRaw
+ * Signature: (IS)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    setPWMSpeed
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    setPWMPosition
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    getPWMRaw
+ * Signature: (I)S
+ */
+JNIEXPORT jshort JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    getPWMSpeed
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    getPWMPosition
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    setPWMDisabled
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    latchPWMZero
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PWMJNI
+ * Method:    setPWMPeriodScale
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PortsJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PortsJNI.cpp
new file mode 100644
index 0000000..89c63a3
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PortsJNI.cpp
@@ -0,0 +1,297 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_PortsJNI.h"
+
+#include "HAL/Ports.h"
+#include "HALUtil.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_wpilibj_hal_PortsJNI
+ * Method:    getNumAccumulators
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumAnalogTriggers
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumAnalogInputs
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumAnalogOutputs
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumCounters
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumDigitalHeaders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumPWMHeaders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumDigitalChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumPWMChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumDigitalPWMOutputs
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumEncoders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumInterrupts
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumRelayChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumRelayHeaders
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumPCMModules
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumSolenoidChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumPDPModules
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PortsJNI
+ * Method:    getNumPDPChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_hal_PortsJNI_getNumPDPChannels(
+    JNIEnv *env, jclass) {
+  PORTSJNI_LOG(logDEBUG) << "Calling PortsJNI getNumPDPChannels";
+  jint value = HAL_GetNumPDPChannels();
+  PORTSJNI_LOG(logDEBUG) << "Value = " << value;
+  return value;
+}
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PowerJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PowerJNI.cpp
new file mode 100644
index 0000000..85f6c16
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/PowerJNI.cpp
@@ -0,0 +1,202 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <jni.h>
+#include "HALUtil.h"
+#include "edu_wpi_first_wpilibj_hal_PowerJNI.h"
+
+using namespace frc;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getVinVoltage
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getVinVoltage(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetVinVoltage(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getVinCurrent
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getVinCurrent(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetVinCurrent(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserVoltage6V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserVoltage6V(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetUserVoltage6V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserCurrent6V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserCurrent6V(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetUserCurrent6V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserActive6V
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserActive6V(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  bool val = HAL_GetUserActive6V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserCurrentFaults6V
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PowerJNI
+ * Method:    getUserVoltage5V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserVoltage5V(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetUserVoltage5V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserCurrent5V
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserCurrent5V(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetUserCurrent5V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserActive5V
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserActive5V(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  bool val = HAL_GetUserActive5V(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserCurrentFaults5V
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_PowerJNI
+ * Method:    getUserVoltage3V3
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserVoltage3V3(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetUserVoltage3V3(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserCurrent3V3
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserCurrent3V3(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  double val = HAL_GetUserCurrent3V3(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserActive3V3
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_hal_PowerJNI_getUserActive3V3(JNIEnv* env, jclass) {
+  int32_t status = 0;
+  bool val = HAL_GetUserActive3V3(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_PowerJNI
+ * Method:    getUserCurrentFaults3V3
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/RelayJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/RelayJNI.cpp
new file mode 100644
index 0000000..7522f97
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/RelayJNI.cpp
@@ -0,0 +1,109 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_RelayJNI.h"
+
+#include "HAL/Relay.h"
+#include "HAL/Ports.h"
+#include "HALUtil.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_wpilibj_hal_RelayJNI
+ * Method:    initializeRelayPort
+ * Signature: (IZ)I;
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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, (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_wpilibj_hal_RelayJNI
+* Method:    freeRelayPort
+* Signature: (I)V;
+*/
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_RelayJNI
+* Method:    checkRelayChannel
+* Signature: (I)Z;
+*/
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_hal_RelayJNI_checkRelayChannel(
+    JNIEnv *env, jclass, jint channel) {
+  RELAYJNI_LOG(logDEBUG) << "Calling RELAYJNI checkRelayChannel";
+  RELAYJNI_LOG(logDEBUG) << "Channel = " << channel;
+  return (jboolean)HAL_CheckRelayChannel((uint8_t) channel);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_RelayJNI
+ * Method:    setRelay
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_RelayJNI
+ * Method:    getRelay
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SPIJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SPIJNI.cpp
new file mode 100644
index 0000000..e9d21e4
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SPIJNI.cpp
@@ -0,0 +1,438 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_SPIJNI.h"
+
+#include "HAL/SPI.h"
+#include "HALUtil.h"
+#include "support/jni_util.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_wpilibj_hal_SPIJNI
+ * Method:    spiInitialize
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiTransaction
+ * Signature: (ILjava/nio/ByteBuffer;Ljava/nio/ByteBuffer;B)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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 = (uint8_t *)env->GetDirectBufferAddress(dataToSend);
+  }
+  uint8_t *dataReceivedPtr =
+      (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_wpilibj_hal_SPIJNI
+ * Method:    spiTransactionB
+ * Signature: (I[B[BB)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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;
+  llvm::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_wpilibj_hal_SPIJNI
+ * Method:    spiWrite
+ * Signature: (ILjava/nio/ByteBuffer;B)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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 = (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_wpilibj_hal_SPIJNI
+ * Method:    spiWriteB
+ * Signature: (I[BB)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiRead
+ * Signature: (IZLjava/nio/ByteBuffer;B)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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 =
+      (uint8_t *)env->GetDirectBufferAddress(dataReceived);
+  SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size;
+  SPIJNI_LOG(logDEBUG) << "DataReceivedPtr = " << dataReceivedPtr;
+  jint retVal;
+  if (initiate) {
+    llvm::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), (uint8_t *)dataReceivedPtr, size);
+  }
+  SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal;
+  return retVal;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_SPIJNI
+ * Method:    spiReadB
+ * Signature: (IZ[BB)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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;
+  llvm::SmallVector<uint8_t, 128> recvBuf;
+  recvBuf.resize(size);
+  if (initiate) {
+    llvm::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_wpilibj_hal_SPIJNI
+ * Method:    spiClose
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiSetSpeed
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiSetOpts
+ * Signature: (IIII)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiSetChipSelectActiveHigh
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiSetChipSelectActiveLow
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiInitAuto
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiFreeAuto
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiStartAutoRate
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiStartAutoTrigger
+ * Signature: (IIIZZ)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiStopAuto
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiSetAutoTransmitData
+ * Signature: (I[BI)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiForceAutoRead
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SPIJNI
+ * Method:    spiReadAutoReceivedData
+ * Signature: (ILjava/nio/ByteBuffer;ID)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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;
+  uint8_t *recvBuf = (uint8_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_wpilibj_hal_SPIJNI
+ * Method:    spiReadAutoReceivedData
+ * Signature: (I[BID)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiReadAutoReceivedData__I_3BID
+  (JNIEnv *env, jclass, jint port, jbyteArray 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;
+  llvm::SmallVector<uint8_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->SetByteArrayRegion(buffer, 0, numToRead,
+                            reinterpret_cast<const jbyte *>(recvBuf.data()));
+  }
+  return retval;
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_SPIJNI
+ * Method:    spiGetAutoDroppedCount
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SerialPortJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SerialPortJNI.cpp
new file mode 100644
index 0000000..2d72505
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SerialPortJNI.cpp
@@ -0,0 +1,322 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_SerialPortJNI.h"
+
+#include "HAL/SerialPort.h"
+#include "HALUtil.h"
+#include "support/jni_util.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_wpilibj_hal_SerialPortJNI
+ * Method:    serialInitializePort
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetBaudRate
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetDataBits
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetParity
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetStopBits
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetWriteMode
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetFlowControl
+ * Signature: (BB)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetTimeout
+ * Signature: (BD)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialEnableTermination
+ * Signature: (BC)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialDisableTermination
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetReadBufferSize
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialSetWriteBufferSize
+ * Signature: (BI)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialGetBytesReceived
+ * Signature: (B)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialRead
+ * Signature: (B[BI)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SerialPortJNI_serialRead(
+    JNIEnv* env, jclass, jbyte port, jbyteArray dataReceived, jint size) {
+  SERIALJNI_LOG(logDEBUG) << "Serial Read";
+  llvm::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_wpilibj_hal_SerialPortJNI
+ * Method:    serialWrite
+ * Signature: (B[BI)I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialFlush
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialClear
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SerialPortJNI
+ * Method:    serialClose
+ * Signature: (B)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SolenoidJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SolenoidJNI.cpp
new file mode 100644
index 0000000..63c805e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/SolenoidJNI.cpp
@@ -0,0 +1,226 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 "HAL/Solenoid.h"
+#include "HAL/Ports.h"
+#include "HAL/handles/HandlesInternal.h"
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_SolenoidJNI.h"
+
+#include "HALUtil.h"
+
+using namespace frc;
+
+TLogLevel solenoidJNILogLevel = logERROR;
+
+#define SOLENOIDJNI_LOG(level)     \
+  if (level > solenoidJNILogLevel) \
+    ;                              \
+  else                             \
+  Log().Get(level)
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_SolenoidJNI
+ * Method:    initializeSolenoidPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    checkSolenoidChannel
+ * Signature: (I)Z;
+*/
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    checkSolenoidModule
+ * Signature: (I)Z;
+*/
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    freeSolenoidPort
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    setSolenoid
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    getSolenoid
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    getAllSolenoids
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    getPCMSolenoidBlackList
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    getPCMSolenoidVoltageStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    getPCMSolenoidVoltageFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    clearAllPCMStickyFaults
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpilibj_hal_SolenoidJNI_clearAllPCMStickyFaults(
+    JNIEnv *env, jclass, jint module) {
+  int32_t status = 0;
+  HAL_ClearAllPCMStickyFaults(module, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_wpilibj_hal_SolenoidJNI
+ * Method:    setOneShotDuration
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_SolenoidJNI
+ * Method:    fireOneShot
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_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/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/ThreadsJNI.cpp b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/ThreadsJNI.cpp
new file mode 100644
index 0000000..7121b8d
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/main/native/cpp/ThreadsJNI.cpp
@@ -0,0 +1,73 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
+/* Open Source Software - may be 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 <assert.h>
+#include <jni.h>
+#include "HAL/cpp/Log.h"
+
+#include "edu_wpi_first_wpilibj_hal_ThreadsJNI.h"
+
+#include "HAL/Threads.h"
+#include "HALUtil.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_wpilibj_hal_ThreadsJNI
+ * Method:    GetCurrentThreadPriority
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_ThreadsJNI
+ * Method:    GetCurrentThreadIsRealTime
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_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_wpilibj_hal_ThreadsJNI
+ * Method:    SetCurrentThreadPriority
+ * Signature: (ZI)Z
+ */
+JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_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, (int32_t)priority, &status);
+  CheckStatus(env, status);
+  return (jboolean)ret;
+}
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/CircularBufferTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/CircularBufferTest.java
new file mode 100644
index 0000000..407a405
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/CircularBufferTest.java
@@ -0,0 +1,219 @@
+/*----------------------------------------------------------------------------*/
+/* 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class CircularBufferTest {
+  private double[] m_values = {751.848, 766.366, 342.657, 234.252, 716.126,
+      132.344, 445.697, 22.727, 421.125, 799.913};
+  private double[] m_addFirstOut = {799.913, 421.125, 22.727, 445.697, 132.344,
+      716.126, 234.252, 342.657};
+  private double[] m_addLastOut = {342.657, 234.252, 716.126, 132.344, 445.697,
+      22.727, 421.125, 799.913};
+
+  @BeforeClass
+  public static void before() {
+    UnitTestUtility.setupMockBase();
+  }
+
+  @Test
+  public void addFirstTest() {
+    CircularBuffer queue = new CircularBuffer(8);
+
+    for (double value : m_values) {
+      queue.addFirst(value);
+    }
+
+    for (int i = 0; i < m_addFirstOut.length; i++) {
+      assertEquals(m_addFirstOut[i], queue.get(i), 0.00005);
+    }
+  }
+
+  @Test
+  public void addLastTest() {
+    CircularBuffer queue = new CircularBuffer(8);
+
+    for (double value : m_values) {
+      queue.addLast(value);
+    }
+
+    for (int i = 0; i < m_addLastOut.length; i++) {
+      assertEquals(m_addLastOut[i], queue.get(i), 0.00005);
+    }
+  }
+
+  @Test
+  public void pushPopTest() {
+    CircularBuffer queue = new CircularBuffer(3);
+
+    // Insert three elements into the buffer
+    queue.addLast(1.0);
+    queue.addLast(2.0);
+    queue.addLast(3.0);
+
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+    assertEquals(3.0, queue.get(2), 0.00005);
+
+    /*
+     * The buffer is full now, so pushing subsequent elements will overwrite the
+     * front-most elements.
+     */
+
+    queue.addLast(4.0); // Overwrite 1 with 4
+
+    // The buffer now contains 2, 3, and 4
+    assertEquals(2.0, queue.get(0), 0.00005);
+    assertEquals(3.0, queue.get(1), 0.00005);
+    assertEquals(4.0, queue.get(2), 0.00005);
+
+    queue.addLast(5.0); // Overwrite 2 with 5
+
+    // The buffer now contains 3, 4, and 5
+    assertEquals(3.0, queue.get(0), 0.00005);
+    assertEquals(4.0, queue.get(1), 0.00005);
+    assertEquals(5.0, queue.get(2), 0.00005);
+
+    assertEquals(5.0, queue.removeLast(), 0.00005); // 5 is removed
+
+    // The buffer now contains 3 and 4
+    assertEquals(3.0, queue.get(0), 0.00005);
+    assertEquals(4.0, queue.get(1), 0.00005);
+
+    assertEquals(3.0, queue.removeFirst(), 0.00005); // 3 is removed
+
+    // Leaving only one element with value == 4
+    assertEquals(4.0, queue.get(0), 0.00005);
+  }
+
+  @Test
+  public void resetTest() {
+    CircularBuffer queue = new CircularBuffer(5);
+
+    for (int i = 0; i < 6; i++) {
+      queue.addLast(i);
+    }
+
+    queue.clear();
+
+    for (int i = 0; i < 5; i++) {
+      assertEquals(0.0, queue.get(i), 0.00005);
+    }
+  }
+
+  @Test
+  public void resizeTest() {
+    CircularBuffer queue = new CircularBuffer(5);
+
+    /* Buffer contains {1, 2, 3, _, _}
+     *                  ^ front
+     */
+    queue.addLast(1.0);
+    queue.addLast(2.0);
+    queue.addLast(3.0);
+
+    queue.resize(2);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.resize(5);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.clear();
+
+    /* Buffer contains {_, 1, 2, 3, _}
+     *                     ^ front
+     */
+    queue.addLast(0.0);
+    queue.addLast(1.0);
+    queue.addLast(2.0);
+    queue.addLast(3.0);
+    queue.removeFirst();
+
+    queue.resize(2);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.resize(5);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.clear();
+
+    /* Buffer contains {_, _, 1, 2, 3}
+     *                        ^ front
+     */
+    queue.addLast(0.0);
+    queue.addLast(0.0);
+    queue.addLast(1.0);
+    queue.addLast(2.0);
+    queue.addLast(3.0);
+    queue.removeFirst();
+    queue.removeFirst();
+
+    queue.resize(2);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.resize(5);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.clear();
+
+    /* Buffer contains {3, _, _, 1, 2}
+     *                           ^ front
+     */
+    queue.addLast(3.0);
+    queue.addFirst(2.0);
+    queue.addFirst(1.0);
+
+    queue.resize(2);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.resize(5);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.clear();
+
+    /* Buffer contains {2, 3, _, _, 1}
+     *                              ^ front
+     */
+    queue.addLast(2.0);
+    queue.addLast(3.0);
+    queue.addFirst(1.0);
+
+    queue.resize(2);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    queue.resize(5);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+
+    // Test addLast() after resize
+    queue.addLast(3.0);
+    assertEquals(1.0, queue.get(0), 0.00005);
+    assertEquals(2.0, queue.get(1), 0.00005);
+    assertEquals(3.0, queue.get(2), 0.00005);
+
+    // Test addFirst() after resize
+    queue.addFirst(4.0);
+    assertEquals(4.0, queue.get(0), 0.00005);
+    assertEquals(1.0, queue.get(1), 0.00005);
+    assertEquals(2.0, queue.get(2), 0.00005);
+    assertEquals(3.0, queue.get(3), 0.00005);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockRobotStateInterface.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockRobotStateInterface.java
new file mode 100644
index 0000000..7c3ab10
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockRobotStateInterface.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.wpilibj;
+
+/**
+ * A concrete implementation of the robot state interface that can be used in UnitTests.
+ */
+public class MockRobotStateInterface implements RobotState.Interface {
+  @Override
+  public boolean isDisabled() {
+    return false;
+  }
+
+  @Override
+  public boolean isEnabled() {
+    return true;
+  }
+
+  @Override
+  public boolean isOperatorControl() {
+    return false;
+  }
+
+  @Override
+  public boolean isAutonomous() {
+    return false;
+  }
+
+  @Override
+  public boolean isTest() {
+    return true;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockSpeedController.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockSpeedController.java
new file mode 100644
index 0000000..cbb5c61
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockSpeedController.java
@@ -0,0 +1,48 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+public class MockSpeedController implements SpeedController {
+  private double m_speed = 0.0;
+  private boolean m_isInverted = false;
+
+  @Override
+  public void set(double speed) {
+    m_speed = m_isInverted ? -speed : speed;
+  }
+
+  @Override
+  public double get() {
+    return m_speed;
+  }
+
+  @Override
+  public void setInverted(boolean isInverted) {
+    m_isInverted = isInverted;
+  }
+
+  @Override
+  public boolean getInverted() {
+    return m_isInverted;
+  }
+
+  @Override
+  public void disable() {
+    m_speed = 0;
+  }
+
+  @Override
+  public void stopMotor() {
+    disable();
+  }
+
+  @Override
+  public void pidWrite(double output) {
+    set(output);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/PIDToleranceTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/PIDToleranceTest.java
new file mode 100644
index 0000000..1da0c9f
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/PIDToleranceTest.java
@@ -0,0 +1,109 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class PIDToleranceTest {
+  private PIDController m_pid;
+  private final double m_setPoint = 50.0;
+  private final double m_tolerance = 10.0;
+  private final double m_range = 200;
+
+  @BeforeClass
+  public static void setupClass() {
+    UnitTestUtility.setupMockBase();
+  }
+
+  private class FakeInput implements PIDSource {
+    public double m_val;
+
+    FakeInput() {
+      m_val = 0;
+    }
+
+    @Override
+    public PIDSourceType getPIDSourceType() {
+      return PIDSourceType.kDisplacement;
+    }
+
+    @Override
+    public double pidGet() {
+      return m_val;
+    }
+
+    @Override
+    public void setPIDSourceType(PIDSourceType arg0) {
+    }
+  }
+
+  private FakeInput m_inp;
+  private PIDOutput m_out = new PIDOutput() {
+    @Override
+    public void pidWrite(double out) {
+    }
+
+  };
+
+
+  @Before
+  public void setUp() throws Exception {
+    m_inp = new FakeInput();
+    m_pid = new PIDController(0.05, 0.0, 0.0, m_inp, m_out);
+    m_pid.setInputRange(-m_range / 2, m_range / 2);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    m_pid.free();
+    m_pid = null;
+  }
+
+  @Test
+  public void testAbsoluteTolerance() {
+    m_pid.setAbsoluteTolerance(m_tolerance);
+    m_pid.setSetpoint(m_setPoint);
+    m_pid.enable();
+    Timer.delay(1);
+    assertFalse("Error was in tolerance when it should not have been. Error was "
+        + m_pid.getError(), m_pid.onTarget());
+    m_inp.m_val = m_setPoint + m_tolerance / 2;
+    Timer.delay(1.0);
+    assertTrue("Error was not in tolerance when it should have been. Error was "
+        + m_pid.getError(), m_pid.onTarget());
+    m_inp.m_val = m_setPoint + 10 * m_tolerance;
+    Timer.delay(1.0);
+    assertFalse("Error was in tolerance when it should not have been. Error was "
+        + m_pid.getError(), m_pid.onTarget());
+  }
+
+  @Test
+  public void testPercentTolerance() {
+    m_pid.setPercentTolerance(m_tolerance);
+    m_pid.setSetpoint(m_setPoint);
+    m_pid.enable();
+    assertFalse("Error was in tolerance when it should not have been. Error was "
+        + m_pid.getError(), m_pid.onTarget());
+    //half of percent tolerance away from setPoint
+    m_inp.m_val = m_setPoint + m_tolerance / 200 * m_range;
+    Timer.delay(1.0);
+    assertTrue("Error was not in tolerance when it should have been. Error was "
+        + m_pid.getError(), m_pid.onTarget());
+    //double percent tolerance away from setPoint
+    m_inp.m_val = m_setPoint + m_tolerance / 50 * m_range;
+    Timer.delay(1.0);
+    assertFalse("Error was in tolerance when it should not have been. Error was "
+        + m_pid.getError(), m_pid.onTarget());
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/SpeedControllerGroupTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/SpeedControllerGroupTest.java
new file mode 100644
index 0000000..3af8a66
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/SpeedControllerGroupTest.java
@@ -0,0 +1,114 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class SpeedControllerGroupTest {
+  private final SpeedController[] m_speedControllers;
+  private final SpeedControllerGroup m_group;
+
+  /**
+   * Returns a Collection of ArrayLists with various MockSpeedController configurations.
+   */
+  @Parameterized.Parameters
+  public static Collection<Object[][]> data() {
+    return Arrays.asList((Object[][][]) new SpeedController[][][] {
+        {{new MockSpeedController()}},
+        {{new MockSpeedController(),
+            new MockSpeedController()}},
+        {{new MockSpeedController(),
+            new MockSpeedController(),
+            new MockSpeedController()}}
+    });
+  }
+
+  /**
+   * Construct SpeedControllerGroupTest.
+   */
+  public SpeedControllerGroupTest(SpeedController[] speedControllers) {
+    m_group = new SpeedControllerGroup(speedControllers[0],
+        Arrays.copyOfRange(speedControllers, 1, speedControllers.length));
+    m_speedControllers = speedControllers;
+  }
+
+  @Test
+  public void testSet() {
+    m_group.set(1.0);
+
+    assertArrayEquals(Arrays.stream(m_speedControllers).mapToDouble(__ -> 1.0).toArray(),
+        Arrays.stream(m_speedControllers).mapToDouble(SpeedController::get).toArray(),
+        0.0);
+  }
+
+  @Test
+  public void testGetInverted() {
+    m_group.setInverted(true);
+
+    assertTrue(m_group.getInverted());
+  }
+
+  @Test
+  public void testSetInvertedDoesNotModifySpeedControllers() {
+    for (SpeedController speedController : m_speedControllers) {
+      speedController.setInverted(false);
+    }
+    m_group.setInverted(true);
+
+    assertArrayEquals(Arrays.stream(m_speedControllers).map(__ -> false).toArray(),
+        Arrays.stream(m_speedControllers).map(SpeedController::getInverted).toArray());
+  }
+
+  @Test
+  public void testSetInvertedDoesInvert() {
+    m_group.setInverted(true);
+    m_group.set(1.0);
+
+    assertArrayEquals(Arrays.stream(m_speedControllers).mapToDouble(__ -> -1.0).toArray(),
+        Arrays.stream(m_speedControllers).mapToDouble(SpeedController::get).toArray(),
+        0.0);
+  }
+
+  @Test
+  public void testDisable() {
+    m_group.set(1.0);
+    m_group.disable();
+
+    assertArrayEquals(Arrays.stream(m_speedControllers).mapToDouble(__ -> 0.0).toArray(),
+        Arrays.stream(m_speedControllers).mapToDouble(SpeedController::get).toArray(),
+        0.0);
+  }
+
+  @Test
+  public void testStopMotor() {
+    m_group.set(1.0);
+    m_group.stopMotor();
+
+    assertArrayEquals(Arrays.stream(m_speedControllers).mapToDouble(__ -> 0.0).toArray(),
+        Arrays.stream(m_speedControllers).mapToDouble(SpeedController::get).toArray(),
+        0.0);
+  }
+
+  @Test
+  public void testPidWrite() {
+    m_group.pidWrite(1.0);
+
+    assertArrayEquals(Arrays.stream(m_speedControllers).mapToDouble(__ -> 1.0).toArray(),
+        Arrays.stream(m_speedControllers).mapToDouble(SpeedController::get).toArray(),
+        0.0);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/UnitTestUtility.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/UnitTestUtility.java
new file mode 100644
index 0000000..b4bdfcb
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/UnitTestUtility.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj;
+
+import com.google.common.base.Stopwatch;
+
+import java.util.concurrent.TimeUnit;
+
+import edu.wpi.first.wpilibj.hal.HAL;
+import edu.wpi.first.wpilibj.util.BaseSystemNotInitializedException;
+
+/**
+ * Utility class for configuring unit tests.
+ */
+public final class UnitTestUtility {
+  private UnitTestUtility() {
+        /* no-op */
+  }
+
+  /**
+   * Sets up the base system WPILib so that it does not rely on hardware.
+   */
+  public static void setupMockBase() {
+    HAL.initialize(500, 0);
+    try {
+      // Check to see if this has been setup
+      Timer.getFPGATimestamp();
+    } catch (BaseSystemNotInitializedException ex) {
+      // If it hasn't been then do this setup
+
+      HLUsageReporting.SetImplementation(new HLUsageReporting.Null());
+      RobotState.SetImplementation(new MockRobotStateInterface());
+      Timer.SetImplementation(new Timer.StaticInterface() {
+
+        @Override
+        public double getFPGATimestamp() {
+          return System.currentTimeMillis() / 1000.0;
+        }
+
+        @Override
+        public double getMatchTime() {
+          return 0;
+        }
+
+        @Override
+        public void delay(double seconds) {
+          try {
+            Thread.sleep((long) (seconds * 1e3));
+          } catch (InterruptedException ex) {
+            Thread.currentThread().interrupt();
+            throw new RuntimeException("Thread was interrupted", ex);
+          }
+        }
+
+        @Override
+        public Timer.Interface newTimer() {
+          return new Timer.Interface() {
+            private final Stopwatch m_stopwatch = Stopwatch.createUnstarted();
+
+            @Override
+            public double get() {
+              return m_stopwatch.elapsed(TimeUnit.SECONDS);
+            }
+
+            @Override
+            public void reset() {
+              m_stopwatch.reset();
+            }
+
+            @Override
+            public void start() {
+              m_stopwatch.start();
+            }
+
+            @Override
+            public void stop() {
+              m_stopwatch.stop();
+            }
+
+            @Override
+            public boolean hasPeriodPassed(double period) {
+              if (get() > period) {
+                // Advance the start time by the period.
+                // Don't set it to the current time... we want to avoid drift.
+                m_stopwatch.reset().start();
+                return true;
+              }
+              return false;
+            }
+          };
+        }
+      });
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/can/CANStatusTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/can/CANStatusTest.java
new file mode 100644
index 0000000..97b06a1
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/can/CANStatusTest.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.can;
+
+import org.junit.Test;
+
+import edu.wpi.first.wpilibj.hal.HAL;
+
+public class CANStatusTest {
+  @Test
+  public void canStatusGetDoesntThrow() {
+    HAL.initialize(500, 0);
+    CANStatus status = new CANStatus();
+    CANJNI.GetCANStatus(status);
+    // Nothing we can assert, so just make sure it didn't throw.
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/AbstractCommandTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/AbstractCommandTest.java
new file mode 100644
index 0000000..3485784
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/AbstractCommandTest.java
@@ -0,0 +1,59 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Before;
+
+import edu.wpi.first.wpilibj.UnitTestUtility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * The basic test for all {@link Command} tests.
+ */
+public abstract class AbstractCommandTest {
+  @Before
+  public void commandSetup() {
+    UnitTestUtility.setupMockBase();
+    Scheduler.getInstance().removeAll();
+    Scheduler.getInstance().enable();
+  }
+
+  public class ASubsystem extends Subsystem {
+    Command m_command;
+
+    protected void initDefaultCommand() {
+      if (m_command != null) {
+        setDefaultCommand(m_command);
+      }
+    }
+
+    public void init(Command command) {
+      m_command = command;
+    }
+  }
+
+
+  protected void assertCommandState(MockCommand command, int initialize, int execute,
+                                    int isFinished, int end, int interrupted) {
+    assertEquals(initialize, command.getInitializeCount());
+    assertEquals(execute, command.getExecuteCount());
+    assertEquals(isFinished, command.getIsFinishedCount());
+    assertEquals(end, command.getEndCount());
+    assertEquals(interrupted, command.getInterruptedCount());
+  }
+
+  protected void sleep(int time) {
+    try {
+      Thread.sleep(time);
+    } catch (InterruptedException ex) {
+      fail("Sleep Interrupted!?!?!?!?");
+    }
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/ButtonTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/ButtonTest.java
new file mode 100644
index 0000000..64fb060
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/ButtonTest.java
@@ -0,0 +1,116 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import edu.wpi.first.wpilibj.buttons.InternalButton;
+
+
+/**
+ * Test that covers the {@link edu.wpi.first.wpilibj.buttons.Button} with the {@link Command}
+ * library.
+ */
+public class ButtonTest extends AbstractCommandTest {
+  private InternalButton m_button1;
+  private InternalButton m_button2;
+
+  @Before
+  public void setUp() throws Exception {
+    m_button1 = new InternalButton();
+    m_button2 = new InternalButton();
+  }
+
+  /**
+   * Simple Button Test.
+   */
+  @Test
+  public void test() {
+    final MockCommand command1 = new MockCommand();
+    final MockCommand command2 = new MockCommand();
+    final MockCommand command3 = new MockCommand();
+    final MockCommand command4 = new MockCommand();
+
+    m_button1.whenPressed(command1);
+    m_button1.whenReleased(command2);
+    m_button1.whileHeld(command3);
+    m_button2.whileHeld(command4);
+
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    assertCommandState(command4, 0, 0, 0, 0, 0);
+    m_button1.setPressed(true);
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    assertCommandState(command4, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    assertCommandState(command4, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 1, 1, 1, 0, 0);
+    assertCommandState(command4, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 2, 2, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 1, 2, 2, 0, 0);
+    assertCommandState(command4, 0, 0, 0, 0, 0);
+    m_button2.setPressed(true);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 3, 3, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 1, 3, 3, 0, 0);
+    assertCommandState(command4, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 4, 4, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 1, 4, 4, 0, 0);
+    assertCommandState(command4, 1, 1, 1, 0, 0);
+    m_button1.setPressed(false);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 5, 5, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 1, 4, 4, 0, 1);
+    assertCommandState(command4, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 6, 6, 0, 0);
+    assertCommandState(command2, 1, 1, 1, 0, 0);
+    assertCommandState(command3, 1, 4, 4, 0, 1);
+    assertCommandState(command4, 1, 3, 3, 0, 0);
+    m_button2.setPressed(false);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 7, 7, 0, 0);
+    assertCommandState(command2, 1, 2, 2, 0, 0);
+    assertCommandState(command3, 1, 4, 4, 0, 1);
+    assertCommandState(command4, 1, 3, 3, 0, 1);
+    command1.cancel();
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 7, 7, 0, 1);
+    assertCommandState(command2, 1, 3, 3, 0, 0);
+    assertCommandState(command3, 1, 4, 4, 0, 1);
+    assertCommandState(command4, 1, 3, 3, 0, 1);
+    command2.setHasFinished(true);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 7, 7, 0, 1);
+    assertCommandState(command2, 1, 4, 4, 1, 0);
+    assertCommandState(command3, 1, 4, 4, 0, 1);
+    assertCommandState(command4, 1, 3, 3, 0, 1);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 7, 7, 0, 1);
+    assertCommandState(command2, 1, 4, 4, 1, 0);
+    assertCommandState(command3, 1, 4, 4, 0, 1);
+    assertCommandState(command4, 1, 3, 3, 0, 1);
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandParallelGroupTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandParallelGroupTest.java
new file mode 100644
index 0000000..8291f3e
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandParallelGroupTest.java
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Test;
+
+/**
+ * Ported from the old CrioTest Classes.
+ */
+public class CommandParallelGroupTest extends AbstractCommandTest {
+  /**
+   * Simple Parallel Command Group With 2 commands one command terminates first.
+   */
+  @Test
+  public void testParallelCommandGroupWithTwoCommands() {
+    final MockCommand command1 = new MockCommand();
+    final MockCommand command2 = new MockCommand();
+
+    final CommandGroup commandGroup = new CommandGroup();
+    commandGroup.addParallel(command1);
+    commandGroup.addParallel(command2);
+
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    commandGroup.start();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 0);
+    assertCommandState(command2, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 2, 2, 0, 0);
+    assertCommandState(command2, 1, 2, 2, 0, 0);
+    command1.setHasFinished(true);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 3, 3, 1, 0);
+    assertCommandState(command2, 1, 3, 3, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 3, 3, 1, 0);
+    assertCommandState(command2, 1, 4, 4, 0, 0);
+    command2.setHasFinished(true);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 3, 3, 1, 0);
+    assertCommandState(command2, 1, 5, 5, 1, 0);
+
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandScheduleTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandScheduleTest.java
new file mode 100644
index 0000000..d324f31
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandScheduleTest.java
@@ -0,0 +1,61 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Test;
+
+/**
+ * Ported from the old CrioTest Classes.
+ */
+public class CommandScheduleTest extends AbstractCommandTest {
+  /**
+   * Simple scheduling of a command and making sure the command is run and successfully terminates.
+   */
+  @Test
+  public void testRunAndTerminate() {
+    final MockCommand command = new MockCommand();
+    command.start();
+    assertCommandState(command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 2, 2, 0, 0);
+    command.setHasFinished(true);
+    assertCommandState(command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 3, 3, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 3, 3, 1, 0);
+  }
+
+  /**
+   * Simple scheduling of a command and making sure the command is run and cancels correctly.
+   */
+  @Test
+  public void testRunAndCancel() {
+    final MockCommand command = new MockCommand();
+    command.start();
+    assertCommandState(command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 3, 3, 0, 0);
+    command.cancel();
+    assertCommandState(command, 1, 3, 3, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 3, 3, 0, 1);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 3, 3, 0, 1);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandSequentialGroupTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandSequentialGroupTest.java
new file mode 100644
index 0000000..5d41b92
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandSequentialGroupTest.java
@@ -0,0 +1,105 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Test;
+
+import java.util.logging.Logger;
+
+/**
+ * Ported from the old CrioTest Classes.
+ */
+public class CommandSequentialGroupTest extends AbstractCommandTest {
+  private static Logger logger = Logger.getLogger(CommandSequentialGroupTest.class.getName());
+
+  /**
+   * Simple Command Group With 3 commands that all depend on a subsystem. Some commands have a
+   * timeout.
+   */
+  @Test(timeout = 20000)
+  public void testThreeCommandOnSubSystem() {
+    logger.fine("Begining Test");
+    final ASubsystem subsystem = new ASubsystem();
+
+    logger.finest("Creating Mock Command1");
+    final MockCommand command1 = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+    logger.finest("Creating Mock Command2");
+    final MockCommand command2 = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+    logger.finest("Creating Mock Command3");
+    final MockCommand command3 = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+
+    logger.finest("Creating Command Group");
+    final CommandGroup commandGroup = new CommandGroup();
+    commandGroup.addSequential(command1, 1.0);
+    commandGroup.addSequential(command2, 2.0);
+    commandGroup.addSequential(command3);
+
+
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    logger.finest("Starting Command group");
+    commandGroup.start();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    sleep(1000); // command 1 timeout
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 1);
+    assertCommandState(command2, 1, 1, 1, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 1);
+    assertCommandState(command2, 1, 2, 2, 0, 0);
+    assertCommandState(command3, 0, 0, 0, 0, 0);
+    sleep(2000); // command 2 timeout
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 1);
+    assertCommandState(command2, 1, 2, 2, 0, 1);
+    assertCommandState(command3, 1, 1, 1, 0, 0);
+
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 1);
+    assertCommandState(command2, 1, 2, 2, 0, 1);
+    assertCommandState(command3, 1, 2, 2, 0, 0);
+    command3.setHasFinished(true);
+    assertCommandState(command1, 1, 1, 1, 0, 1);
+    assertCommandState(command2, 1, 2, 2, 0, 1);
+    assertCommandState(command3, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 1);
+    assertCommandState(command2, 1, 2, 2, 0, 1);
+    assertCommandState(command3, 1, 3, 3, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 1);
+    assertCommandState(command2, 1, 2, 2, 0, 1);
+    assertCommandState(command3, 1, 3, 3, 1, 0);
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandSupersedeTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandSupersedeTest.java
new file mode 100644
index 0000000..7c09a57
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandSupersedeTest.java
@@ -0,0 +1,120 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Test;
+
+import java.util.logging.Logger;
+
+/**
+ * Ported from the old CrioTest Classes.
+ */
+public class CommandSupersedeTest extends AbstractCommandTest {
+  private static final Logger logger = Logger.getLogger(CommandSupersedeTest.class.getName());
+
+
+  /**
+   * Testing one command superseding another because of dependencies.
+   */
+  @Test
+  public void testOneCommandSupersedingAnotherBecauseOfDependencies() {
+    final ASubsystem subsystem = new ASubsystem();
+
+    final MockCommand command1 = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+
+    final MockCommand command2 = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    command1.start();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 2, 2, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 3, 3, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    command2.start();
+    assertCommandState(command1, 1, 3, 3, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 4, 4, 0, 1);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 4, 4, 0, 1);
+    assertCommandState(command2, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 4, 4, 0, 1);
+    assertCommandState(command2, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 4, 4, 0, 1);
+    assertCommandState(command2, 1, 3, 3, 0, 0);
+  }
+
+  /**
+   * Testing one command failing superseding another because of dependencies because the first
+   * command cannot be interrupted.
+   */
+  @Test
+  public void testCommandFailingSupersedingBecauseFirstCanNotBeInterrupted() {
+    final ASubsystem subsystem = new ASubsystem();
+
+    final MockCommand command1 = new MockCommand() {
+      {
+        requires(subsystem);
+        setInterruptible(false);
+      }
+    };
+
+    final MockCommand command2 = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    command1.start();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 0, 0, 0, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 1, 1, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 2, 2, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 3, 3, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    command2.start();
+    assertCommandState(command1, 1, 3, 3, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command1, 1, 4, 4, 0, 0);
+    assertCommandState(command2, 0, 0, 0, 0, 0);
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandTimeoutTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandTimeoutTest.java
new file mode 100644
index 0000000..fe191b1
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/CommandTimeoutTest.java
@@ -0,0 +1,53 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Test;
+
+/**
+ * Test a {@link Command} that times out.
+ */
+public class CommandTimeoutTest extends AbstractCommandTest {
+  /**
+   * Command 2 second Timeout Test.
+   */
+  @Test
+  public void testTwoSecondTimeout() {
+    final ASubsystem subsystem = new ASubsystem();
+
+
+    final MockCommand command = new MockCommand() {
+      {
+        requires(subsystem);
+        setTimeout(2);
+      }
+
+      @Override
+      public boolean isFinished() {
+        return super.isFinished() || isTimedOut();
+      }
+    };
+
+    command.start();
+    assertCommandState(command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 3, 3, 0, 0);
+    sleep(2000);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 4, 4, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(command, 1, 4, 4, 1, 0);
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/ConditionalCommandTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/ConditionalCommandTest.java
new file mode 100644
index 0000000..878854b
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/ConditionalCommandTest.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.command;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+//import org.junit.Ignore;
+import org.junit.Test;
+
+public class ConditionalCommandTest extends AbstractCommandTest {
+  MockConditionalCommand m_command;
+  MockConditionalCommand m_commandNull;
+  MockCommand m_onTrue;
+  MockCommand m_onFalse;
+  MockSubsystem m_subsys;
+  Boolean m_condition;
+
+  @Before
+  public void initCommands() {
+    m_subsys = new MockSubsystem();
+    m_onTrue = new MockCommand(m_subsys);
+    m_onFalse = new MockCommand(m_subsys);
+    m_command = new MockConditionalCommand(m_onTrue, m_onFalse);
+    m_commandNull = new MockConditionalCommand(m_onTrue, null);
+  }
+
+  protected void assertConditionalCommandState(MockConditionalCommand command, int initialize,
+                                               int execute, int isFinished, int end,
+                                               int interrupted) {
+    assertEquals(initialize, command.getInitializeCount());
+    assertEquals(execute, command.getExecuteCount());
+    assertEquals(isFinished, command.getIsFinishedCount());
+    assertEquals(end, command.getEndCount());
+    assertEquals(interrupted, command.getInterruptedCount());
+  }
+
+  @Test
+  public void testOnTrue() {
+    m_command.setCondition(true);
+
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 0);
+    m_onTrue.setHasFinished(true);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 4, 4, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 5, 5, 1, 0);
+
+    assertTrue("Did not initialize the true command", m_onTrue.getInitializeCount() > 0);
+    assertTrue("Initialized the false command", m_onFalse.getInitializeCount() == 0);
+  }
+
+  @Test
+  public void testOnFalse() {
+    m_command.setCondition(false);
+
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onFalse
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onFalse
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onFalse, 1, 1, 1, 0, 0);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onFalse, 1, 2, 2, 0, 0);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 0);
+    m_onFalse.setHasFinished(true);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onFalse, 1, 3, 3, 1, 0);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 4, 4, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onFalse, 1, 3, 3, 1, 0);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 5, 5, 1, 0);
+
+    assertTrue("Did not initialize the false command", m_onFalse.getInitializeCount() > 0);
+    assertTrue("Initialized the true command", m_onTrue.getInitializeCount() == 0);
+  }
+
+  @Test
+  public void testCancelSubCommand() {
+    m_command.setCondition(true);
+
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 0);
+    m_onTrue.cancel();
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 1);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 4, 4, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 1);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 5, 5, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 1);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 5, 5, 1, 0);
+  }
+
+  @Test
+  public void testCancelRequires() {
+    m_command.setCondition(true);
+
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 0);
+    m_onFalse.start();
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 4, 4, 0, 1);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 0, 1);
+    assertCommandState(m_onFalse, 1, 1, 1, 0, 0);
+    assertConditionalCommandState(m_command, 1, 4, 4, 0, 1);
+  }
+
+  @Test
+  public void testCancelCondCommand() {
+    m_command.setCondition(true);
+
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 0);
+    m_command.cancel();
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 1);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 1);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 1);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 1);
+  }
+
+  @Test
+  public void testOnTrueTwice() {
+    m_command.setCondition(true);
+
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 0);
+    m_onTrue.setHasFinished(true);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 4, 4, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 5, 5, 1, 0);
+
+    m_onTrue.resetCounters();
+    m_command.resetCounters();
+    m_command.setCondition(true);
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 2, 2, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 0, 0);
+    m_onTrue.setHasFinished(true);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 4, 4, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 3, 3, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 5, 5, 1, 0);
+  }
+
+  @Test
+  public void testOnTrueInstant() {
+    m_command.setCondition(true);
+    m_onTrue.setHasFinished(true);
+
+    Scheduler.getInstance().add(m_command);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onTrue
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 1, 1, 1, 1, 0);
+    assertCommandState(m_onFalse, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_command, 1, 3, 3, 1, 0);
+  }
+
+  @Test
+  public void testOnFalseNull() {
+    m_commandNull.setCondition(false);
+
+    Scheduler.getInstance().add(m_commandNull);
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_commandNull, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init command and select m_onFalse
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_commandNull, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();  // init m_onFalse
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_commandNull, 1, 1, 1, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(m_onTrue, 0, 0, 0, 0, 0);
+    assertConditionalCommandState(m_commandNull, 1, 1, 1, 1, 0);
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/DefaultCommandTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/DefaultCommandTest.java
new file mode 100644
index 0000000..5c041db
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/DefaultCommandTest.java
@@ -0,0 +1,129 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+import org.junit.Test;
+
+/**
+ * Tests the {@link Command} library.
+ */
+public class DefaultCommandTest extends AbstractCommandTest {
+  /**
+   * Testing of default commands where the interrupting command ends itself.
+   */
+  @Test
+  public void testDefaultCommandWhereTheInteruptingCommandEndsItself() {
+    final ASubsystem subsystem = new ASubsystem();
+
+
+    final MockCommand defaultCommand = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+
+    final MockCommand anotherCommand = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+    assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
+    subsystem.init(defaultCommand);
+
+    assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
+
+    anotherCommand.start();
+    assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
+    assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
+    anotherCommand.setHasFinished(true);
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 3, 3, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 2, 4, 4, 0, 1);
+    assertCommandState(anotherCommand, 1, 3, 3, 1, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 2, 5, 5, 0, 1);
+    assertCommandState(anotherCommand, 1, 3, 3, 1, 0);
+  }
+
+
+  /**
+   * Testing of default commands where the interrupting command is canceled.
+   */
+  @Test
+  public void testDefaultCommandsInterruptingCommandCanceled() {
+    final ASubsystem subsystem = new ASubsystem();
+
+
+    final MockCommand defaultCommand = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+
+    final MockCommand anotherCommand = new MockCommand() {
+      {
+        requires(subsystem);
+      }
+    };
+    assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
+    subsystem.init(defaultCommand);
+    subsystem.initDefaultCommand();
+    assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
+
+    anotherCommand.start();
+    assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
+    assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 1, 1, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
+    anotherCommand.cancel();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
+    assertCommandState(anotherCommand, 1, 2, 2, 0, 1);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 2, 4, 4, 0, 1);
+    assertCommandState(anotherCommand, 1, 2, 2, 0, 1);
+    Scheduler.getInstance().run();
+    assertCommandState(defaultCommand, 2, 5, 5, 0, 1);
+    assertCommandState(anotherCommand, 1, 2, 2, 0, 1);
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockCommand.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockCommand.java
new file mode 100644
index 0000000..1b7b7c5
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockCommand.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.command;
+
+/**
+ * A class to simulate a simple command. The command keeps track of how many times each method was
+ * called.
+ */
+public class MockCommand extends Command {
+  private int m_initializeCount = 0;
+  private int m_executeCount = 0;
+  private int m_isFinishedCount = 0;
+  private boolean m_hasFinished = false;
+  private int m_endCount = 0;
+  private int m_interruptedCount = 0;
+
+  public MockCommand(Subsystem subsys) {
+    super();
+    requires(subsys);
+  }
+
+  public MockCommand() {
+    super();
+  }
+
+  protected void initialize() {
+    ++m_initializeCount;
+  }
+
+  protected void execute() {
+    ++m_executeCount;
+  }
+
+  protected boolean isFinished() {
+    ++m_isFinishedCount;
+    return isHasFinished();
+  }
+
+  protected void end() {
+    ++m_endCount;
+  }
+
+  protected void interrupted() {
+    ++m_interruptedCount;
+  }
+
+
+  /**
+   * How many times the initialize method has been called.
+   */
+  public int getInitializeCount() {
+    return m_initializeCount;
+  }
+
+  /**
+   * If the initialize method has been called at least once.
+   */
+  public boolean hasInitialized() {
+    return getInitializeCount() > 0;
+  }
+
+  /**
+   * How many time the execute method has been called.
+   */
+  public int getExecuteCount() {
+    return m_executeCount;
+  }
+
+  /**
+   * How many times the isFinished method has been called.
+   */
+  public int getIsFinishedCount() {
+    return m_isFinishedCount;
+  }
+
+  /**
+   * Get what value the isFinished method will return.
+   *
+   * @return what value the isFinished method will return.
+   */
+  public boolean isHasFinished() {
+    return m_hasFinished;
+  }
+
+  /**
+   * Set what value the isFinished method will return.
+   *
+   * @param hasFinished set what value the isFinished method will return.
+   */
+  public void setHasFinished(boolean hasFinished) {
+    m_hasFinished = hasFinished;
+  }
+
+  /**
+   * How many times the end method has been called.
+   */
+  public int getEndCount() {
+    return m_endCount;
+  }
+
+  /**
+   * If the end method has been called at least once.
+   */
+  public boolean hasEnd() {
+    return getEndCount() > 0;
+  }
+
+  /**
+   * How many times the interrupted method has been called.
+   */
+  public int getInterruptedCount() {
+    return m_interruptedCount;
+  }
+
+  /**
+   * If the interrupted method has been called at least once.
+   */
+  public boolean hasInterrupted() {
+    return getInterruptedCount() > 0;
+  }
+
+  /**
+   * Reset internal counters.
+   */
+  public void resetCounters() {
+    m_initializeCount = 0;
+    m_executeCount = 0;
+    m_isFinishedCount = 0;
+    m_hasFinished = false;
+    m_endCount = 0;
+    m_interruptedCount = 0;
+  }
+
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockConditionalCommand.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockConditionalCommand.java
new file mode 100644
index 0000000..ebb6340
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockConditionalCommand.java
@@ -0,0 +1,120 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.command;
+
+public class MockConditionalCommand extends ConditionalCommand {
+  private boolean m_condition = false;
+  private int m_initializeCount = 0;
+  private int m_executeCount = 0;
+  private int m_isFinishedCount = 0;
+  private int m_endCount = 0;
+  private int m_interruptedCount = 0;
+
+  public MockConditionalCommand(MockCommand onTrue, MockCommand onFalse) {
+    super(onTrue, onFalse);
+  }
+
+  @Override
+  protected boolean condition() {
+    return m_condition;
+  }
+
+  public void setCondition(boolean condition) {
+    this.m_condition = condition;
+  }
+
+  protected void initialize() {
+    ++m_initializeCount;
+  }
+
+  protected void execute() {
+    ++m_executeCount;
+  }
+
+  protected boolean isFinished() {
+    ++m_isFinishedCount;
+    return super.isFinished();
+  }
+
+  protected void end() {
+    ++m_endCount;
+  }
+
+  protected void interrupted() {
+    ++m_interruptedCount;
+  }
+
+
+  /**
+   * How many times the initialize method has been called.
+   */
+  public int getInitializeCount() {
+    return m_initializeCount;
+  }
+
+  /**
+   * If the initialize method has been called at least once.
+   */
+  public boolean hasInitialized() {
+    return getInitializeCount() > 0;
+  }
+
+  /**
+   * How many time the execute method has been called.
+   */
+  public int getExecuteCount() {
+    return m_executeCount;
+  }
+
+  /**
+   * How many times the isFinished method has been called.
+   */
+  public int getIsFinishedCount() {
+    return m_isFinishedCount;
+  }
+
+  /**
+   * How many times the end method has been called.
+   */
+  public int getEndCount() {
+    return m_endCount;
+  }
+
+  /**
+   * If the end method has been called at least once.
+   */
+  public boolean hasEnd() {
+    return getEndCount() > 0;
+  }
+
+  /**
+   * How many times the interrupted method has been called.
+   */
+  public int getInterruptedCount() {
+    return m_interruptedCount;
+  }
+
+  /**
+   * If the interrupted method has been called at least once.
+   */
+  public boolean hasInterrupted() {
+    return getInterruptedCount() > 0;
+  }
+
+  /**
+   * Reset internal counters.
+   */
+  public void resetCounters() {
+    m_condition = false;
+    m_initializeCount = 0;
+    m_executeCount = 0;
+    m_isFinishedCount = 0;
+    m_endCount = 0;
+    m_interruptedCount = 0;
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockSubsystem.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockSubsystem.java
new file mode 100644
index 0000000..f20be37
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/command/MockSubsystem.java
@@ -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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.first.wpilibj.command;
+
+/**
+ * A class to simulate a simple subsystem.
+ */
+public class MockSubsystem extends Subsystem {
+  protected void initDefaultCommand() {}
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/JNITest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/JNITest.java
new file mode 100644
index 0000000..89a8bd3
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/JNITest.java
@@ -0,0 +1,26 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.hal;
+
+import edu.wpi.first.networktables.NetworkTablesJNI;
+import org.junit.Test;
+
+public class JNITest {
+  @Test
+  public void jniNtcoreLinkTest() {
+    // Test to verify that the JNI test link works correctly.
+    NetworkTablesJNI.flush(NetworkTablesJNI.getDefaultInstance());
+  }
+
+  @Test
+  public void jniHalLinkTest() {
+    HAL.initialize(500, 0);
+    // Test to verify that the JNI test link works correctly.
+    HALUtil.getHALRuntimeType();
+  }
+}
diff --git a/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/MatchInfoDataTest.java b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/MatchInfoDataTest.java
new file mode 100644
index 0000000..4c06fb2
--- /dev/null
+++ b/third_party/allwpilib_2018/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/MatchInfoDataTest.java
@@ -0,0 +1,20 @@
+/*----------------------------------------------------------------------------*/
+/* 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.wpilibj.hal;
+
+import org.junit.Test;
+
+public class MatchInfoDataTest {
+  @Test
+  public void matchInfoDataDoesNotThrow() {
+    HAL.initialize(500, 0);
+    MatchInfoData data = new MatchInfoData();
+    HAL.getMatchInfo(data);
+    // Nothing we can assert, so just make sure it didn't throw.
+  }
+}