Added support for 2017 WPILib.

Change-Id: Ib22e31d0999b123c65498c31c654e3fa7bab4798
diff --git a/NO_BUILD_AMD64 b/NO_BUILD_AMD64
index 3edc6fe..f4faeab 100644
--- a/NO_BUILD_AMD64
+++ b/NO_BUILD_AMD64
@@ -1,6 +1,8 @@
 -//third_party:wpilib
 -//third_party/allwpilib_2016/...
 -//third_party/ntcore_2016/...
+-//third_party/allwpilib_2017/...
+-//third_party/ntcore_2017/...
 -//frc971/wpilib/...
 -//y2012/wpilib/...
 -//y2012:download
diff --git a/WORKSPACE b/WORKSPACE
index 0d4eb2f..01187a5 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -62,16 +62,29 @@
 )
 
 new_http_archive(
-  name = 'allwpilib_ni_libraries_repo',
-  build_file = 'debian/ni-libraries.BUILD',
+  name = 'allwpilib_ni_libraries_repo_2016',
+  build_file = 'debian/ni-libraries-2016.BUILD',
   sha256 = '821687afbee2d7531fb3e47d8d58ac10005695e59685be3ac3aa00b3179faf52',
   url = 'http://frc971.org/Build-Dependencies/allwpilib_ni-libraries_20749ed.tar.gz',
   strip_prefix = 'ni-libraries',
 )
 
 bind(
-  name = 'ni-libraries',
-  actual = '@allwpilib_ni_libraries_repo//:ni-libraries',
+  name = 'ni-libraries-2016',
+  actual = '@allwpilib_ni_libraries_repo_2016//:ni-libraries',
+)
+
+new_http_archive(
+  name = 'allwpilib_ni_libraries_repo_2017',
+  build_file = 'debian/ni-libraries-2017.BUILD',
+  sha256 = '67c1ad365fb712cc0acb0bf43465b831030523dc6f88daa02626994f644d91eb',
+  url = 'http://frc971.org/Build-Dependencies/allwpilib_ni-libraries_e375b4a.tar.gz',
+  strip_prefix = 'ni-libraries',
+)
+
+bind(
+  name = 'ni-libraries-2017',
+  actual = '@allwpilib_ni_libraries_repo_2017//:ni-libraries',
 )
 
 # Downloaded from:
diff --git a/debian/ni-libraries.BUILD b/debian/ni-libraries-2016.BUILD
similarity index 100%
rename from debian/ni-libraries.BUILD
rename to debian/ni-libraries-2016.BUILD
diff --git a/debian/ni-libraries-2017.BUILD b/debian/ni-libraries-2017.BUILD
new file mode 100644
index 0000000..9d79098
--- /dev/null
+++ b/debian/ni-libraries-2017.BUILD
@@ -0,0 +1,20 @@
+cc_library(
+  name = 'ni-libraries',
+  visibility = ['//visibility:public'],
+  srcs = [
+    'lib/libFRC_NetworkCommunication.so.17.0.0',
+    'lib/libRoboRIO_FRC_ChipObject.so.17.0.0',
+    'lib/libNiFpgaLv.so.16.0.0',
+    'lib/libNiFpga.so.16.0.0',
+    'lib/libNiRioSrv.so.16.0.0',
+    'lib/libspi.so.1.0.0',
+    'lib/libi2c.so.2.0.0',
+    'lib/libniriosession.so.16.0.0',
+    'lib/libniriodevenum.so.16.0.0',
+  ],
+  includes = [
+    'include',
+  ],
+  hdrs = glob(['include/**']),
+  linkstatic = True,
+)
diff --git a/doc/allwpilib_ni-libraries_tarball.sh b/doc/allwpilib_ni-libraries_tarball.sh
index 61fccd4..07058a0 100755
--- a/doc/allwpilib_ni-libraries_tarball.sh
+++ b/doc/allwpilib_ni-libraries_tarball.sh
@@ -3,8 +3,7 @@
 # A script to generate a allwpilib_ni-libraries_bla.tar.gz file from a given
 # revision of allwpilib.
 
-# Example: ./doc/allwpilib_ni-libraries_tarball.sh \
-#   https://usfirst.collab.net/gerrit/allwpilib master
+# Example: `./doc/allwpilib_ni-libraries_tarball.sh https://github.com/wpilibsuite/allwpilib master`
 
 set -e
 set -u
