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/wpilibc/athena/src/Notifier.cpp b/wpilibc/athena/src/Notifier.cpp
new file mode 100644
index 0000000..67abe37
--- /dev/null
+++ b/wpilibc/athena/src/Notifier.cpp
@@ -0,0 +1,141 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008-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 "Notifier.h"
+
+#include "HAL/HAL.h"
+#include "Timer.h"
+#include "Utility.h"
+#include "WPIErrors.h"
+
+using namespace frc;
+
+priority_mutex Notifier::m_destructorMutex;
+
+/**
+ * Create a Notifier for timer event notification.
+ *
+ * @param handler The handler is called at the notification time which is set
+ * using StartSingle or StartPeriodic.
+ */
+Notifier::Notifier(TimerEventHandler handler) {
+ if (handler == nullptr)
+ wpi_setWPIErrorWithContext(NullParameter, "handler must not be nullptr");
+ m_handler = handler;
+ int32_t status = 0;
+ m_notifier = HAL_InitializeNotifier(&Notifier::Notify, this, &status);
+ wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
+}
+
+/**
+ * Free the resources for a timer event.
+ */
+Notifier::~Notifier() {
+ int32_t status = 0;
+ // atomically set handle to 0, then clean
+ HAL_NotifierHandle handle = m_notifier.exchange(0);
+ HAL_CleanNotifier(handle, &status);
+ wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
+
+ /* Acquire the mutex; this makes certain that the handler is not being
+ * executed by the interrupt manager.
+ */
+ std::lock_guard<priority_mutex> lockStatic(Notifier::m_destructorMutex);
+ std::lock_guard<priority_mutex> lock(m_processMutex);
+}
+
+/**
+ * Update the HAL alarm time.
+ */
+void Notifier::UpdateAlarm() {
+ int32_t status = 0;
+ // Return if we are being destructed, or were not created successfully
+ if (m_notifier == 0) return;
+ HAL_UpdateNotifierAlarm(
+ m_notifier, static_cast<uint64_t>(m_expirationTime * 1e6), &status);
+ wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
+}
+
+/**
+ * Notify is called by the HAL layer. We simply need to pass it through to
+ * the user handler.
+ */
+void Notifier::Notify(uint64_t currentTimeInt, HAL_NotifierHandle handle) {
+ Notifier* notifier;
+ {
+ // Lock static mutex to grab the notifier param
+ std::lock_guard<priority_mutex> lock(Notifier::m_destructorMutex);
+ int32_t status = 0;
+ auto notifierPointer = HAL_GetNotifierParam(handle, &status);
+ if (notifierPointer == nullptr) return;
+ notifier = static_cast<Notifier*>(notifierPointer);
+ notifier->m_processMutex.lock();
+ }
+
+ if (notifier->m_periodic) {
+ notifier->m_expirationTime += notifier->m_period;
+ notifier->UpdateAlarm();
+ }
+
+ auto handler = notifier->m_handler;
+
+ if (handler) handler();
+ notifier->m_processMutex.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.
+ */
+void Notifier::StartSingle(double delay) {
+ std::lock_guard<priority_mutex> sync(m_processMutex);
+ m_periodic = false;
+ m_period = delay;
+ m_expirationTime = GetClock() + m_period;
+ UpdateAlarm();
+}
+
+/**
+ * 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.
+ */
+void Notifier::StartPeriodic(double period) {
+ std::lock_guard<priority_mutex> sync(m_processMutex);
+ m_periodic = true;
+ m_period = period;
+ m_expirationTime = GetClock() + m_period;
+ UpdateAlarm();
+}
+
+/**
+ * Stop timer events from occuring.
+ *
+ * Stop any repeating timer events from occuring. 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.
+ */
+void Notifier::Stop() {
+ int32_t status = 0;
+ HAL_StopNotifierAlarm(m_notifier, &status);
+ wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
+
+ // Wait for a currently executing handler to complete before returning from
+ // Stop()
+ std::lock_guard<priority_mutex> lockStatic(Notifier::m_destructorMutex);
+ std::lock_guard<priority_mutex> lock(m_processMutex);
+}