Rename our allwpilib (which is now 2020) to not have 2019 in the name

Change-Id: I3c07f85ed32ab8b97db765a9b43f2a6ce7da964a
diff --git a/hal/src/main/native/sim/Interrupts.cpp b/hal/src/main/native/sim/Interrupts.cpp
new file mode 100644
index 0000000..a7dd285
--- /dev/null
+++ b/hal/src/main/native/sim/Interrupts.cpp
@@ -0,0 +1,569 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "hal/Interrupts.h"
+
+#include <memory>
+
+#include <wpi/condition_variable.h>
+
+#include "AnalogInternal.h"
+#include "DigitalInternal.h"
+#include "ErrorsInternal.h"
+#include "HALInitializer.h"
+#include "MockHooksInternal.h"
+#include "PortsInternal.h"
+#include "hal/AnalogTrigger.h"
+#include "hal/Errors.h"
+#include "hal/Value.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+#include "hal/handles/UnlimitedHandleResource.h"
+#include "mockdata/AnalogInDataInternal.h"
+#include "mockdata/DIODataInternal.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4996 4018 6297 26451 4334)
+#endif
+
+using namespace hal;
+
+enum WaitResult {
+  Timeout = 0x0,
+  RisingEdge = 0x1,
+  FallingEdge = 0x100,
+  Both = 0x101,
+};
+
+namespace {
+struct Interrupt {
+  bool isAnalog;
+  HAL_Handle portHandle;
+  uint8_t index;
+  HAL_AnalogTriggerType trigType;
+  bool watcher;
+  int64_t risingTimestamp;
+  int64_t fallingTimestamp;
+  bool previousState;
+  bool fireOnUp;
+  bool fireOnDown;
+  int32_t callbackId;
+
+  void* callbackParam;
+  HAL_InterruptHandlerFunction callbackFunction;
+};
+
+struct SynchronousWaitData {
+  HAL_InterruptHandle interruptHandle{HAL_kInvalidHandle};
+  wpi::condition_variable waitCond;
+  HAL_Bool waitPredicate{false};
+};
+}  // namespace
+
+static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+                             HAL_HandleEnum::Interrupt>* interruptHandles;
+
+typedef HAL_Handle SynchronousWaitDataHandle;
+static UnlimitedHandleResource<SynchronousWaitDataHandle, SynchronousWaitData,
+                               HAL_HandleEnum::Vendor>*
+    synchronousInterruptHandles;
+
+namespace hal {
+namespace init {
+void InitializeInterrupts() {
+  static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+                               HAL_HandleEnum::Interrupt>
+      iH;
+  interruptHandles = &iH;
+  static UnlimitedHandleResource<SynchronousWaitDataHandle, SynchronousWaitData,
+                                 HAL_HandleEnum::Vendor>
+      siH;
+  synchronousInterruptHandles = &siH;
+}
+}  // namespace init
+}  // namespace hal
+
+extern "C" {
+HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
+                                             int32_t* status) {
+  hal::init::CheckInit();
+  HAL_InterruptHandle handle = interruptHandles->Allocate();
+  if (handle == HAL_kInvalidHandle) {
+    *status = NO_AVAILABLE_RESOURCES;
+    return HAL_kInvalidHandle;
+  }
+  auto anInterrupt = interruptHandles->Get(handle);
+  if (anInterrupt == nullptr) {  // would only occur on thread issue.
+    *status = HAL_HANDLE_ERROR;
+    return HAL_kInvalidHandle;
+  }
+
+  anInterrupt->index = getHandleIndex(handle);
+  anInterrupt->callbackId = -1;
+
+  anInterrupt->watcher = watcher;
+
+  return handle;
+}
+void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
+                          int32_t* status) {
+  HAL_DisableInterrupts(interruptHandle, status);
+  auto anInterrupt = interruptHandles->Get(interruptHandle);
+  interruptHandles->Free(interruptHandle);
+  if (anInterrupt == nullptr) {
+    return nullptr;
+  }
+  return anInterrupt->callbackParam;
+}
+
+static void ProcessInterruptDigitalSynchronous(const char* name, void* param,
+                                               const struct HAL_Value* value) {
+  // void* is a SynchronousWaitDataHandle.
+  // convert to uintptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  SynchronousWaitDataHandle handle =
+      static_cast<SynchronousWaitDataHandle>(handleTmp);
+  auto interruptData = synchronousInterruptHandles->Get(handle);
+  if (interruptData == nullptr) return;
+  auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_BOOLEAN) return;
+  bool retVal = value->data.v_boolean;
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  // If its a falling change, and we dont fire on falling return
+  if (interrupt->previousState && !interrupt->fireOnDown) return;
+  // If its a rising change, and we dont fire on rising return.
+  if (!interrupt->previousState && !interrupt->fireOnUp) return;
+
+  interruptData->waitPredicate = true;
+
+  // Pulse interrupt
+  interruptData->waitCond.notify_all();
+}
+
+static double GetAnalogTriggerValue(HAL_Handle triggerHandle,
+                                    HAL_AnalogTriggerType type,
+                                    int32_t* status) {
+  return HAL_GetAnalogTriggerOutput(triggerHandle, type, status);
+}
+
+static void ProcessInterruptAnalogSynchronous(const char* name, void* param,
+                                              const struct HAL_Value* value) {
+  // void* is a SynchronousWaitDataHandle.
+  // convert to uintptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  SynchronousWaitDataHandle handle =
+      static_cast<SynchronousWaitDataHandle>(handleTmp);
+  auto interruptData = synchronousInterruptHandles->Get(handle);
+  if (interruptData == nullptr) return;
+  auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_DOUBLE) return;
+  int32_t status = 0;
+  bool retVal = GetAnalogTriggerValue(interrupt->portHandle,
+                                      interrupt->trigType, &status);
+  if (status != 0) {
+    // Interrupt and Cancel
+    interruptData->waitPredicate = true;
+    // Pulse interrupt
+    interruptData->waitCond.notify_all();
+  }
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  // If its a falling change, and we dont fire on falling return
+  if (interrupt->previousState && !interrupt->fireOnDown) return;
+  // If its a rising change, and we dont fire on rising return.
+  if (!interrupt->previousState && !interrupt->fireOnUp) return;
+
+  interruptData->waitPredicate = true;
+
+  // Pulse interrupt
+  interruptData->waitCond.notify_all();
+}
+
+static int64_t WaitForInterruptDigital(HAL_InterruptHandle handle,
+                                       Interrupt* interrupt, double timeout,
+                                       bool ignorePrevious) {
+  auto data = std::make_shared<SynchronousWaitData>();
+
+  auto dataHandle = synchronousInterruptHandles->Allocate(data);
+  if (dataHandle == HAL_kInvalidHandle) {
+    // Error allocating data
+    return WaitResult::Timeout;
+  }
+
+  // auto data = synchronousInterruptHandles->Get(dataHandle);
+  data->waitPredicate = false;
+  data->interruptHandle = handle;
+
+  int32_t status = 0;
+
+  int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
+
+  if (status != 0) return WaitResult::Timeout;
+
+  interrupt->previousState = SimDIOData[digitalIndex].value;
+
+  int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
+      &ProcessInterruptDigitalSynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(dataHandle)), false);
+
+  bool timedOut = false;
+
+  wpi::mutex waitMutex;
+
+  auto timeoutTime =
+      std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
+
+  {
+    std::unique_lock lock(waitMutex);
+    while (!data->waitPredicate) {
+      if (data->waitCond.wait_until(lock, timeoutTime) ==
+          std::cv_status::timeout) {
+        timedOut = true;
+        break;
+      }
+    }
+  }
+
+  // Cancel our callback
+  SimDIOData[digitalIndex].value.CancelCallback(uid);
+  (void)synchronousInterruptHandles->Free(dataHandle);
+
+  // Check for what to return
+  if (timedOut) return WaitResult::Timeout;
+  // True => false, Falling
+  if (interrupt->previousState) {
+    // Set our return value and our timestamps
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    return 1 << (8 + interrupt->index);
+  } else {
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    return 1 << (interrupt->index);
+  }
+}
+
+static int64_t WaitForInterruptAnalog(HAL_InterruptHandle handle,
+                                      Interrupt* interrupt, double timeout,
+                                      bool ignorePrevious) {
+  auto data = std::make_shared<SynchronousWaitData>();
+
+  auto dataHandle = synchronousInterruptHandles->Allocate(data);
+  if (dataHandle == HAL_kInvalidHandle) {
+    // Error allocating data
+    return WaitResult::Timeout;
+  }
+
+  data->waitPredicate = false;
+  data->interruptHandle = handle;
+
+  int32_t status = 0;
+  interrupt->previousState = GetAnalogTriggerValue(
+      interrupt->portHandle, interrupt->trigType, &status);
+
+  if (status != 0) return WaitResult::Timeout;
+
+  int32_t analogIndex =
+      GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
+
+  if (status != 0) return WaitResult::Timeout;
+
+  int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
+      &ProcessInterruptAnalogSynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(dataHandle)), false);
+
+  bool timedOut = false;
+
+  wpi::mutex waitMutex;
+
+  auto timeoutTime =
+      std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
+
+  {
+    std::unique_lock lock(waitMutex);
+    while (!data->waitPredicate) {
+      if (data->waitCond.wait_until(lock, timeoutTime) ==
+          std::cv_status::timeout) {
+        timedOut = true;
+        break;
+      }
+    }
+  }
+
+  // Cancel our callback
+  SimAnalogInData[analogIndex].voltage.CancelCallback(uid);
+  (void)synchronousInterruptHandles->Free(dataHandle);
+
+  // Check for what to return
+  if (timedOut) return WaitResult::Timeout;
+  // True => false, Falling
+  if (interrupt->previousState) {
+    // Set our return value and our timestamps
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    return 1 << (8 + interrupt->index);
+  } else {
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    return 1 << (interrupt->index);
+  }
+}
+
+int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
+                             double timeout, HAL_Bool ignorePrevious,
+                             int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return WaitResult::Timeout;
+  }
+
+  // Check to make sure we are actually an interrupt in synchronous mode
+  if (!interrupt->watcher) {
+    *status = NiFpga_Status_InvalidParameter;
+    return WaitResult::Timeout;
+  }
+
+  if (interrupt->isAnalog) {
+    return WaitForInterruptAnalog(interruptHandle, interrupt.get(), timeout,
+                                  ignorePrevious);
+  } else {
+    return WaitForInterruptDigital(interruptHandle, interrupt.get(), timeout,
+                                   ignorePrevious);
+  }
+}
+
+static void ProcessInterruptDigitalAsynchronous(const char* name, void* param,
+                                                const struct HAL_Value* value) {
+  // void* is a HAL handle
+  // convert to uintptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
+  auto interrupt = interruptHandles->Get(handle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_BOOLEAN) return;
+  bool retVal = value->data.v_boolean;
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  int32_t mask = 0;
+  if (interrupt->previousState) {
+    interrupt->previousState = retVal;
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    mask = 1 << (8 + interrupt->index);
+    if (!interrupt->fireOnDown) return;
+  } else {
+    interrupt->previousState = retVal;
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    mask = 1 << (interrupt->index);
+    if (!interrupt->fireOnUp) return;
+  }
+
+  // run callback
+  auto callback = interrupt->callbackFunction;
+  if (callback == nullptr) return;
+  callback(mask, interrupt->callbackParam);
+}
+
+static void ProcessInterruptAnalogAsynchronous(const char* name, void* param,
+                                               const struct HAL_Value* value) {
+  // void* is a HAL handle
+  // convert to intptr_t first, then to handle
+  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+  HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
+  auto interrupt = interruptHandles->Get(handle);
+  if (interrupt == nullptr) return;
+  // Have a valid interrupt
+  if (value->type != HAL_Type::HAL_DOUBLE) return;
+  int32_t status = 0;
+  bool retVal = GetAnalogTriggerValue(interrupt->portHandle,
+                                      interrupt->trigType, &status);
+  if (status != 0) return;
+  // If no change in interrupt, return;
+  if (retVal == interrupt->previousState) return;
+  int mask = 0;
+  if (interrupt->previousState) {
+    interrupt->previousState = retVal;
+    interrupt->fallingTimestamp = hal::GetFPGATime();
+    if (!interrupt->fireOnDown) return;
+    mask = 1 << (8 + interrupt->index);
+  } else {
+    interrupt->previousState = retVal;
+    interrupt->risingTimestamp = hal::GetFPGATime();
+    if (!interrupt->fireOnUp) return;
+    mask = 1 << (interrupt->index);
+  }
+
+  // run callback
+  auto callback = interrupt->callbackFunction;
+  if (callback == nullptr) return;
+  callback(mask, interrupt->callbackParam);
+}
+
+static void EnableInterruptsDigital(HAL_InterruptHandle handle,
+                                    Interrupt* interrupt) {
+  int32_t status = 0;
+  int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
+  if (status != 0) return;
+
+  interrupt->previousState = SimDIOData[digitalIndex].value;
+
+  int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
+      &ProcessInterruptDigitalAsynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
+  interrupt->callbackId = uid;
+}
+
+static void EnableInterruptsAnalog(HAL_InterruptHandle handle,
+                                   Interrupt* interrupt) {
+  int32_t status = 0;
+  int32_t analogIndex =
+      GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
+  if (status != 0) return;
+
+  status = 0;
+  interrupt->previousState = GetAnalogTriggerValue(
+      interrupt->portHandle, interrupt->trigType, &status);
+  if (status != 0) return;
+
+  int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
+      &ProcessInterruptAnalogAsynchronous,
+      reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
+  interrupt->callbackId = uid;
+}
+
+void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
+                          int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // If we have not had a callback set, error out
+  if (interrupt->callbackFunction == nullptr) {
+    *status = INCOMPATIBLE_STATE;
+    return;
+  }
+
+  // EnableInterrupts has already been called
+  if (interrupt->callbackId >= 0) {
+    // We can double enable safely.
+    return;
+  }
+
+  if (interrupt->isAnalog) {
+    EnableInterruptsAnalog(interruptHandle, interrupt.get());
+  } else {
+    EnableInterruptsDigital(interruptHandle, interrupt.get());
+  }
+}
+void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
+                           int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  // No need to disable if we are already disabled
+  if (interrupt->callbackId < 0) return;
+
+  if (interrupt->isAnalog) {
+    // Do analog
+    int32_t status = 0;
+    int32_t analogIndex =
+        GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
+    if (status != 0) return;
+    SimAnalogInData[analogIndex].voltage.CancelCallback(interrupt->callbackId);
+  } else {
+    int32_t status = 0;
+    int32_t digitalIndex =
+        GetDigitalInputChannel(interrupt->portHandle, &status);
+    if (status != 0) return;
+    SimDIOData[digitalIndex].value.CancelCallback(interrupt->callbackId);
+  }
+  interrupt->callbackId = -1;
+}
+int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
+                                         int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return interrupt->risingTimestamp;
+}
+int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
+                                          int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return interrupt->fallingTimestamp;
+}
+void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
+                           HAL_Handle digitalSourceHandle,
+                           HAL_AnalogTriggerType analogTriggerType,
+                           int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  bool routingAnalogTrigger = false;
+  uint8_t routingChannel = 0;
+  uint8_t routingModule = 0;
+  bool success =
+      remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
+                         routingModule, routingAnalogTrigger);
+  if (!success) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  interrupt->isAnalog = routingAnalogTrigger;
+  interrupt->trigType = analogTriggerType;
+  interrupt->portHandle = digitalSourceHandle;
+}
+void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
+                                HAL_InterruptHandlerFunction handler,
+                                void* param, int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  interrupt->callbackFunction = handler;
+  interrupt->callbackParam = param;
+}
+
+void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
+                                        HAL_InterruptHandlerFunction handler,
+                                        void* param, int32_t* status) {
+  HAL_AttachInterruptHandler(interruptHandle, handler, param, status);
+}
+
+void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
+                                  HAL_Bool risingEdge, HAL_Bool fallingEdge,
+                                  int32_t* status) {
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  interrupt->fireOnDown = fallingEdge;
+  interrupt->fireOnUp = risingEdge;
+}
+}  // extern "C"