/*
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 eventid_t 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, eventid_t 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 it is better to 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(eventmask_t 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)->p_rdymsg = RDY_OK;
elp = elp->el_next;
}
}
#ifdef CH_USE_EVENTS_TIMEOUT
/**
* 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 evhandler_t. 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.
*/
eventid_t chEvtWait(eventmask_t ewmask,
const evhandler_t handlers[]) {
return chEvtWaitTimeout(ewmask, handlers, TIME_INFINITE);
}
/**
* 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 evhandler_t. 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 if the specified time expired
* @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.
*/
eventid_t chEvtWaitTimeout(eventmask_t ewmask,
const evhandler_t handlers[],
systime_t time) {
eventid_t i;
eventmask_t m;
chSysLock();
if ((currp->p_epending & ewmask) == 0) {
currp->p_ewmask = ewmask;
if (chSchGoSleepTimeoutS(PRWTEVENT, time) < RDY_OK)
return RDY_TIMEOUT;
}
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;
}
#else /* !CH_USE_EVENTS_TIMEOUT */
eventid_t chEvtWait(eventmask_t ewmask,
const evhandler_t handlers[]) {
eventid_t i;
eventmask_t 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;
}
#endif /* CH_USE_EVENTS_TIMEOUT */
#endif /* CH_USE_EVENTS */
/** @} */