diff --git a/doc/allwpilib_subtree.sh b/doc/allwpilib_subtree.sh
index aa83d0c..7f79dc0 100755
--- a/doc/allwpilib_subtree.sh
+++ b/doc/allwpilib_subtree.sh
@@ -7,8 +7,7 @@
 # The implementation running `git filter-branch` over allwpilib's entire history
 # isn't the fastest thing ever, but it's not all that bad.
 
-# Example: ./doc/allwpilib_subtree.sh add third_party/allwpilib_2016 \
-#   https://usfirst.collab.net/gerrit/allwpilib master
+# Example: `./doc/allwpilib_subtree.sh add third_party/allwpilib_2017 https://github.com/wpilibsuite/allwpilib master`
 
 set -e
 set -u
@@ -26,8 +25,18 @@
 
 git fetch "${REMOTE}" "${REF}"
 
-readonly REMOVE_DIRECTORIES="ni-libraries wpilibj wpilibjIntegrationTests gradle"
-readonly TREE_FILTER="$(for d in ${REMOVE_DIRECTORIES}; do
+readonly REMOVE_DIRECTORIES=(
+ni-libraries
+wpilibj
+wpilibjIntegrationTests
+gradle
+simulation
+myRobot
+myRobotCpp
+gen
+test-scripts
+)
+readonly TREE_FILTER="$(for d in "${REMOVE_DIRECTORIES[@]}"}; do
   echo "if [ -d $d ]; then git rm -rf $d; fi && "
 done)"
 git filter-branch --tree-filter "${TREE_FILTER}true" FETCH_HEAD
diff --git a/frc971/wpilib/buffered_pcm.cc b/frc971/wpilib/buffered_pcm.cc
index 35df795..2ddbfa7 100644
--- a/frc971/wpilib/buffered_pcm.cc
+++ b/frc971/wpilib/buffered_pcm.cc
@@ -22,8 +22,8 @@
 
 void BufferedPcm::Flush() {
   LOG(DEBUG, "sending solenoids 0x%" PRIx8 "\n", values_);
-#ifdef WPILIB2015
-  SolenoidBase::Set(values_, 0xFF);
+#ifdef WPILIB2017
+  SolenoidBase::SetAll(m_moduleNumber, values_);
 #else
   SolenoidBase::Set(values_, 0xFF, m_moduleNumber);
 #endif
diff --git a/frc971/wpilib/dma.cc b/frc971/wpilib/dma.cc
index ea9f64c..dbbfc56 100644
--- a/frc971/wpilib/dma.cc
+++ b/frc971/wpilib/dma.cc
@@ -8,6 +8,9 @@
 #include "DigitalSource.h"
 #include "AnalogInput.h"
 #include "Encoder.h"
+#ifdef WPILIB2017
+#include "HAL/HAL.h"
+#endif
 
 // Interface to the roboRIO FPGA's DMA features.
 
@@ -22,14 +25,13 @@
   };
 } t1Output;
 
-static const uint32_t kNumHeaders = 10;
+static const int32_t kNumHeaders = 10;
 
-#ifdef WPILIB2015
-static constexpr ssize_t kChannelSize[18] = {2, 2, 4, 4, 2, 2, 4, 4, 3, 3,
-                                             2, 1, 4, 4, 4, 4, 4, 4};
-#else
 static constexpr ssize_t kChannelSize[20] = {2, 2, 4, 4, 2, 2, 4, 4, 3, 3,
                                              2, 1, 4, 4, 4, 4, 4, 4, 4, 4};
