/* ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/RT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @addtogroup Events * @{ */ #include #ifdef CH_USE_EVENTS /** * Registers an Event Listener on an Event Source. * @param esp pointer to the \p EventSource structure * @param elp pointer to the \p EventListener structure * @param eid numeric identifier assigned to the Event Listener. The identifier * is used as index for the event callback function. * The value must range between zero and the size, in bit, of the * \p t_eventid type minus one. * @note Multiple Event Listeners can use the same event identifier, the * listener will share the callback function. */ void chEvtRegister(EventSource *esp, EventListener *elp, t_eventid eid) { chSysLock(); elp->el_next = esp->es_next; esp->es_next = elp; elp->el_listener = currp; elp->el_id = eid; chSysUnlock(); } /** * Unregisters an Event Listener from its Event Source. * @param esp pointer to the \p EventSource structure * @param elp pointer to the \p EventListener structure * @note If the event listener is not registered on the specified event source * then the function does nothing. * @note For optimal performance perform the unregister operations in inverse * order of the register operations (elements are found on top of the * list). */ void chEvtUnregister(EventSource *esp, EventListener *elp) { EventListener *p = (EventListener *)esp; chSysLock(); while (p->el_next != (EventListener *)esp) { if (p->el_next == elp) { p->el_next = elp->el_next; break; } p = p->el_next; } chSysUnlock(); } /** * Clears the pending events specified in the mask. * @param mask the events to be cleared */ void chEvtClear(t_eventmask mask) { chSysLock(); currp->p_epending &= ~mask; chSysUnlock(); } /** * Signals all the Event Listeners registered on the specified Event Source. * @param esp pointer to the \p EventSource structure */ void chEvtSend(EventSource *esp) { chSysLock(); chEvtSendI(esp); chSchRescheduleS(); chSysUnlock(); } /** * Signals all the Event Listeners registered on the specified Event Source. * @param esp pointer to the \p EventSource structure * @note This function does not reschedule. */ void chEvtSendI(EventSource *esp) { EventListener *elp; elp = esp->es_next; while (elp != (EventListener *)esp) { Thread *tp = elp->el_listener; tp->p_epending |= EventMask(elp->el_id); if ((tp->p_state == PRWTEVENT) && (tp->p_epending & tp->p_ewmask)) chSchReadyI(tp, RDY_OK); elp = elp->el_next; } } /** * The function waits for an event and returns the event identifier, if an * event handler is specified then the handler is executed before returning. * @param ewmask mask of the events that should be served by the function, * \p ALL_EVENTS enables all the sources * @param handlers an array of \p t_evhandler. The array must be * have indexes from zero up the higher registered event * identifier. The array can be \p NULL or contain \p NULL * elements (no callbacks specified). * @return the event identifier * @note Only a single event is served in the function, the one with the * lowest event id. The function is meant to be invoked into a loop so * that all events are received and served.
* This means that Event Listeners with a lower event identifier have * an higher priority. */ t_eventid chEvtWait(t_eventmask ewmask, const t_evhandler handlers[]) { t_eventid i; t_eventmask m; chSysLock(); if ((currp->p_epending & ewmask) == 0) { currp->p_ewmask = ewmask; chSchGoSleepS(PRWTEVENT); } i = 0, m = 1; while ((currp->p_epending & ewmask & m) == 0) i += 1, m <<= 1; currp->p_epending &= ~m; chSysUnlock(); if (handlers && handlers[i]) handlers[i](i); return i; } #ifdef CH_USE_EVENTS_TIMEOUT static void wakeup(void *p) { #ifdef CH_USE_DEBUG if (((Thread *)p)->p_state != PRWTEVENT) chDbgPanic("chevents.c, wakeup()\r\n"); #endif chSchReadyI(p, RDY_TIMEOUT); } /** * The function waits for an event or the specified timeout then returns the * event identifier, if an event handler is specified then the handler is * executed before returning. * @param ewmask mask of the events that should be served by the function, * \p ALL_EVENTS enables all the sources * @param handlers an array of \p t_evhandler. The array must be * have indexes from zero up the higher registered event * identifier. The array can be NULL or contain NULL elements * (no callback specified). * @param time the number of ticks before the operation timouts * @return the event identifier or \p RDY_TIMEOUT the specified time expired or * if the timeout was set to zero and no serviceable pending events * were present * @note Only a single event is served in the function, the one with the * lowest event id. The function is meant to be invoked into a loop so * that all events are received and served.
* This means that Event Listeners with a lower event identifier have * an higher priority. * @note The function is available only if the \p CH_USE_EVENTS_TIMEOUT * option is enabled in \p chconf.h. */ t_eventid chEvtWaitTimeout(t_eventmask ewmask, const t_evhandler handlers[], t_time time) { t_eventid i; t_eventmask m; chSysLock(); if ((currp->p_epending & ewmask) == 0) { VirtualTimer vt; chVTSetI(&vt, time, wakeup, currp); currp->p_ewmask = ewmask; chSchGoSleepS(PRWTEVENT); if (!chVTIsArmedI(&vt)) { chSysUnlock(); return RDY_TIMEOUT; } chVTResetI(&vt); } i = 0, m = 1; while ((currp->p_epending & ewmask & m) == 0) i += 1, m <<= 1; currp->p_epending &= ~m; chSysUnlock(); if (handlers && handlers[i]) handlers[i](i); return i; } #endif /*CH_USE_EVENTS_TIMEOUT */ #endif /* CH_USE_EVENTS */ /** @} */