Rename our allwpilib (which is now 2020) to not have 2019 in the name
Change-Id: I3c07f85ed32ab8b97db765a9b43f2a6ce7da964a
diff --git a/hal/src/main/native/athena/Interrupts.cpp b/hal/src/main/native/athena/Interrupts.cpp
new file mode 100644
index 0000000..78d518c
--- /dev/null
+++ b/hal/src/main/native/athena/Interrupts.cpp
@@ -0,0 +1,271 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2016-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/SafeThread.h>
+
+#include "DigitalInternal.h"
+#include "HALInitializer.h"
+#include "PortsInternal.h"
+#include "hal/ChipObject.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/handles/LimitedHandleResource.h"
+
+using namespace hal;
+
+namespace {
+// Safe thread to allow callbacks to run on their own thread
+class InterruptThread : public wpi::SafeThread {
+ public:
+ void Main() {
+ std::unique_lock lock(m_mutex);
+ while (m_active) {
+ m_cond.wait(lock, [&] { return !m_active || m_notify; });
+ if (!m_active) break;
+ m_notify = false;
+ HAL_InterruptHandlerFunction handler = m_handler;
+ uint32_t mask = m_mask;
+ void* param = m_param;
+ lock.unlock(); // don't hold mutex during callback execution
+ handler(mask, param);
+ lock.lock();
+ }
+ }
+
+ bool m_notify = false;
+ HAL_InterruptHandlerFunction m_handler;
+ void* m_param;
+ uint32_t m_mask;
+};
+
+class InterruptThreadOwner : public wpi::SafeThreadOwner<InterruptThread> {
+ public:
+ void SetFunc(HAL_InterruptHandlerFunction handler, void* param) {
+ auto thr = GetThread();
+ if (!thr) return;
+ thr->m_handler = handler;
+ thr->m_param = param;
+ }
+
+ void Notify(uint32_t mask) {
+ auto thr = GetThread();
+ if (!thr) return;
+ thr->m_mask = mask;
+ thr->m_notify = true;
+ thr->m_cond.notify_one();
+ }
+};
+
+struct Interrupt {
+ std::unique_ptr<tInterrupt> anInterrupt;
+ std::unique_ptr<tInterruptManager> manager;
+ std::unique_ptr<InterruptThreadOwner> threadOwner = nullptr;
+ void* param = nullptr;
+};
+
+} // namespace
+
+static void threadedInterruptHandler(uint32_t mask, void* param) {
+ static_cast<InterruptThreadOwner*>(param)->Notify(mask);
+}
+
+static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+ HAL_HandleEnum::Interrupt>* interruptHandles;
+
+namespace hal {
+namespace init {
+void InitialzeInterrupts() {
+ static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
+ HAL_HandleEnum::Interrupt>
+ iH;
+ interruptHandles = &iH;
+}
+} // namespace init
+} // namespace hal
+
+extern "C" {
+
+HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
+ int32_t* status) {
+ hal::init::CheckInit();
+ HAL_InterruptHandle handle = interruptHandles->Allocate();
+ if (handle == HAL_kInvalidHandle) {
+ *status = NO_AVAILABLE_RESOURCES;
+ return HAL_kInvalidHandle;
+ }
+ auto anInterrupt = interruptHandles->Get(handle);
+ uint32_t interruptIndex = static_cast<uint32_t>(getHandleIndex(handle));
+ // Expects the calling leaf class to allocate an interrupt index.
+ anInterrupt->anInterrupt.reset(tInterrupt::create(interruptIndex, status));
+ anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
+ anInterrupt->manager = std::make_unique<tInterruptManager>(
+ (1u << interruptIndex) | (1u << (interruptIndex + 8u)), watcher, status);
+ return handle;
+}
+
+void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
+ int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ interruptHandles->Free(interruptHandle);
+ if (anInterrupt == nullptr) {
+ return nullptr;
+ }
+
+ if (anInterrupt->manager->isEnabled(status)) {
+ anInterrupt->manager->disable(status);
+ }
+
+ void* param = anInterrupt->param;
+ return param;
+}
+
+int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
+ double timeout, HAL_Bool ignorePrevious,
+ int32_t* status) {
+ uint32_t result;
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return 0;
+ }
+
+ result = anInterrupt->manager->watch(static_cast<int32_t>(timeout * 1e3),
+ ignorePrevious, status);
+
+ // Don't report a timeout as an error - the return code is enough to tell
+ // that a timeout happened.
+ if (*status == -NiFpga_Status_IrqTimeout) {
+ *status = NiFpga_Status_Success;
+ }
+
+ return result;
+}
+
+void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
+ int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return;
+ }
+
+ if (!anInterrupt->manager->isEnabled(status)) {
+ anInterrupt->manager->enable(status);
+ }
+}
+
+void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
+ int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return;
+ }
+ if (anInterrupt->manager->isEnabled(status)) {
+ anInterrupt->manager->disable(status);
+ }
+}
+
+int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
+ int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return 0;
+ }
+ uint32_t timestamp = anInterrupt->anInterrupt->readRisingTimeStamp(status);
+ return timestamp;
+}
+
+int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
+ int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return 0;
+ }
+ uint32_t timestamp = anInterrupt->anInterrupt->readFallingTimeStamp(status);
+ return timestamp;
+}
+
+void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
+ HAL_Handle digitalSourceHandle,
+ HAL_AnalogTriggerType analogTriggerType,
+ int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return;
+ }
+ anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
+ bool routingAnalogTrigger = false;
+ uint8_t routingChannel = 0;
+ uint8_t routingModule = 0;
+ bool success =
+ remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
+ routingModule, routingAnalogTrigger);
+ if (!success) {
+ *status = HAL_HANDLE_ERROR;
+ return;
+ }
+ anInterrupt->anInterrupt->writeConfig_Source_AnalogTrigger(
+ routingAnalogTrigger, status);
+ anInterrupt->anInterrupt->writeConfig_Source_Channel(routingChannel, status);
+ anInterrupt->anInterrupt->writeConfig_Source_Module(routingModule, status);
+}
+
+void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
+ HAL_InterruptHandlerFunction handler,
+ void* param, int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return;
+ }
+ anInterrupt->manager->registerHandler(handler, param, status);
+ anInterrupt->param = param;
+}
+
+void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interrupt_handle,
+ HAL_InterruptHandlerFunction handler,
+ void* param, int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interrupt_handle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return;
+ }
+
+ anInterrupt->threadOwner = std::make_unique<InterruptThreadOwner>();
+ anInterrupt->threadOwner->Start();
+ anInterrupt->threadOwner->SetFunc(handler, param);
+
+ HAL_AttachInterruptHandler(interrupt_handle, threadedInterruptHandler,
+ anInterrupt->threadOwner.get(), status);
+
+ if (*status != 0) {
+ anInterrupt->threadOwner = nullptr;
+ }
+ anInterrupt->param = param;
+}
+
+void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
+ HAL_Bool risingEdge, HAL_Bool fallingEdge,
+ int32_t* status) {
+ auto anInterrupt = interruptHandles->Get(interruptHandle);
+ if (anInterrupt == nullptr) {
+ *status = HAL_HANDLE_ERROR;
+ return;
+ }
+ anInterrupt->anInterrupt->writeConfig_RisingEdge(risingEdge, status);
+ anInterrupt->anInterrupt->writeConfig_FallingEdge(fallingEdge, status);
+}
+
+} // extern "C"