+
+#ifndef WPILIB2017
+#define HAL_GetErrorMessage getHALErrorMessage
 #endif
 
 enum DMAOffsetConstants {
@@ -49,25 +51,17 @@
   kEnable_Counters_High = 13,
   kEnable_CounterTimers_Low = 14,
   kEnable_CounterTimers_High = 15,
-#ifdef WPILIB2015
-  kEnable_Encoders = 16,
-  kEnable_EncoderTimers = 17,
-#else
   kEnable_Encoders_Low = 16,
   kEnable_Encoders_High = 17,
   kEnable_EncoderTimers_Low = 18,
   kEnable_EncoderTimers_High = 19,
-#endif
 };
 
 DMA::DMA() {
   tRioStatusCode status = 0;
   tdma_config_ = tDMA::create(&status);
   tdma_config_->writeConfig_ExternalClock(false, &status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
-#ifdef WPILIB2015
-  NiFpga_WriteU32(0x10000, 0x1832c, 0x0);
-#endif
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
   if (status != 0) {
     return;
   }
@@ -85,7 +79,7 @@
 void DMA::SetPause(bool pause) {
   tRioStatusCode status = 0;
   tdma_config_->writeConfig_Pause(pause, &status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
 }
 
 void DMA::SetRate(uint32_t cycles) {
@@ -94,7 +88,7 @@
   }
   tRioStatusCode status = 0;
   tdma_config_->writeRate(cycles, &status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
 }
 
 void DMA::Add(Encoder *encoder) {
@@ -107,17 +101,6 @@
   }
   const int index = encoder->GetFPGAIndex();
 
-#ifdef WPILIB2015
-  if (index < 4) {
-    // TODO(austin): Encoder uses a Counter for 1x or 2x; quad for 4x...
-    tdma_config_->writeConfig_Enable_Encoders(true, &status);
-  } else {
-    wpi_setErrorWithContext(
-        NiFpga_Status_InvalidParameter,
-        "FPGA encoder index is not in the 4 that get logged.");
-    return;
-  }
-#else
   if (index < 4) {
     // TODO(austin): Encoder uses a Counter for 1x or 2x; quad for 4x...
     tdma_config_->writeConfig_Enable_Encoders_Low(true, &status);
@@ -130,9 +113,8 @@
         "FPGA encoder index is not in the 4 that get logged.");
     return;
   }
-#endif
 
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
 }
 
 void DMA::Add(DigitalSource * /*input*/) {
@@ -145,7 +127,7 @@
   }
 
   tdma_config_->writeConfig_Enable_DI(true, &status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
 }
 
 void DMA::Add(AnalogInput *input) {
@@ -162,7 +144,7 @@
   } else {
     tdma_config_->writeConfig_Enable_AI0_High(true, &status);
   }
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
 }
 
 void DMA::SetExternalTrigger(DigitalSource *input, bool rising, bool falling) {
@@ -190,13 +172,13 @@
   if (status == 0) {
     if (!is_external_clock) {
       tdma_config_->writeConfig_ExternalClock(true, &status);
-      wpi_setErrorWithContext(status, getHALErrorMessage(status));
+      wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
       if (status != 0) {
         return;
       }
     }
   } else {
-    wpi_setErrorWithContext(status, getHALErrorMessage(status));
+    wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
     return;
   }
 
@@ -206,7 +188,12 @@
   new_trigger.RisingEdge = rising;
   new_trigger.ExternalClockSource_AnalogTrigger = false;
   unsigned char module = 0;
-  unsigned char channel = input->GetChannelForRouting();
+  uint32_t channel =
+#ifdef WPILIB2017
+      input->GetChannel();
+#else
+      input->GetChannelForRouting();
+#endif
   if (channel >= kNumHeaders) {
     module = 1;
     channel -= kNumHeaders;
@@ -218,29 +205,12 @@
   new_trigger.ExternalClockSource_Channel = channel;
 
 // Configures the trigger to be external, not off the FPGA clock.
-#ifndef WPILIB2015
   tdma_config_->writeExternalTriggers(channel_index / 4, channel_index % 4,
                                       new_trigger, &status);
   if (status != 0) {
-    wpi_setErrorWithContext(status, getHALErrorMessage(status));
+    wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
     return;
   }
-#else
-  uint32_t current_triggers;
-  tRioStatusCode register_status =
-      NiFpga_ReadU32(0x10000, 0x1832c, &current_triggers);
-  if (register_status != 0) {
-    wpi_setErrorWithContext(register_status, getHALErrorMessage(status));
-    return;
-  }
-  current_triggers = (current_triggers & ~(0xff << (channel_index * 8))) |
-                     (new_trigger.value << (channel_index * 8));
-  register_status = NiFpga_WriteU32(0x10000, 0x1832c, current_triggers);
-  if (register_status != 0) {
-    wpi_setErrorWithContext(register_status, getHALErrorMessage(status));
-    return;
-  }
-#endif
 }
 
 DMA::ReadStatus DMA::Read(DMASample *sample, uint32_t timeout_ms,
@@ -269,7 +239,7 @@
   } else if (status == NiFpga_Status_FifoTimeout) {
     return STATUS_TIMEOUT;
   } else {
-    wpi_setErrorWithContext(status, getHALErrorMessage(status));
+    wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
     return STATUS_ERROR;
   }
 }
