blob: 0023100d8ec547bbfb0b509a048028ae50c645c9 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#include "Notifier.h"
9#include "Timer.h"
10#include "Utility.h"
11#include "WPIErrors.h"
12#include "HAL/HAL.hpp"
13
Brian Silverman26e4e522015-12-17 01:56:40 -050014/**
15 * Create a Notifier for timer event notification.
16 * @param handler The handler is called at the notification time which is set
17 * using StartSingle or StartPeriodic.
18 */
Brian Silverman1a675112016-02-20 20:42:49 -050019Notifier::Notifier(TimerEventHandler handler) {
Brian Silverman26e4e522015-12-17 01:56:40 -050020 if (handler == nullptr)
21 wpi_setWPIErrorWithContext(NullParameter, "handler must not be nullptr");
22 m_handler = handler;
Brian Silverman1a675112016-02-20 20:42:49 -050023 int32_t status = 0;
24 m_notifier = initializeNotifier(&Notifier::Notify, this, &status);
25 wpi_setErrorWithContext(status, getHALErrorMessage(status));
Brian Silverman26e4e522015-12-17 01:56:40 -050026}
27
28/**
29 * Free the resources for a timer event.
Brian Silverman26e4e522015-12-17 01:56:40 -050030 */
31Notifier::~Notifier() {
Brian Silverman1a675112016-02-20 20:42:49 -050032 int32_t status = 0;
33 cleanNotifier(m_notifier, &status);
34 wpi_setErrorWithContext(status, getHALErrorMessage(status));
Brian Silverman26e4e522015-12-17 01:56:40 -050035
Brian Silverman1a675112016-02-20 20:42:49 -050036 /* Acquire the mutex; this makes certain that the handler is not being
37 * executed by the interrupt manager.
38 */
Brian Silverman26e4e522015-12-17 01:56:40 -050039 std::lock_guard<priority_mutex> lock(m_handlerMutex);
40}
41
42/**
Brian Silverman1a675112016-02-20 20:42:49 -050043 * Update the HAL alarm time.
Brian Silverman26e4e522015-12-17 01:56:40 -050044 */
45void Notifier::UpdateAlarm() {
Brian Silverman1a675112016-02-20 20:42:49 -050046 int32_t status = 0;
47 updateNotifierAlarm(m_notifier, (uint64_t)(m_expirationTime * 1e6), &status);
48 wpi_setErrorWithContext(status, getHALErrorMessage(status));
Brian Silverman26e4e522015-12-17 01:56:40 -050049}
50
51/**
Brian Silverman1a675112016-02-20 20:42:49 -050052 * Notify is called by the HAL layer. We simply need to pass it through to
53 * the user handler.
Brian Silverman26e4e522015-12-17 01:56:40 -050054 */
Brian Silverman1a675112016-02-20 20:42:49 -050055void Notifier::Notify(uint64_t currentTimeInt, void *param) {
56 Notifier* notifier = static_cast<Notifier*>(param);
Brian Silverman26e4e522015-12-17 01:56:40 -050057
Brian Silverman1a675112016-02-20 20:42:49 -050058 notifier->m_processMutex.lock();
59 if (notifier->m_periodic) {
60 notifier->m_expirationTime += notifier->m_period;
61 notifier->UpdateAlarm();
Brian Silverman26e4e522015-12-17 01:56:40 -050062 }
Brian Silverman26e4e522015-12-17 01:56:40 -050063
Brian Silverman1a675112016-02-20 20:42:49 -050064 auto handler = notifier->m_handler;
Brian Silverman26e4e522015-12-17 01:56:40 -050065
Brian Silverman1a675112016-02-20 20:42:49 -050066 notifier->m_handlerMutex.lock();
67 notifier->m_processMutex.unlock();
68
69 if (handler) handler();
70 notifier->m_handlerMutex.unlock();
Brian Silverman26e4e522015-12-17 01:56:40 -050071}
72
73/**
74 * Register for single event notification.
75 * A timer event is queued for a single event after the specified delay.
76 * @param delay Seconds to wait before the handler is called.
77 */
78void Notifier::StartSingle(double delay) {
Brian Silverman1a675112016-02-20 20:42:49 -050079 std::lock_guard<priority_mutex> sync(m_processMutex);
Brian Silverman26e4e522015-12-17 01:56:40 -050080 m_periodic = false;
81 m_period = delay;
Brian Silverman1a675112016-02-20 20:42:49 -050082 m_expirationTime = GetClock() + m_period;
83 UpdateAlarm();
Brian Silverman26e4e522015-12-17 01:56:40 -050084}
85
86/**
87 * Register for periodic event notification.
88 * A timer event is queued for periodic event notification. Each time the
Brian Silverman1a675112016-02-20 20:42:49 -050089 * interrupt occurs, the event will be immediately requeued for the same time
90 * interval.
Brian Silverman26e4e522015-12-17 01:56:40 -050091 * @param period Period in seconds to call the handler starting one period after
92 * the call to this method.
93 */
94void Notifier::StartPeriodic(double period) {
Brian Silverman1a675112016-02-20 20:42:49 -050095 std::lock_guard<priority_mutex> sync(m_processMutex);
Brian Silverman26e4e522015-12-17 01:56:40 -050096 m_periodic = true;
97 m_period = period;
Brian Silverman1a675112016-02-20 20:42:49 -050098 m_expirationTime = GetClock() + m_period;
99 UpdateAlarm();
Brian Silverman26e4e522015-12-17 01:56:40 -0500100}
101
102/**
103 * Stop timer events from occuring.
104 * Stop any repeating timer events from occuring. This will also remove any
Brian Silverman1a675112016-02-20 20:42:49 -0500105 * single notification events from the queue.
Brian Silverman26e4e522015-12-17 01:56:40 -0500106 * If a timer-based call to the registered handler is in progress, this function
Brian Silverman1a675112016-02-20 20:42:49 -0500107 * will block until the handler call is complete.
Brian Silverman26e4e522015-12-17 01:56:40 -0500108 */
109void Notifier::Stop() {
Brian Silverman1a675112016-02-20 20:42:49 -0500110 int32_t status = 0;
111 stopNotifierAlarm(m_notifier, &status);
112 wpi_setErrorWithContext(status, getHALErrorMessage(status));
113
Brian Silverman26e4e522015-12-17 01:56:40 -0500114 // Wait for a currently executing handler to complete before returning from
115 // Stop()
116 std::lock_guard<priority_mutex> sync(m_handlerMutex);
117}