Squashed 'third_party/allwpilib_2017/' content from commit 35ac87d

Change-Id: I7bb6f5556c30d3f5a092e68de0be9c710c60c9f4
git-subtree-dir: third_party/allwpilib_2017
git-subtree-split: 35ac87d6ff8b7f061c4f18c9ea316e5dccd4888a
diff --git a/hal/lib/athena/cpp/Semaphore.cpp b/hal/lib/athena/cpp/Semaphore.cpp
new file mode 100644
index 0000000..521c816
--- /dev/null
+++ b/hal/lib/athena/cpp/Semaphore.cpp
@@ -0,0 +1,32 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2015-2017. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HAL/cpp/Semaphore.h"
+
+Semaphore::Semaphore(int32_t count) { m_count = count; }
+
+void Semaphore::give() {
+  std::lock_guard<priority_mutex> lock(m_mutex);
+  ++m_count;
+  m_condition.notify_one();
+}
+
+void Semaphore::take() {
+  std::unique_lock<priority_mutex> lock(m_mutex);
+  m_condition.wait(lock, [this] { return m_count; });
+  --m_count;
+}
+
+bool Semaphore::tryTake() {
+  std::lock_guard<priority_mutex> lock(m_mutex);
+  if (m_count) {
+    --m_count;
+    return true;
+  } else {
+    return false;
+  }
+}
diff --git a/hal/lib/athena/cpp/SerialHelper.cpp b/hal/lib/athena/cpp/SerialHelper.cpp
new file mode 100644
index 0000000..5b7e8be
--- /dev/null
+++ b/hal/lib/athena/cpp/SerialHelper.cpp
@@ -0,0 +1,343 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HAL/cpp/SerialHelper.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+
+#include "../visa/visa.h"
+#include "HAL/Errors.h"
+#include "llvm/StringRef.h"
+
+constexpr const char* OnboardResourceVISA = "ASRL1::INSTR";
+constexpr const char* MxpResourceVISA = "ASRL2::INSTR";
+
+constexpr const char* OnboardResourceOS = "/dev/ttyS0";
+constexpr const char* MxpResourceOS = "/dev/ttyS1";
+
+namespace hal {
+std::string SerialHelper::m_usbNames[2]{"", ""};
+
+priority_mutex SerialHelper::m_nameMutex;
+
+SerialHelper::SerialHelper() {
+  viOpenDefaultRM(reinterpret_cast<ViSession*>(&m_resourceHandle));
+}
+
+std::string SerialHelper::GetVISASerialPortName(HAL_SerialPort port,
+                                                int32_t* status) {
+  if (port == HAL_SerialPort::HAL_SerialPort_Onboard) {
+    return OnboardResourceVISA;
+  } else if (port == HAL_SerialPort::HAL_SerialPort_MXP) {
+    return MxpResourceVISA;
+  }
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return error
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+  }
+
+  int32_t visaIndex = GetIndexForPort(port, status);
+  if (visaIndex == -1) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+    // Error
+  } else {
+    return m_visaResource[visaIndex].str();
+  }
+}
+
+std::string SerialHelper::GetOSSerialPortName(HAL_SerialPort port,
+                                              int32_t* status) {
+  if (port == HAL_SerialPort::HAL_SerialPort_Onboard) {
+    return OnboardResourceOS;
+  } else if (port == HAL_SerialPort::HAL_SerialPort_MXP) {
+    return MxpResourceOS;
+  }
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return error
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+  }
+
+  int32_t osIndex = GetIndexForPort(port, status);
+  if (osIndex == -1) {
+    *status = HAL_SERIAL_PORT_NOT_FOUND;
+    return "";
+    // Error
+  } else {
+    return m_osResource[osIndex].str();
+  }
+}
+
+std::vector<std::string> SerialHelper::GetVISASerialPortList(int32_t* status) {
+  std::vector<std::string> retVec;
+
+  // Always add 2 onboard ports
+  retVec.emplace_back(OnboardResourceVISA);
+  retVec.emplace_back(MxpResourceVISA);
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return only onboard list
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = 0;
+    return retVec;
+  }
+
+  for (auto& i : m_visaResource) {
+    retVec.emplace_back(i.str());
+  }
+
+  return retVec;
+}
+
+std::vector<std::string> SerialHelper::GetOSSerialPortList(int32_t* status) {
+  std::vector<std::string> retVec;
+
+  // Always add 2 onboard ports
+  retVec.emplace_back(OnboardResourceOS);
+  retVec.emplace_back(MxpResourceOS);
+
+  QueryHubPaths(status);
+
+  // If paths are empty or status error, return only onboard list
+  if (*status != 0 || m_visaResource.empty() || m_osResource.empty() ||
+      m_sortedHubPath.empty()) {
+    *status = 0;
+    return retVec;
+  }
+
+  for (auto& i : m_osResource) {
+    retVec.emplace_back(i.str());
+  }
+
+  return retVec;
+}
+
+void SerialHelper::SortHubPathVector() {
+  m_sortedHubPath.clear();
+  m_sortedHubPath = m_unsortedHubPath;
+  std::sort(m_sortedHubPath.begin(), m_sortedHubPath.end(),
+            [](const llvm::SmallVectorImpl<char>& lhs,
+               const llvm::SmallVectorImpl<char>& rhs) -> int {
+              llvm::StringRef lhsRef(lhs.begin(), lhs.size());
+              llvm::StringRef rhsRef(rhs.begin(), rhs.size());
+              return lhsRef.compare(rhsRef);
+            });
+}
+
+void SerialHelper::CoiteratedSort(
+    llvm::SmallVectorImpl<llvm::SmallString<16>>& vec) {
+  llvm::SmallVector<llvm::SmallString<16>, 4> sortedVec;
+  for (auto& str : m_sortedHubPath) {
+    for (size_t i = 0; i < m_unsortedHubPath.size(); i++) {
+      if (llvm::StringRef{m_unsortedHubPath[i].begin(),
+                          m_unsortedHubPath[i].size()}
+              .equals(llvm::StringRef{str.begin(), str.size()})) {
+        sortedVec.push_back(vec[i]);
+        break;
+      }
+    }
+  }
+  vec = sortedVec;
+}
+
+void SerialHelper::QueryHubPaths(int32_t* status) {
+  // VISA resource matching string
+  const char* str = "?*";
+  // Items needed for VISA
+  ViUInt32 retCnt = 0;
+  ViFindList viList = 0;
+  ViChar desc[VI_FIND_BUFLEN];
+  *status = viFindRsrc(m_resourceHandle, const_cast<char*>(str), &viList,
+                       &retCnt, desc);
+
+  if (*status < 0) {
+    // Handle the bad status elsewhere
+    // Note let positive statii (warnings) continue
+    goto done;
+  }
+  // Status might be positive, so reset it to 0
+  *status = 0;
+
+  // Storage buffers for Visa calls and system exec calls
+  char osName[256];
+  char execBuffer[128];
+
+  // Loop through all returned VISA objects.
+  // Increment the internal VISA ptr every loop
+  for (size_t i = 0; i < retCnt; i++, viFindNext(viList, desc)) {
+    // Ignore any matches to the 2 onboard ports
+    if (std::strcmp(OnboardResourceVISA, desc) == 0 ||
+        std::strcmp(MxpResourceVISA, desc) == 0) {
+      continue;
+    }
+
+    // Open the resource, grab its interface name, and close it.
+    ViSession vSession;
+    *status = viOpen(m_resourceHandle, desc, VI_NULL, VI_NULL, &vSession);
+    if (*status < 0) goto done;
+    *status = 0;
+
+    *status = viGetAttribute(vSession, VI_ATTR_INTF_INST_NAME, &osName);
+    // Ignore an error here, as we want to close the session on an error
+    // Use a seperate close variable so we can check
+    ViStatus closeStatus = viClose(vSession);
+    if (*status < 0) goto done;
+    if (closeStatus < 0) goto done;
+    *status = 0;
+
+    // split until (/dev/
+    llvm::StringRef devNameRef = llvm::StringRef{osName}.split("(/dev/").second;
+    // String not found, continue
+    if (devNameRef.equals("")) continue;
+
+    // Split at )
+    llvm::StringRef matchString = devNameRef.split(')').first;
+    if (matchString.equals(devNameRef)) continue;
+
+    // Run find using pipe to get a list of system accessors
+    llvm::SmallString<128> val(
+        "sh -c \"find /sys/devices/soc0 | grep amba | grep usb | grep ");
+    val += matchString;
+    val += "\"";
+
+    // Pipe code found on StackOverflow
+    // http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c-using-posix
+
+    // Using std::string because this is guarenteed to be large
+    std::string output = "";
+
+    std::shared_ptr<FILE> pipe(popen(val.c_str(), "r"), pclose);
+    // Just check the next item on a pipe failure
+    if (!pipe) continue;
+    while (!feof(pipe.get())) {
+      if (std::fgets(execBuffer, 128, pipe.get()) != 0) output += execBuffer;
+    }
+
+    if (!output.empty()) {
+      llvm::SmallVector<llvm::StringRef, 16> pathSplitVec;
+      // Split output by line, grab first line, and split it into
+      // individual directories
+      llvm::StringRef{output}.split('\n').first.split(pathSplitVec, '/', -1,
+                                                      false);
+
+      // Find each individual item index
+
+      const char* usb1 = "usb1";
+      const char* tty = "tty";
+
+      int findusb = -1;
+      int findtty = -1;
+      int findregex = -1;
+      for (size_t i = 0; i < pathSplitVec.size(); i++) {
+        if (findusb == -1 && pathSplitVec[i].equals(usb1)) {
+          findusb = i;
+        }
+        if (findtty == -1 && pathSplitVec[i].equals(tty)) {
+          findtty = i;
+        }
+        if (findregex == -1 && pathSplitVec[i].equals(matchString)) {
+          findregex = i;
+        }
+      }
+
+      // Get the index for our device
+      int hubIndex = findtty;
+      if (findtty == -1) hubIndex = findregex;
+
+      int devStart = findusb + 1;
+
+      if (hubIndex < devStart) continue;
+
+      // Add our devices to our list
+      m_unsortedHubPath.emplace_back(
+          llvm::StringRef{pathSplitVec[hubIndex - 2]});
+      m_visaResource.emplace_back(desc);
+      m_osResource.emplace_back(
+          llvm::StringRef{osName}.split("(").second.split(")").first);
+    }
+  }
+
+  SortHubPathVector();
+
+  CoiteratedSort(m_visaResource);
+  CoiteratedSort(m_osResource);
+done:
+  viClose(viList);
+}
+
+int32_t SerialHelper::GetIndexForPort(HAL_SerialPort port, int32_t* status) {
+  // Hold lock whenever we're using the names array
+  std::lock_guard<priority_mutex> lock(m_nameMutex);
+
+  std::string portString = m_usbNames[port - 2];
+
+  llvm::SmallVector<int32_t, 4> indices;
+
+  // If port has not been assigned, find the one to assign
+  if (portString.empty()) {
+    for (size_t i = 0; i < 2; i++) {
+      // Remove all used ports
+      auto idx = std::find(m_sortedHubPath.begin(), m_sortedHubPath.end(),
+                           m_usbNames[i]);
+      if (idx != m_sortedHubPath.end()) {
+        // found
+        m_sortedHubPath.erase(idx);
+      }
+      if (m_usbNames[i] == "") {
+        indices.push_back(i);
+      }
+    }
+
+    int32_t idx = -1;
+    for (size_t i = 0; i < indices.size(); i++) {
+      if (indices[i] == port - 2) {
+        idx = i;
+        break;
+      }
+    }
+
+    if (idx == -1) {
+      *status = HAL_SERIAL_PORT_NOT_FOUND;
+      return -1;
+    }
+
+    if (idx >= static_cast<int32_t>(m_sortedHubPath.size())) {
+      *status = HAL_SERIAL_PORT_NOT_FOUND;
+      return -1;
+    }
+
+    portString = m_sortedHubPath[idx].str();
+    m_usbNames[port - 2] = portString;
+  }
+
+  int retIndex = -1;
+
+  for (size_t i = 0; i < m_sortedHubPath.size(); i++) {
+    if (m_sortedHubPath[i].equals(portString)) {
+      retIndex = i;
+      break;
+    }
+  }
+
+  return retIndex;
+}
+
+}  // namespace hal
diff --git a/hal/lib/athena/cpp/priority_mutex.cpp b/hal/lib/athena/cpp/priority_mutex.cpp
new file mode 100644
index 0000000..1213898
--- /dev/null
+++ b/hal/lib/athena/cpp/priority_mutex.cpp
@@ -0,0 +1,28 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "HAL/cpp/priority_mutex.h"
+
+void priority_recursive_mutex::lock() { pthread_mutex_lock(&m_mutex); }
+
+void priority_recursive_mutex::unlock() { pthread_mutex_unlock(&m_mutex); }
+
+bool priority_recursive_mutex::try_lock() noexcept {
+  return !pthread_mutex_trylock(&m_mutex);
+}
+
+pthread_mutex_t* priority_recursive_mutex::native_handle() { return &m_mutex; }
+
+void priority_mutex::lock() { pthread_mutex_lock(&m_mutex); }
+
+void priority_mutex::unlock() { pthread_mutex_unlock(&m_mutex); }
+
+bool priority_mutex::try_lock() noexcept {
+  return !pthread_mutex_trylock(&m_mutex);
+}
+
+pthread_mutex_t* priority_mutex::native_handle() { return &m_mutex; }