@@ -286,7 +256,7 @@
 void DMA::Start(size_t queue_depth) {
   tRioStatusCode status = 0;
   tconfig_ = tdma_config_->readConfig(&status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
   if (status != 0) {
     return;
   }
@@ -317,15 +287,10 @@
     SET_SIZE(Enable_Counters_High);
     SET_SIZE(Enable_CounterTimers_Low);
     SET_SIZE(Enable_CounterTimers_High);
-#ifdef WPILIB2015
-    SET_SIZE(Enable_Encoders);
-    SET_SIZE(Enable_EncoderTimers);
-#else
     SET_SIZE(Enable_Encoders_Low);
     SET_SIZE(Enable_Encoders_High);
     SET_SIZE(Enable_EncoderTimers_Low);
     SET_SIZE(Enable_EncoderTimers_High);
-#endif
 #undef SET_SIZE
     capture_size_ = accum_size + 1;
   }
@@ -333,23 +298,23 @@
   manager_.reset(
       new nFPGA::tDMAManager(0, queue_depth * capture_size_, &status));
 
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
   if (status != 0) {
     return;
   }
   // Start, stop, start to clear the buffer.
   manager_->start(&status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
   if (status != 0) {
     return;
   }
   manager_->stop(&status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
   if (status != 0) {
     return;
   }
   manager_->start(&status);
-  wpi_setErrorWithContext(status, getHALErrorMessage(status));
+  wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
   if (status != 0) {
     return;
   }
@@ -372,36 +337,30 @@
   if (offset(kEnable_DI) == -1) {
     wpi_setStaticErrorWithContext(
         dma_, NiFpga_Status_ResourceNotFound,
-        getHALErrorMessage(NiFpga_Status_ResourceNotFound));
+        HAL_GetErrorMessage(NiFpga_Status_ResourceNotFound));
     return false;
   }
-  if (input->GetChannelForRouting() < kNumHeaders) {
-    return (read_buffer_[offset(kEnable_DI)] >> input->GetChannelForRouting()) &
-           0x1;
+  const uint32_t channel =
+#ifdef WPILIB2017
+      input->GetChannel();
+#else
+      input->GetChannelForRouting();
+#endif
+  if (channel < kNumHeaders) {
+    return (read_buffer_[offset(kEnable_DI)] >> channel) & 0x1;
   } else {
-    return (read_buffer_[offset(kEnable_DI)] >>
-            (input->GetChannelForRouting() + 6)) &
-           0x1;
+    return (read_buffer_[offset(kEnable_DI)] >> (channel + 6)) & 0x1;
   }
 }
 
 int32_t DMASample::GetRaw(Encoder *input) const {
   int index = input->GetFPGAIndex();
   uint32_t dmaWord = 0;
-#ifdef WPILIB2015
-  if (index >= 4 || offset(kEnable_Encoders) == -1) {
-    wpi_setStaticErrorWithContext(
-        dma_, NiFpga_Status_ResourceNotFound,
-        getHALErrorMessage(NiFpga_Status_ResourceNotFound));
-    return -1;
-  }
-  dmaWord = read_buffer_[offset(kEnable_Encoders) + index];
-#else
   if (index < 4) {
     if (offset(kEnable_Encoders_Low) == -1) {
       wpi_setStaticErrorWithContext(
           dma_, NiFpga_Status_ResourceNotFound,
-          getHALErrorMessage(NiFpga_Status_ResourceNotFound));
+          HAL_GetErrorMessage(NiFpga_Status_ResourceNotFound));
       return -1;
     }
     dmaWord = read_buffer_[offset(kEnable_Encoders_Low) + index];
@@ -409,17 +368,16 @@
     if (offset(kEnable_Encoders_High) == -1) {
       wpi_setStaticErrorWithContext(
           dma_, NiFpga_Status_ResourceNotFound,
-          getHALErrorMessage(NiFpga_Status_ResourceNotFound));
+          HAL_GetErrorMessage(NiFpga_Status_ResourceNotFound));
       return -1;
     }
     dmaWord = read_buffer_[offset(kEnable_Encoders_High) + (index - 4)];
   } else {
     wpi_setStaticErrorWithContext(
         dma_, NiFpga_Status_ResourceNotFound,
-        getHALErrorMessage(NiFpga_Status_ResourceNotFound));
+        HAL_GetErrorMessage(NiFpga_Status_ResourceNotFound));
     return 0;
   }
-#endif
 
   int32_t result = 0;
 
