Now you can download a copy of these docs so you can use them offline! Download now
Notifier.cpp
00001 /*----------------------------------------------------------------------------*/ 00002 /* Copyright (c) FIRST 2008. All Rights Reserved. */ 00003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 00004 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ 00005 /*----------------------------------------------------------------------------*/ 00006 00007 #include "Notifier.h" 00008 #include "Synchronized.h" 00009 #include "Timer.h" 00010 #include "Utility.h" 00011 #include "WPIErrors.h" 00012 00013 const UINT32 Notifier::kTimerInterruptNumber; 00014 Notifier *Notifier::timerQueueHead = NULL; 00015 SEM_ID Notifier::queueSemaphore = NULL; 00016 tAlarm *Notifier::talarm = NULL; 00017 tInterruptManager *Notifier::manager = NULL; 00018 int Notifier::refcount = 0; 00019 00025 Notifier::Notifier(TimerEventHandler handler, void *param) 00026 { 00027 if (handler == NULL) 00028 wpi_setWPIErrorWithContext(NullParameter, "handler must not be NULL"); 00029 m_handler = handler; 00030 m_param = param; 00031 m_periodic = false; 00032 m_expirationTime = 0; 00033 m_period = 0; 00034 m_nextEvent = NULL; 00035 m_queued = false; 00036 m_handlerSemaphore = semBCreate(SEM_Q_PRIORITY, SEM_FULL); 00037 if (queueSemaphore == NULL) 00038 { 00039 queueSemaphore = semBCreate(SEM_Q_PRIORITY, SEM_FULL); 00040 } 00041 tRioStatusCode localStatus = NiFpga_Status_Success; 00042 { 00043 Synchronized sync(queueSemaphore); 00044 // do the first time intialization of static variables 00045 if (refcount == 0) 00046 { 00047 manager = new tInterruptManager(1 << kTimerInterruptNumber, false, &localStatus); 00048 manager->registerHandler(ProcessQueue, NULL, &localStatus); 00049 manager->enable(&localStatus); 00050 talarm = tAlarm::create(&localStatus); 00051 } 00052 refcount++; 00053 } 00054 wpi_setError(localStatus); 00055 } 00056 00062 Notifier::~Notifier() 00063 { 00064 tRioStatusCode localStatus = NiFpga_Status_Success; 00065 { 00066 Synchronized sync(queueSemaphore); 00067 DeleteFromQueue(); 00068 00069 // Delete the static variables when the last one is going away 00070 if (!(--refcount)) 00071 { 00072 talarm->writeEnable(false, &localStatus); 00073 delete talarm; 00074 talarm = NULL; 00075 manager->disable(&localStatus); 00076 delete manager; 00077 manager = NULL; 00078 } 00079 } 00080 wpi_setError(localStatus); 00081 00082 // Acquire the semaphore; this makes certain that the handler is 00083 // not being executed by the interrupt manager. 00084 semTake(m_handlerSemaphore, WAIT_FOREVER); 00085 // Delete while holding the semaphore so there can be no race. 00086 semDelete(m_handlerSemaphore); 00087 } 00088 00096 void Notifier::UpdateAlarm() 00097 { 00098 if (timerQueueHead != NULL) 00099 { 00100 tRioStatusCode localStatus = NiFpga_Status_Success; 00101 // write the first item in the queue into the trigger time 00102 talarm->writeTriggerTime((UINT32)(timerQueueHead->m_expirationTime * 1e6), &localStatus); 00103 // Enable the alarm. The hardware disables itself after each alarm. 00104 talarm->writeEnable(true, &localStatus); 00105 wpi_setStaticError(timerQueueHead, localStatus); 00106 } 00107 } 00108 00115 void Notifier::ProcessQueue(uint32_t mask, void *params) 00116 { 00117 Notifier *current; 00118 while (true) // keep processing past events until no more 00119 { 00120 { 00121 Synchronized sync(queueSemaphore); 00122 double currentTime = GetClock(); 00123 current = timerQueueHead; 00124 if (current == NULL || current->m_expirationTime > currentTime) 00125 { 00126 break; // no more timer events to process 00127 } 00128 // need to process this entry 00129 timerQueueHead = current->m_nextEvent; 00130 if (current->m_periodic) 00131 { 00132 // if periodic, requeue the event 00133 // compute when to put into queue 00134 current->InsertInQueue(true); 00135 } 00136 else 00137 { 00138 // not periodic; removed from queue 00139 current->m_queued = false; 00140 } 00141 // Take handler semaphore while holding queue semaphore to make sure 00142 // the handler will execute to completion in case we are being deleted. 00143 semTake(current->m_handlerSemaphore, WAIT_FOREVER); 00144 } 00145 00146 current->m_handler(current->m_param); // call the event handler 00147 semGive(current->m_handlerSemaphore); 00148 } 00149 // reschedule the first item in the queue 00150 Synchronized sync(queueSemaphore); 00151 UpdateAlarm(); 00152 } 00153 00163 void Notifier::InsertInQueue(bool reschedule) 00164 { 00165 if (reschedule) 00166 { 00167 m_expirationTime += m_period; 00168 } 00169 else 00170 { 00171 m_expirationTime = GetClock() + m_period; 00172 } 00173 if (timerQueueHead == NULL || timerQueueHead->m_expirationTime >= this->m_expirationTime) 00174 { 00175 // the queue is empty or greater than the new entry 00176 // the new entry becomes the first element 00177 this->m_nextEvent = timerQueueHead; 00178 timerQueueHead = this; 00179 if (!reschedule) 00180 { 00181 // since the first element changed, update alarm, unless we already plan to 00182 UpdateAlarm(); 00183 } 00184 } 00185 else 00186 { 00187 for (Notifier **npp = &(timerQueueHead->m_nextEvent); ; npp = &(*npp)->m_nextEvent) 00188 { 00189 Notifier *n = *npp; 00190 if (n == NULL || n->m_expirationTime > this->m_expirationTime) 00191 { 00192 *npp = this; 00193 this->m_nextEvent = n; 00194 break; 00195 } 00196 } 00197 } 00198 m_queued = true; 00199 } 00200 00208 void Notifier::DeleteFromQueue() 00209 { 00210 if (m_queued) 00211 { 00212 m_queued = false; 00213 wpi_assert(timerQueueHead != NULL); 00214 if (timerQueueHead == this) 00215 { 00216 // remove the first item in the list - update the alarm 00217 timerQueueHead = this->m_nextEvent; 00218 UpdateAlarm(); 00219 } 00220 else 00221 { 00222 for (Notifier *n = timerQueueHead; n != NULL; n = n->m_nextEvent) 00223 { 00224 if (n->m_nextEvent == this) 00225 { 00226 // this element is the next element from *n from the queue 00227 n->m_nextEvent = this->m_nextEvent; // point around this one 00228 } 00229 } 00230 } 00231 } 00232 } 00233 00239 void Notifier::StartSingle(double delay) 00240 { 00241 Synchronized sync(queueSemaphore); 00242 m_periodic = false; 00243 m_period = delay; 00244 DeleteFromQueue(); 00245 InsertInQueue(false); 00246 } 00247 00254 void Notifier::StartPeriodic(double period) 00255 { 00256 Synchronized sync(queueSemaphore); 00257 m_periodic = true; 00258 m_period = period; 00259 DeleteFromQueue(); 00260 InsertInQueue(false); 00261 } 00262 00270 void Notifier::Stop() 00271 { 00272 { 00273 Synchronized sync(queueSemaphore); 00274 DeleteFromQueue(); 00275 } 00276 // Wait for a currently executing handler to complete before returning from Stop() 00277 Synchronized sync(m_handlerSemaphore); 00278 }
Generated on Thu Jan 12 2012 22:35:22 for WPILibC++ by
1.7.1