Now you can download a copy of these docs so you can use them offline! Download now
Notifier.cpp
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2008. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
5 /*----------------------------------------------------------------------------*/
6 
7 #include "Notifier.h"
8 #include "Timer.h"
9 #include "Utility.h"
10 #include "WPIErrors.h"
11 
12 const uint32_t Notifier::kTimerInterruptNumber;
13 Notifier *Notifier::timerQueueHead = NULL;
14 ReentrantSemaphore Notifier::queueSemaphore;
15 tAlarm *Notifier::talarm = NULL;
16 tInterruptManager *Notifier::manager = NULL;
17 int Notifier::refcount = 0;
18 
24 Notifier::Notifier(TimerEventHandler handler, void *param)
25 {
26  if (handler == NULL)
27  wpi_setWPIErrorWithContext(NullParameter, "handler must not be NULL");
28  m_handler = handler;
29  m_param = param;
30  m_periodic = false;
31  m_expirationTime = 0;
32  m_period = 0;
33  m_nextEvent = NULL;
34  m_queued = false;
35  m_handlerSemaphore = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
36  tRioStatusCode localStatus = NiFpga_Status_Success;
37  {
38  Synchronized sync(queueSemaphore);
39  // do the first time intialization of static variables
40  if (refcount == 0)
41  {
42  manager = new tInterruptManager(1 << kTimerInterruptNumber, false, &localStatus);
43  manager->registerHandler(ProcessQueue, NULL, &localStatus);
44  manager->enable(&localStatus);
45  talarm = tAlarm::create(&localStatus);
46  }
47  refcount++;
48  }
49  wpi_setError(localStatus);
50 }
51 
58 {
59  tRioStatusCode localStatus = NiFpga_Status_Success;
60  {
61  Synchronized sync(queueSemaphore);
62  DeleteFromQueue();
63 
64  // Delete the static variables when the last one is going away
65  if (!(--refcount))
66  {
67  talarm->writeEnable(false, &localStatus);
68  delete talarm;
69  talarm = NULL;
70  manager->disable(&localStatus);
71  delete manager;
72  manager = NULL;
73  }
74  }
75  wpi_setError(localStatus);
76 
77  // Acquire the semaphore; this makes certain that the handler is
78  // not being executed by the interrupt manager.
79  semTake(m_handlerSemaphore, WAIT_FOREVER);
80  // Delete while holding the semaphore so there can be no race.
81  semDelete(m_handlerSemaphore);
82 }
83 
91 void Notifier::UpdateAlarm()
92 {
93  if (timerQueueHead != NULL)
94  {
95  tRioStatusCode localStatus = NiFpga_Status_Success;
96  // write the first item in the queue into the trigger time
97  talarm->writeTriggerTime((uint32_t)(timerQueueHead->m_expirationTime * 1e6), &localStatus);
98  // Enable the alarm. The hardware disables itself after each alarm.
99  talarm->writeEnable(true, &localStatus);
100  wpi_setStaticError(timerQueueHead, localStatus);
101  }
102 }
103 
110 void Notifier::ProcessQueue(uint32_t mask, void *params)
111 {
112  Notifier *current;
113  while (true) // keep processing past events until no more
114  {
115  {
116  Synchronized sync(queueSemaphore);
117  double currentTime = GetClock();
118  current = timerQueueHead;
119  if (current == NULL || current->m_expirationTime > currentTime)
120  {
121  break; // no more timer events to process
122  }
123  // need to process this entry
124  timerQueueHead = current->m_nextEvent;
125  if (current->m_periodic)
126  {
127  // if periodic, requeue the event
128  // compute when to put into queue
129  current->InsertInQueue(true);
130  }
131  else
132  {
133  // not periodic; removed from queue
134  current->m_queued = false;
135  }
136  // Take handler semaphore while holding queue semaphore to make sure
137  // the handler will execute to completion in case we are being deleted.
138  semTake(current->m_handlerSemaphore, WAIT_FOREVER);
139  }
140 
141  current->m_handler(current->m_param); // call the event handler
142  semGive(current->m_handlerSemaphore);
143  }
144  // reschedule the first item in the queue
145  Synchronized sync(queueSemaphore);
146  UpdateAlarm();
147 }
148 
158 void Notifier::InsertInQueue(bool reschedule)
159 {
160  if (reschedule)
161  {
162  m_expirationTime += m_period;
163  }
164  else
165  {
166  m_expirationTime = GetClock() + m_period;
167  }
168  if (timerQueueHead == NULL || timerQueueHead->m_expirationTime >= this->m_expirationTime)
169  {
170  // the queue is empty or greater than the new entry
171  // the new entry becomes the first element
172  this->m_nextEvent = timerQueueHead;
173  timerQueueHead = this;
174  if (!reschedule)
175  {
176  // since the first element changed, update alarm, unless we already plan to
177  UpdateAlarm();
178  }
179  }
180  else
181  {
182  for (Notifier **npp = &(timerQueueHead->m_nextEvent); ; npp = &(*npp)->m_nextEvent)
183  {
184  Notifier *n = *npp;
185  if (n == NULL || n->m_expirationTime > this->m_expirationTime)
186  {
187  *npp = this;
188  this->m_nextEvent = n;
189  break;
190  }
191  }
192  }
193  m_queued = true;
194 }
195 
203 void Notifier::DeleteFromQueue()
204 {
205  if (m_queued)
206  {
207  m_queued = false;
208  wpi_assert(timerQueueHead != NULL);
209  if (timerQueueHead == this)
210  {
211  // remove the first item in the list - update the alarm
212  timerQueueHead = this->m_nextEvent;
213  UpdateAlarm();
214  }
215  else
216  {
217  for (Notifier *n = timerQueueHead; n != NULL; n = n->m_nextEvent)
218  {
219  if (n->m_nextEvent == this)
220  {
221  // this element is the next element from *n from the queue
222  n->m_nextEvent = this->m_nextEvent; // point around this one
223  }
224  }
225  }
226  }
227 }
228 
234 void Notifier::StartSingle(double delay)
235 {
236  Synchronized sync(queueSemaphore);
237  m_periodic = false;
238  m_period = delay;
239  DeleteFromQueue();
240  InsertInQueue(false);
241 }
242 
249 void Notifier::StartPeriodic(double period)
250 {
251  Synchronized sync(queueSemaphore);
252  m_periodic = true;
253  m_period = period;
254  DeleteFromQueue();
255  InsertInQueue(false);
256 }
257 
266 {
267  {
268  Synchronized sync(queueSemaphore);
269  DeleteFromQueue();
270  }
271  // Wait for a currently executing handler to complete before returning from Stop()
272  Synchronized sync(m_handlerSemaphore);
273 }
void StartPeriodic(double period)
Definition: Notifier.cpp:249
Notifier(TimerEventHandler handler, void *param=NULL)
Definition: Notifier.cpp:24
void Stop()
Definition: Notifier.cpp:265
void StartSingle(double delay)
Definition: Notifier.cpp:234
virtual ~Notifier()
Definition: Notifier.cpp:57

Generated on Sat Apr 26 2014 12:26:45 for WPILibC++ by doxygen 1.8.6