@@ -448,7 +406,7 @@
     if (offset(kEnable_AI0_Low) == -1) {
       wpi_setStaticErrorWithContext(
           dma_, NiFpga_Status_ResourceNotFound,
-          getHALErrorMessage(NiFpga_Status_ResourceNotFound));
+          HAL_GetErrorMessage(NiFpga_Status_ResourceNotFound));
       return 0xffff;
     }
     dmaWord = read_buffer_[offset(kEnable_AI0_Low) + channel / 2];
@@ -456,14 +414,14 @@
     if (offset(kEnable_AI0_High) == -1) {
       wpi_setStaticErrorWithContext(
           dma_, NiFpga_Status_ResourceNotFound,
-          getHALErrorMessage(NiFpga_Status_ResourceNotFound));
+          HAL_GetErrorMessage(NiFpga_Status_ResourceNotFound));
       return 0xffff;
     }
     dmaWord = read_buffer_[offset(kEnable_AI0_High) + (channel - 4) / 2];
   } else {
     wpi_setStaticErrorWithContext(
         dma_, NiFpga_Status_ResourceNotFound,
-        getHALErrorMessage(NiFpga_Status_ResourceNotFound));
+        HAL_GetErrorMessage(NiFpga_Status_ResourceNotFound));
     return 0xffff;
   }
   if (channel % 2) {
diff --git a/frc971/wpilib/dma.h b/frc971/wpilib/dma.h
index 970497c..e07ab36 100644
--- a/frc971/wpilib/dma.h
+++ b/frc971/wpilib/dma.h
@@ -9,13 +9,30 @@
 #include <array>
 #include <memory>
 
+#ifdef WPILIB2017
+#include "HAL/ChipObject.h"
+#else
 #include "ChipObject.h"
+#endif
 #include "ErrorBase.h"
 
 class DMA;
+#ifdef WPILIB2017
+namespace frc {
 class DigitalSource;
 class AnalogInput;
 class Encoder;
+}  // namespace frc
+#else
+class DigitalSource;
+class AnalogInput;
+class Encoder;
+namespace frc {
+using ::DigitalSource;
+using ::AnalogInput;
+using ::Encoder;
+}  // namespace frc
+#endif
 
 // A POD class which stores the data from a DMA sample and provides safe ways to
 // access it.
diff --git a/frc971/wpilib/interrupt_edge_counting.cc b/frc971/wpilib/interrupt_edge_counting.cc
index 5c10b89..ec6f627 100644
--- a/frc971/wpilib/interrupt_edge_counting.cc
+++ b/frc971/wpilib/interrupt_edge_counting.cc
@@ -21,7 +21,11 @@
 
 void EdgeCounter::operator()() {
   ::aos::SetCurrentThreadName("EdgeCounter_" +
+#ifdef WPILIB2017
+                              ::std::to_string(input_->GetChannel()));
+#else
                               ::std::to_string(input_->GetChannelForRouting()));
+#endif
 
   input_->RequestInterrupts();
   input_->SetUpSourceEdge(true, true);
@@ -55,7 +59,11 @@
       current_value_ = hall_value;
     } else {
       LOG(WARNING, "Detected spurious edge on %d.  Dropping it.\n",
+#ifdef WPILIB2017
+          input_->GetChannel());
+#else
           input_->GetChannelForRouting());
+#endif
     }
   }
 }
diff --git a/frc971/wpilib/joystick_sender.cc b/frc971/wpilib/joystick_sender.cc
index 4942eaa..b4866e9 100644
--- a/frc971/wpilib/joystick_sender.cc
+++ b/frc971/wpilib/joystick_sender.cc
@@ -6,7 +6,11 @@
 #include "aos/common/logging/queue_logging.h"
 
 #include "DriverStation.h"
+#ifdef WPILIB2017
+#include "HAL/HAL.h"
+#else
 #include "HAL/HAL.hpp"
+#endif
 
 namespace frc971 {
 namespace wpilib {
@@ -27,8 +31,13 @@
     ds->WaitForData();
     auto new_state = ::aos::joystick_state.MakeMessage();
 
+#ifdef WPILIB2017
+    HAL_ControlWord control_word;
+    HAL_GetControlWord(&control_word);
+#else
     HALControlWord control_word;
     HALGetControlWord(&control_word);
+#endif
     new_state->test_mode = control_word.test;
     new_state->fms_attached = control_word.fmsAttached;
     new_state->enabled = control_word.enabled;
diff --git a/frc971/wpilib/wpilib_interface.cc b/frc971/wpilib/wpilib_interface.cc
index 016f52f..af72f7d 100644
--- a/frc971/wpilib/wpilib_interface.cc
+++ b/frc971/wpilib/wpilib_interface.cc
@@ -7,15 +7,25 @@
 #include "ControllerPower.h"
 #undef ERROR
 
+#ifndef WPILIB2017
+namespace frc {
+using ::DriverStation;
+}  // namespace frc
+#endif
+
 namespace frc971 {
 namespace wpilib {
 
-void SendRobotState(int32_t my_pid, DriverStation *ds) {
+void SendRobotState(int32_t my_pid, frc::DriverStation *ds) {
   auto new_state = ::aos::robot_state.MakeMessage();
 
   new_state->reader_pid = my_pid;
   new_state->outputs_enabled = ds->IsSysActive();
+#ifdef WPILIB2017
+  new_state->browned_out = ds->IsBrownedOut();
+#else
   new_state->browned_out = ds->IsSysBrownedOut();
+#endif
 
   new_state->is_3v3_active = ControllerPower::GetEnabled3V3();
   new_state->is_5v_active = ControllerPower::GetEnabled5V();
diff --git a/frc971/wpilib/wpilib_interface.h b/frc971/wpilib/wpilib_interface.h
index 216bf09..1c55cc7 100644
--- a/frc971/wpilib/wpilib_interface.h
+++ b/frc971/wpilib/wpilib_interface.h
@@ -3,13 +3,22 @@
 
 #include <stdint.h>
 
+#ifdef WPILIB2017
+namespace frc {
 class DriverStation;
+}  // namespace frc
+#else
+class DriverStation;
+namespace frc {
+using ::DriverStation;
+}  // namespace frc
+#endif
 
 namespace frc971 {
 namespace wpilib {
 
 // Sends out a message on ::aos::robot_state.
-void SendRobotState(int32_t my_pid, DriverStation *ds);
+void SendRobotState(int32_t my_pid, ::frc::DriverStation *ds);
 
 }  // namespace wpilib
 }  // namespace frc971
diff --git a/third_party/BUILD b/third_party/BUILD
index da60a79..cef6fcf 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -1,6 +1,6 @@
 cc_library(
   name = 'wpilib',
-  deps = ['//third_party/allwpilib_2016:wpilib'],
+  deps = ['//third_party/allwpilib_2017:wpilib'],
   visibility = ['//visibility:public'],
   linkstatic = True,
 )
diff --git a/third_party/allwpilib_2016/BUILD b/third_party/allwpilib_2016/BUILD
index 2d789d7..fbe00dc 100644
--- a/third_party/allwpilib_2016/BUILD
+++ b/third_party/allwpilib_2016/BUILD
@@ -78,7 +78,7 @@
  ],
  deps = [
    '//third_party/ntcore_2016:ntcore',
-   '//external:ni-libraries',
+   '//external:ni-libraries-2016',
    '//aos/common/logging',
  ],
  hdrs = _h_hdrs + _hpp_hdrs + ['wpilibc/shared/include/Task.inc'],
diff --git a/third_party/allwpilib_2017/BUILD b/third_party/allwpilib_2017/BUILD
new file mode 100644
index 0000000..054ef08
--- /dev/null
+++ b/third_party/allwpilib_2017/BUILD
@@ -0,0 +1,113 @@
+licenses(['notice'])
+
+genrule(
+  name = 'wpilib_version',
+  outs = ['shared/src/WPILibVersion.cpp'],
+  cmd = '\n'.join([
+    "cat > \"$@\" << EOF",
+    "// Autogenerated file! Do not manually edit this file.",
+    "#include \"WPILibVersion.h\"",
+    "const char *WPILibVersion = \"2017-frc971\";",
+    "EOF",
+  ]),
+)
+
+_header_dirs = [
+  'wpilibc/shared/include',
+  'wpilibc/athena/include',
+  'hal/include',
+  'hal/lib/athena',
+]
+
+# Names of WPILib "devices" I don't want to deal with making trivial updates to
+# chop out various ugliness or have to vet for sanity.
+_excluded_devices = [
+  'ADXL345_I2C',
+  'GearTooth',
+  'Ultrasonic',
+  'Victor',
+  'TalonSRX',
+  'CANTalon',
+  'CANJaguar',
+  'PIDController',
+  'Spark',
+  'Servo',
+  'VictorSP',
+  'SD540',
+  'RobotDrive',
+  'Jaguar',
+  'ADXL345_SPI',
+  'DoubleSolenoid',
+  'AnalogPotentiometer',
+  'ADXL362',
+  'AnalogGyro',
+  'AnalogAccelerometer',
+  'CameraServer',
+  'ADXRS450_Gyro',
+  'GyroBase',
+  'IterativeRobot',
+]
+
+# Whole subdirectories of WPILib we don't want around.
+_excluded_shared_directories = [
+  'SmartDashboard',
+  'LiveWindow',
+  'Commands',
+  'Buttons',
+  'Filters',
+]
+
+# Header files we don't want to have.
+_bad_hdrs = ([
+  'wpilibc/athena/include/WPILib.h',
+] + ['wpilibc/shared/include/%s/**/*' % d
+     for d in _excluded_shared_directories] +
+ ['wpilibc/*/include/%s.h' % d for d in _excluded_devices])
+_h_hdrs = glob([d + '/**/*.h' for d in _header_dirs], exclude=_bad_hdrs)
+_hpp_hdrs = glob([d + '/**/*.hpp' for d in _header_dirs], exclude=_bad_hdrs)
+
+cc_library(
+  name = 'wpilib',
+  visibility = ['//third_party:__pkg__'],
+  srcs = glob([
+    'wpilibc/athena/src/*.cpp',
+    'wpilibc/athena/src/Internal/*.cpp',
+    'wpilibc/shared/src/**/*.cpp',
+
+    'hal/lib/athena/*.cpp',
+    'hal/lib/athena/cpp/*.cpp',
+    'hal/lib/athena/ctre/*.cpp',
+    'hal/lib/shared/handles/*.cpp',
+  ], exclude = (
+    ['wpilibc/shared/src/%s/**/*' % d for d in _excluded_shared_directories] +
+    ['wpilibc/*/src/%s.cpp' % d for d in _excluded_devices]
+  )) + [
+    ':wpilib_version',
+  ],
+  copts = [
+    '-Wno-unused-parameter',
+    '-Wno-switch-enum',
+    '-Wno-attributes',
+    '-Wno-cast-align',
+    '-Wno-cast-qual',
+    '-Wno-deprecated-declarations',
+    '-Wno-error',
+    '-Wno-unused-const-variable',
+  ],
+  deps = [
+    '//third_party/ntcore_2017:ntcore',
+    '//external:ni-libraries-2017',
+    '//aos/common/logging',
+  ],
+  hdrs = _h_hdrs + _hpp_hdrs + [
+    'wpilibc/shared/include/CircularBuffer.inc',
+    'wpilibc/athena/include/Task.inc',
+  ],
+  includes = _header_dirs,
+  linkopts = [
+    '-lpthread',
+  ],
+  defines = [
+    'WPILIB2017=1',
+  ],
+)
diff --git a/third_party/allwpilib_2017/hal/lib/athena/HAL.cpp b/third_party/allwpilib_2017/hal/lib/athena/HAL.cpp
index 708ca1b..45fa6ce 100644
--- a/third_party/allwpilib_2017/hal/lib/athena/HAL.cpp
+++ b/third_party/allwpilib_2017/hal/lib/athena/HAL.cpp
@@ -36,8 +36,6 @@
 static std::unique_ptr<tSysWatchdog> watchdog;
 
 static priority_mutex timeMutex;
-static uint32_t timeEpoch = 0;
-static uint32_t prevFPGATime = 0;
 static HAL_NotifierHandle rolloverNotifier = 0;
 
 using namespace hal;
@@ -224,14 +222,7 @@
     *status = NiFpga_Status_ResourceNotInitialized;
     return 0;
   }
-  std::lock_guard<priority_mutex> lock(timeMutex);
-  uint32_t fpgaTime = global->readLocalTime(status);
-  if (*status != 0) return 0;
-  // check for rollover
-  if (fpgaTime < prevFPGATime) ++timeEpoch;
-  prevFPGATime = fpgaTime;
-  return static_cast<uint64_t>(timeEpoch) << 32 |
-         static_cast<uint64_t>(fpgaTime);
+  return global->readLocalTime(status);
 }
 
 /**
diff --git a/third_party/allwpilib_2017/wpilibc/athena/include/DriverStation.h b/third_party/allwpilib_2017/wpilibc/athena/include/DriverStation.h
index 6bd2ea6..f38b299 100644
--- a/third_party/allwpilib_2017/wpilibc/athena/include/DriverStation.h
+++ b/third_party/allwpilib_2017/wpilibc/athena/include/DriverStation.h
@@ -96,8 +96,6 @@
 
  private:
   DriverStation();
-  void ReportJoystickUnpluggedError(llvm::StringRef message);
-  void ReportJoystickUnpluggedWarning(llvm::StringRef message);
   void Run();
   void UpdateControlWord(bool force, HAL_ControlWord& controlWord) const;
 
@@ -136,8 +134,6 @@
   mutable HAL_ControlWord m_controlWordCache;
   mutable std::chrono::steady_clock::time_point m_lastControlWordUpdate;
   mutable priority_mutex m_controlWordMutex;
-
-  double m_nextMessageTime = 0;
 };
 
 }  // namespace frc
diff --git a/third_party/allwpilib_2017/wpilibc/athena/src/DriverStation.cpp b/third_party/allwpilib_2017/wpilibc/athena/src/DriverStation.cpp
index fd91d95..95d20b7 100644
--- a/third_party/allwpilib_2017/wpilibc/athena/src/DriverStation.cpp
+++ b/third_party/allwpilib_2017/wpilibc/athena/src/DriverStation.cpp
@@ -97,9 +97,6 @@
     lock.release();
     if (axis >= HAL_kMaxJoystickAxes)
       wpi_setWPIError(BadJoystickAxis);
-    else
-      ReportJoystickUnpluggedWarning(
-          "Joystick Axis missing, check if all controllers are plugged in");
     return 0.0;
   }
 
@@ -122,9 +119,6 @@
     lock.unlock();
     if (pov >= HAL_kMaxJoystickPOVs)
       wpi_setWPIError(BadJoystickAxis);
-    else
-      ReportJoystickUnpluggedWarning(
-          "Joystick POV missing, check if all controllers are plugged in");
     return -1;
   }
 
@@ -159,17 +153,12 @@
     return false;
   }
   if (button == 0) {
-    ReportJoystickUnpluggedError(
-        "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
     return false;
   }
   std::unique_lock<priority_mutex> lock(m_joystickDataMutex);
   if (button > m_joystickButtons[stick].count) {
     // Unlock early so error printing isn't locked.
     lock.unlock();
-    ReportJoystickUnpluggedWarning(
-        "Joystick Button missing, check if all controllers are "
-        "plugged in");
     return false;
   }
 
@@ -597,31 +586,6 @@
   m_dsThread = std::thread(&DriverStation::Run, this);
 }
 
-/**
- * Reports errors related to unplugged joysticks
- * Throttles the errors so that they don't overwhelm the DS
- */
-void DriverStation::ReportJoystickUnpluggedError(llvm::StringRef message) {
-  double currentTime = Timer::GetFPGATimestamp();
-  if (currentTime > m_nextMessageTime) {
-    ReportError(message);
-    m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
-  }
-}
-
-/**
- * Reports errors related to unplugged joysticks.
- *
- * Throttles the errors so that they don't overwhelm the DS.
- */
-void DriverStation::ReportJoystickUnpluggedWarning(llvm::StringRef message) {
-  double currentTime = Timer::GetFPGATimestamp();
-  if (currentTime > m_nextMessageTime) {
-    ReportWarning(message);
-    m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
-  }
-}
-
 void DriverStation::Run() {
   m_isRunning = true;
   int period = 0;
diff --git a/third_party/ntcore_2017/BUILD b/third_party/ntcore_2017/BUILD
new file mode 100644
index 0000000..82f3545
--- /dev/null
+++ b/third_party/ntcore_2017/BUILD
@@ -0,0 +1,28 @@
+licenses(['notice'])
+
+cc_library(
+  name = 'ntcore',
+  visibility = ['//visibility:public'],
+  srcs = glob([
+    'src/**/*.cpp',
+    'src/**/*.h',
+    'wpiutil/src/**/*.cpp',
+  ], exclude = [
+    'src/networktables/**',
+  ]),
+  copts = [
+    '-Wno-switch-enum',
+    '-Wno-cast-align',
+  ],
+  hdrs = glob([
+    'include/**/*.h',
+    'wpiutil/include/**/*.h',
+  ]),
+  includes = [
+    'include',
+    'wpiutil/include',
+  ],
+  linkopts = [
+    '-lpthread',
+  ],
+)