From 30f0bb1d66f016d6d8366aa483ca12a4724bd599 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Tue, 18 Sep 2007 12:40:26 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- src/chdelta.c | 84 +++++++++ src/chevents.c | 247 ++++++++++++++++++++++++ src/chinit.c | 59 ++++++ src/chmsg.c | 194 +++++++++++++++++++ src/chqueues.c | 478 +++++++++++++++++++++++++++++++++++++++++++++++ src/chschd.c | 205 ++++++++++++++++++++ src/chsem.c | 376 +++++++++++++++++++++++++++++++++++++ src/chserial.c | 195 +++++++++++++++++++ src/chsleep.c | 79 ++++++++ src/chthreads.c | 265 ++++++++++++++++++++++++++ src/include/ch.h | 97 ++++++++++ src/include/delta.h | 83 ++++++++ src/include/events.h | 95 ++++++++++ src/include/messages.h | 59 ++++++ src/include/queues.h | 172 +++++++++++++++++ src/include/scheduler.h | 81 ++++++++ src/include/semaphores.h | 82 ++++++++ src/include/serial.h | 154 +++++++++++++++ src/include/sleep.h | 43 +++++ src/include/threads.h | 203 ++++++++++++++++++++ src/templates/chconf.h | 154 +++++++++++++++ src/templates/chcore.c | 50 +++++ src/templates/chcore.h | 69 +++++++ src/templates/chtypes.h | 62 ++++++ src/templates/readme.txt | 1 + 25 files changed, 3587 insertions(+) create mode 100644 src/chdelta.c create mode 100644 src/chevents.c create mode 100644 src/chinit.c create mode 100644 src/chmsg.c create mode 100644 src/chqueues.c create mode 100644 src/chschd.c create mode 100644 src/chsem.c create mode 100644 src/chserial.c create mode 100644 src/chsleep.c create mode 100644 src/chthreads.c create mode 100644 src/include/ch.h create mode 100644 src/include/delta.h create mode 100644 src/include/events.h create mode 100644 src/include/messages.h create mode 100644 src/include/queues.h create mode 100644 src/include/scheduler.h create mode 100644 src/include/semaphores.h create mode 100644 src/include/serial.h create mode 100644 src/include/sleep.h create mode 100644 src/include/threads.h create mode 100644 src/templates/chconf.h create mode 100644 src/templates/chcore.c create mode 100644 src/templates/chcore.h create mode 100644 src/templates/chtypes.h create mode 100644 src/templates/readme.txt diff --git a/src/chdelta.c b/src/chdelta.c new file mode 100644 index 000000000..9a4f8b21d --- /dev/null +++ b/src/chdelta.c @@ -0,0 +1,84 @@ +/* + 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 VirtualTimers + * @{ + */ + +#include + +#ifdef CH_USE_VIRTUAL_TIMERS +DeltaList dlist; + +/** + * Virtual Timers initialization. Internal use only. + */ +void chVTInit(void) { + + dlist.dl_next = dlist.dl_prev = (VirtualTimer *)&dlist; + dlist.dl_dtime = MAXDELTA; +} + +/** + * Enables a virtual timer. + * @param vtp the \p VirtualTimer structure pointer + * @param time the number of time ticks + * @param vtfunc the timer callback function. After invoking the callback + * the timer is disabled and the structure can be disposed or + * reused. + * @param par a parameter that will be passed to the callback function + * @note Must be called with the interrupts disabled. + * @note The associated function is invoked by an interrupt handler. + */ +void chVTSetI(VirtualTimer *vtp, t_time time, t_vtfunc vtfunc, void *par) { + VirtualTimer *p; + + vtp->vt_func = vtfunc; + vtp->vt_par = par; + p = dlist.dl_next; + while (p->vt_dtime < time) { + time -= p->vt_dtime; + p = p->vt_next; + } + + vtp->vt_prev = (vtp->vt_next = p)->vt_prev; + vtp->vt_prev->vt_next = p->vt_prev = vtp; + vtp->vt_dtime = time; + if (p != (VirtualTimer *)&dlist) + p->vt_dtime -= time; +} + +/** + * Disables a Virtual Timer. + * @param vtp the \p VirtualTimer structure pointer + * @note It must be called with the interrupts disabled. + * @note The timer MUST be active when this function is invoked. + */ +void chVTResetI(VirtualTimer *vtp) { + + if (vtp->vt_next != (VirtualTimer *)&dlist) + vtp->vt_next->vt_dtime += vtp->vt_dtime; + vtp->vt_prev->vt_next = vtp->vt_next; + vtp->vt_next->vt_prev = vtp->vt_prev; + vtp->vt_func = 0; +} +#endif /* CH_USE_VIRTUAL_TIMER */ + +/** @} */ diff --git a/src/chevents.c b/src/chevents.c new file mode 100644 index 000000000..87f990c16 --- /dev/null +++ b/src/chevents.c @@ -0,0 +1,247 @@ +/* + 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) { + EventListener *elp; + BOOL flag = FALSE; + + chSysLock(); + + 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), flag = TRUE; + elp = elp->el_next; + } + if (flag) + chSchRescheduleI(); + + chSysUnlock(); +} + +/** + * Signals all the Event Listeners registered on the specified Event Source. + * @param esp pointer to the \p EventSource structure + * @note This function must be called with interrupts disabled. + */ +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); + 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, t_evhandler handlers[]) { + t_eventid i; + t_eventmask m; + + chSysLock(); + + if ((currp->p_epending & ewmask) == 0) { + currp->p_ewmask = ewmask; + chSchGoSleepI(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 unwait(void *p) { + +// Test removed, it should never happen. +// if (((Thread *)p)->p_state == PRWTEVENT) + chSchReadyI(dequeue(p))->p_rdymsg = 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, if set to + * zero then the function exits immediatly with \p RDY_TIMEOUT if + * there are not serviceable events pending + * @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, + t_evhandler handlers[], + t_time time) { + t_eventid i; + t_eventmask m; + + chSysLock(); + + if ((currp->p_epending & ewmask) == 0) { + VirtualTimer vt; + + if (time == 0) { + + chSysUnlock(); + return RDY_TIMEOUT; + } + + chVTSetI(&vt, time, unwait, currp); + currp->p_ewmask = ewmask; + chSchGoSleepI(PRWTEVENT); + if (!vt.vt_func) { + + chSysUnlock(); + return RDY_TIMEOUT; // No need to read t_rdymsg value, it is a 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 */ + +/** @} */ diff --git a/src/chinit.c b/src/chinit.c new file mode 100644 index 000000000..b86626fa6 --- /dev/null +++ b/src/chinit.c @@ -0,0 +1,59 @@ +/* + 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 Initialization + * @{ + */ + +#include + +static Thread idlethread; + +/** + * ChibiOS/RT initialization. After executing this function the current + * instructions stream becomes the idle thread. The thread must execute the + * first user thread and then go to sleep into the \p chSysPause() where it + * will just serve the interrupts while keeping the lowest possible power + * mode.

+ * @code + * chSysInit(); + * chThdCreate(...); // Starts one or more user threads. + * chSysPause(); + * @endcode + * @note Interrupts should be still disabled when \p chSysInit() is invoked and + * are internally enabled. + */ +void chSysInit(void) { + + chSchInit(); +#ifdef CH_USE_VIRTUAL_TIMERS + chVTInit(); +#endif + /* + * Now this instructions flow becomes the idle thread. + */ + _InitThread(IDLEPRIO, 0, &idlethread); + idlethread.p_state = PRCURR; + currp = &idlethread; + + chSysUnlock(); +} + +/** @} */ diff --git a/src/chmsg.c b/src/chmsg.c new file mode 100644 index 000000000..0f71b2216 --- /dev/null +++ b/src/chmsg.c @@ -0,0 +1,194 @@ +/* + 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 Messages + * @{ + */ +#include + +#ifdef CH_USE_MESSAGES +/** + * Sends a message to the specified thread. The client is stopped until the + * server executes a \p chMsgRelease() after receiving the message. + * + * @param tp the pointer to the thread + * @param msg the message, it can be a pointer to a complex structure + * @return the return message from \p chMsgRelease() + */ +t_msg chMsgSend(Thread *tp, t_msg msg) { + + chSysLock(); + + enqueue(currp, &tp->p_msgqueue); + if (tp->p_state == PRWTMSG) + chSchReadyI(tp); + currp->p_msg = msg; + chSchGoSleepI(PRSNDMSG); + msg = currp->p_rdymsg; + + chSysUnlock(); + return msg; +} + +#ifdef CH_USE_MESSAGES_EVENT +/** + * Sends a message to the specified thread and atomically triggers an event. + * The client is stopped until the server executes a \p chMsgRelease() + * after receiving the message. + * + * @param tp the pointer to the thread + * @param msg the message, it can be a pointer to a complex structure + * @param esp the event source to pulse while sending the message + * @return the return message from \p chMsgRelease() + * @return the message return status from \p chMsgRelease() + * @note This function assumes that the receiving thread is not sleeping into + * a \p chMsgWait(). The use case is that the server thread is waiting + * for both messages AND events while waiting into \p chEvtWait(). + */ +t_msg chMsgSendWithEvent(Thread *tp, t_msg msg, EventSource *esp) { + + chSysLock(); + + enqueue(currp, &tp->p_msgqueue); +// if (tp->p_state == PRWTMSG) +// chSchReadyI(tp); + chEvtSendI(esp); + currp->p_msg = msg; + chSchGoSleepI(PRSNDMSG); + msg = currp->p_rdymsg; + + chSysUnlock(); + return msg; +} +#endif + +#ifdef CH_USE_MESSAGES_TIMEOUT +static void unsend(void *p) { + +// Test removed, it should never happen. +// if (((Thread *)p)->p_state == PRSNDMSG) + chSchReadyI(dequeue(p))->p_rdymsg = RDY_TIMEOUT; +} + +/** + * Sends a message to the specified thread with timeout specification. The + * sender is stopped until the receiver executes a \p chMsgRelease(). + * + * @param tp the pointer to the thread + * @param msg the message. Note that it can be a pointer to a complex + * message structure. + * @param time the number of ticks before the operation fails + * @return the message return status from \p chMsgRelease() or + * \p RDY_TIMEOUT the specified time expired. + * @note The server thread can also return data into the message structure + * if you need messages to be bidirectional, just define the structure + * according your needs. If you dont need complicated messages exchange + * you may just use the \p chMsgRelease() status code as response + * to the message. + */ +t_msg chMsgSendTimeout(Thread *tp, t_msg msg, t_time time) { + VirtualTimer vt; + + chSysLock(); + + chVTSetI(&vt, time, unsend, currp); + enqueue(currp, &tp->p_msgqueue); + if (tp->p_state == PRWTMSG) + chSchReadyI(tp); + currp->p_msg = msg; + chSchGoSleepI(PRSNDMSG); + msg = currp->p_rdymsg; + if (vt.vt_func) + chVTResetI(&vt); + + chSysUnlock(); + return msg; +} +#endif /* CH_USE_MESSAGES_TIMEOUT */ + +/** + * Suspends the thread and waits for an incoming message. + * + * @return the pointer to the message structure. Note, it is always the + * message associated to the thread on the top of the messages queue. + * @note You can assume that the data contained in the message is stable until + * you invoke \p chMsgRelease() because the sending thread is + * suspended until then. Always remember that the message data is not + * copied between the sender and the receiver, just a pointer is passed. + */ +t_msg chMsgWait(void) { + t_msg msg; + + chSysLock(); + + if (!chMsgIsPendingI(currp)) + chSchGoSleepI(PRWTMSG); + msg = chMsgGetI(currp); + + chSysUnlock(); + return msg; +} + +/** + * Returns the next message in the queue. + * + * @return the pointer to the message structure. Note, it is always the + * message associated to the thread on the top of the messages queue. + * If the queue is empty then \p NULL is returned. + * @note You can assume that the data contained in the message is stable until + * you invoke \p chMsgRelease() because the sending thread is + * suspended until then. Always remember that the message data is not + * copied between the sender and the receiver, just a pointer is passed. + */ +t_msg chMsgGet(void) { + t_msg msg; + + chSysLock(); + + msg = chMsgIsPendingI(currp) ? chMsgGetI(currp) : NULL; + + chSysUnlock(); + return msg; +} + +/** + * Releases the thread waiting on top of the messages queue. + * + * @param msg the message returned to the message sender + * @note You can call this function only if there is a message already in the + * queue else the result will be unpredictable (a crash most likely). + * Exiting from the \p chMsgWait() ensures you have at least one + * message in the queue so it is not a big deal.
+ * The condition is not checked in order to make this code as fast as + * possible. + */ +void chMsgRelease(t_msg msg) { + + chSysLock(); + +// if (!chMsgIsPendingI(currp) + chSchWakeupI(dequeue(currp->p_msgqueue.p_next), msg); + + chSysUnlock(); +} + +#endif /* CH_USE_MESSAGES */ + +/** @} */ diff --git a/src/chqueues.c b/src/chqueues.c new file mode 100644 index 000000000..2cccc3120 --- /dev/null +++ b/src/chqueues.c @@ -0,0 +1,478 @@ +/* + 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 IOQueues + * @{ + */ + +#include + +#ifdef CH_USE_QUEUES + +/** + * Initializes an input queue. A Semaphore is internally initialized + * and works as a counter of the bytes contained in the queue. + * @param qp pointer to a \p Queue structure + * @param buffer pointer to a memory area allocated as queue buffer + * @param size size of the queue buffer + * @param inotify pointer to a callback function that is invoked when + * some data is read from the Queue. The value can be \p NULL. + */ +void chIQInit(Queue *qp, BYTE8 *buffer, t_size size, t_qnotify inotify) { + + qp->q_buffer = qp->q_rdptr = qp->q_wrptr = buffer; + qp->q_top = buffer + size; + chSemInit(&qp->q_sem, 0); + qp->q_notify = inotify; +} + +/** + * Resets an input queue. All the data is lost and the waiting threads + * resumed. + * @param qp pointer to a \p Queue structure + */ +void chIQReset(Queue *qp) { + + chSysLock(); + + qp->q_rdptr = qp->q_wrptr = qp->q_buffer; + chSemResetI(&qp->q_sem, 0); + + chSysUnlock(); +} + +/** + * Inserts a byte into an input queue. + * @param qp pointer to a \p Queue structure + * @param b the byte value to be written + * @return \p Q_OK if the operation is successful or \p Q_FULL if the queue is + * full. + * @note This function is the lower side endpoint of the Input Queue. + * @note This function must be called with interrupts disabled or from an + * interrupt handler. + */ +t_msg chIQPutI(Queue *qp, BYTE8 b) { + + if (chIQIsFull(qp)) + return Q_FULL; + + *qp->q_wrptr++ = b; + if (qp->q_wrptr >= qp->q_top) + qp->q_wrptr = qp->q_buffer; + chSemSignalI(&qp->q_sem); + return Q_OK; +} + +/** + * Gets a byte from the input queue, if the queue is empty then the + * calling thread is suspended until a byte arrives in the queue. + * @param qp pointer to a \p Queue structure + * @return a byte from the queue or \p Q_RESET if the queue was reset + */ +t_msg chIQGet(Queue *qp) { + BYTE8 b; + + chSysLock(); + + chSemWaitS(&qp->q_sem); + if (currp->p_rdymsg < RDY_OK) { + + chSysUnlock(); + return currp->p_rdymsg; + } + b = *qp->q_rdptr++; + if (qp->q_rdptr >= qp->q_top) + qp->q_rdptr = qp->q_buffer; + + if (qp->q_notify) + qp->q_notify(); + + chSysUnlock(); + return b; +} + +#ifdef CH_USE_QUEUES_TIMEOUT +/** + * Gets a byte from the input queue, if the queue is empty then the + * calling thread is suspended until a byte arrives in the queue or the + * specified time expires. + * @param qp pointer to a \p Queue structure + * @param time the number of ticks before the operation timouts + * @return a byte from the queue, \p Q_TIMEOUT if the specified time expired + * or \p Q_RESET if the queue was reset + * @note The function is available only if the \p CH_USE_QUEUES_TIMEOUT + * option is enabled in \p chconf.h. + */ +t_msg chIQGetTimeout(Queue *qp, t_time time) { + BYTE8 b; + t_msg msg; + + chSysLock(); + + if ((msg = chSemWaitTimeoutS(&qp->q_sem, time)) < RDY_OK) + return msg; + b = *qp->q_rdptr++; + if (qp->q_rdptr >= qp->q_top) + qp->q_rdptr = qp->q_buffer; + + if (qp->q_notify) + qp->q_notify(); + + chSysUnlock(); + return b; +} +#endif /* CH_USE_QUEUES_TIMEOUTS */ + +/** + * Reads some data from the input queue into the specified buffer. The function + * is non-blocking and can return zero if the queue is empty. + * @param qp pointer to a \p Queue structure + * @param buffer the data buffer + * @param n the maxium amount of data to be read + * @return the number of bytes read + * @note This function is the upper side endpoint of the input queue. + * @note The function is not atomical, if you need atomicity it is suggested + * to use a semaphore for mutual exclusion. + */ +t_size chIQRead(Queue *qp, BYTE8 *buffer, t_size n) { + + t_size r = 0; + while (n--) { + chSysLock(); + + if (chIQIsEmpty(qp)) { + + chSysUnlock(); + break; + } + chSemFastWaitS(&qp->q_sem); + *buffer++ = *qp->q_rdptr++; + if (qp->q_rdptr >= qp->q_top) + qp->q_rdptr = qp->q_buffer; + +// if (qp->q_notify) +// qp->q_notify(); + + chSysUnlock(); + r++; + } + + if (r && qp->q_notify) { + chSysLock(); + + qp->q_notify(); + + chSysUnlock(); + } + + return r; +} + +/** + * Initializes an output queue. A Semaphore is internally initialized + * and works as a counter of the free bytes in the queue. + * @param qp pointer to a \p Queue structure + * @param buffer pointer to a memory area allocated as queue buffer + * @param size size of the queue buffer + * @param onotify pointer to a callback function that is invoked when + * some data is written in the Queue. The value can be \p NULL. + */ +void chOQInit(Queue *qp, BYTE8 *buffer, t_size size, t_qnotify onotify) { + + qp->q_buffer = qp->q_rdptr = qp->q_wrptr = buffer; + qp->q_top = buffer + size; + chSemInit(&qp->q_sem, size); + qp->q_notify = onotify; +} + +/** + * Resets an Output Queue. All the data is lost and the waiting threads + * resumed. + * @param qp pointer to a \p Queue structure + */ +void chOQReset(Queue *qp) { + + chSysLock(); + + qp->q_rdptr = qp->q_wrptr = qp->q_buffer; + chSemResetI(&qp->q_sem, (t_semcnt)(qp->q_top - qp->q_buffer)); + + chSysUnlock(); +} + +/** + * Inserts a byte in the output queue, if the queue is full then the thread + * is suspended until the queue has free space available. + * @param qp pointer to a \p Queue structure + * @param b the byte value to be written + */ +void chOQPut(Queue *qp, BYTE8 b) { + + chSysLock(); + + chSemWaitS(&qp->q_sem); + *qp->q_wrptr++ = b; + if (qp->q_wrptr >= qp->q_top) + qp->q_wrptr = qp->q_buffer; + + if (qp->q_notify) + qp->q_notify(); + + chSysUnlock(); +} + +/** + * Gets a byte from an output queue. + * @param qp pointer to a \p Queue structure + * @return the byte value or \p Q_EMPTY if the queue is empty + * @note This function is the lower side endpoint of the output queue. + * @note This function must be called with interrupts disabled or from an + * interrupt handler. + */ +t_msg chOQGetI(Queue *qp) { + BYTE8 b; + + if (chOQIsEmpty(qp)) + return Q_EMPTY; + + b = *qp->q_rdptr++; + if (qp->q_rdptr >= qp->q_top) + qp->q_rdptr = qp->q_buffer; + chSemSignalI(&qp->q_sem); + return b; +} + +/** + * Writes some data from the specified buffer into the queue. The function + * is non-blocking and can return zero if the queue is full. + * @param qp pointer to a \p Queue structure + * @param buffer the data buffer + * @param n the maxium amount of data to be written + * @note This function is the upper side endpoint of the output queue. + * @note The function is not atomical, if you need atomicity it is suggested + * to use a semaphore for mutual exclusion. + */ +t_size chOQWrite(Queue *qp, BYTE8 *buffer, t_size n) { + + t_size w = 0; + while (n--) { + chSysLock(); + + if (chOQIsFull(qp)) { + + chSysUnlock(); + break; + } + chSemFastWaitS(&qp->q_sem); + *qp->q_wrptr++ = *buffer++; + if (qp->q_wrptr >= qp->q_top) + qp->q_wrptr = qp->q_buffer; + +// if (qp->q_notify) +// qp->q_notify(); + + chSysUnlock(); + w++; + } + + if (w && qp->q_notify) { + chSysLock(); + + qp->q_notify(); + + chSysUnlock(); + } + + return w; +} +#endif /* CH_USE_QUEUES */ + +#ifdef CH_USE_QUEUES_HALFDUPLEX + /** + * Initializes an half duplex queue. + * @param qp pointer to the \p HalfDuplexQueue structure + * @param buffer pointer to a memory area allocated as buffer for the queue + * @param size the size of the queue buffer + * @param inotify pointer to a callback function that is invoked when + * some data is read from the queue. The value can be \p NULL. + * @param onotify pointer to a callback function that is invoked when + * some data is written to the queue. The value can be \p NULL. + */ +void chHDQInit(HalfDuplexQueue *qp, BYTE8 *buffer, t_size size, + t_qnotify inotify, t_qnotify onotify) { + + qp->hdq_buffer = qp->hdq_rdptr = qp->hdq_wrptr = buffer; + qp->hdq_top = buffer + size; + chSemInit(&qp->hdq_isem, 0); + chSemInit(&qp->hdq_osem, size); + qp->hdq_inotify = inotify; + qp->hdq_onotify = onotify; +} + +/** + * Reads a byte from the receive queue, if the queue is empty or is in + * transmission mode then the invoking thread is suspended. + * @param qp pointer to a \p HalfDuplexQueue structure + * @return the byte value + */ +t_msg chHDQGetReceive(HalfDuplexQueue *qp) { + BYTE8 b; + + chSysLock(); + + chSemWaitS(&qp->hdq_isem); + if (currp->p_rdymsg < RDY_OK) { + + chSysUnlock(); + return currp->p_rdymsg; + } + /* + * NOTE: The semaphore can be signaled only if the queue is in + * receive mode. + */ + b = *qp->hdq_rdptr++; + if (qp->hdq_rdptr >= qp->hdq_top) + qp->hdq_rdptr = qp->hdq_buffer; + + if (qp->hdq_inotify) + qp->hdq_inotify(); + + chSysUnlock(); + return b; +} + +#ifdef CH_USE_QUEUES_TIMEOUT +/** + * Reads a byte from the receive queue, if the queue is empty or is in + * transmission mode then the invoking thread is suspended. + * @param qp pointer to a \p HalfDuplexQueue structure + * @param time the number of ticks before the operation timouts + * @return the byte value or \p Q_TIMEOUT if a timeout occurs + * @note The function is available only if the \p CH_USE_QUEUES_TIMEOUT + * option is enabled in \p chconf.h. + */ +t_msg chHDQGetReceiveTimeout(HalfDuplexQueue *qp, t_time time) { + BYTE8 b; + t_msg msg; + + chSysLock(); + + if ((msg = chSemWaitTimeoutS(&qp->hdq_isem, time)) < RDY_OK) { + + chSysUnlock(); + return msg; + } + /* + * NOTE: The semaphore can be signaled only if the queue is in + * receive mode. + */ + b = *qp->hdq_rdptr++; + if (qp->hdq_rdptr >= qp->hdq_top) + qp->hdq_rdptr = qp->hdq_buffer; + + if (qp->hdq_inotify) + qp->hdq_inotify(); + + chSysUnlock(); + return b; +} +#endif + +/** + * Writes a byte into the transmit queue. If the buffer contains unread + * input data then the the buffer is cleared and the queue goes in + * transmission mode. + * @param qp pointer to a \p HalfDuplexQueue structure + * @param b the byte value to be written + */ +void chHDQPutTransmit(HalfDuplexQueue *qp, BYTE8 b) { + + chSysLock(); + + /* + * Transmission mode requires that all the unread data must be destroyed. + */ + if (qp->hdq_isem.s_cnt > 0) { + qp->hdq_isem.s_cnt = 0; + qp->hdq_rdptr = qp->hdq_wrptr = qp->hdq_buffer; + } + + /* + * Goes in transmission mode. + */ + chSemWaitS(&qp->hdq_osem); + *qp->hdq_wrptr++ = b; + if (qp->hdq_wrptr >= qp->hdq_top) + qp->hdq_wrptr = qp->hdq_buffer; + + if (qp->hdq_onotify) + qp->hdq_onotify(); + + chSysUnlock(); +} + +/** + * Gets a byte from the transmit queue. + * @param qp pointer to a \p HalfDuplexQueue structure + * @return the byte value or \p Q_EMPTY if the transmit queue is empty (not in + * transmission mode) + * @note This function must be called with interrupts disabled or from an + * interrupt handler. + */ +t_msg chHDQGetTransmitI(HalfDuplexQueue *qp) { + BYTE8 b; + + if (!chHDQIsTransmitting(qp)) + return Q_EMPTY; + + b = *qp->hdq_rdptr++; + if (qp->hdq_rdptr >= qp->hdq_top) + qp->hdq_rdptr = qp->hdq_buffer; + chSemSignalI(&qp->hdq_osem); + return b; +} + +/** + * Writes a byte into the receive queue. If the queue is in transmission mode + * then the byte is lost. + * @param qp pointer to a \p HalfDuplexQueue structure + * @param b the byte value to be written + * @return \p Q_OK if the operation is successful or \p Q_FULL if the driver + * is in transmit mode or the receive queue is full. + * @note This function must be called with interrupts disabled or from an + * interrupt handler. + */ +t_msg chHDQPutReceiveI(HalfDuplexQueue *qp, BYTE8 b) { + + if (chHDQIsTransmitting(qp)) + return Q_FULL; + + if (chHDQIsFullReceive(qp)) + return Q_FULL; + + *qp->hdq_wrptr++ = b; + if (qp->hdq_wrptr >= qp->hdq_top) + qp->hdq_wrptr = qp->hdq_buffer; + chSemSignalI(&qp->hdq_isem); + return Q_OK; +} +#endif /* CH_USE_QUEUES_HALFDUPLEX */ + +/** @} */ diff --git a/src/chschd.c b/src/chschd.c new file mode 100644 index 000000000..b38fe366f --- /dev/null +++ b/src/chschd.c @@ -0,0 +1,205 @@ +/* + 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 Scheduler + * @{ + */ + +#include + +/** @cond never*/ + +static ReadyList rlist; + +#ifndef CH_CURRP_REGISTER_CACHE +Thread *currp; +#endif + +static UWORD16 preempt; +#ifdef CH_USE_SYSTEMTIME +t_time stime; +#endif + +/** @endcond */ + +/** + * Scheduler initialization. + * @note Internally invoked by the \p chSysInit(). + */ +void chSchInit(void) { + + rlist.p_next = rlist.p_prev = (Thread *)&rlist; + rlist.p_prio = MAXPRIO; + preempt = CH_TIME_QUANTUM; +#ifdef CH_USE_SYSTEMTIME + stime = 0; +#endif +} + +/** + * Inserts a thread in the Ready List. + * @param tp the Thread to be made ready + * @return the Thread pointer + * @note The function must be called in the system mutex zone. + * @note The function does not reschedule, the \p chSchRescheduleI() should + * be called soon after. + * @note The function is not meant to be used in the user code directly. + */ +Thread *chSchReadyI(Thread *tp) { + Thread *cp; + t_prio prio = tp->p_prio; + + tp->p_state = PRREADY; + tp->p_rdymsg = RDY_OK; + cp = rlist.p_next; + while (cp->p_prio < prio) + cp = cp->p_next; + tp->p_prev = (tp->p_next = cp)->p_prev; + tp->p_prev->p_next = cp->p_prev = tp; + return tp; +} + +/* + * Switches to the next thread in the ready list, the ready list is assumed + * to contain at least a thread. + */ +static void nextready(void) { + Thread *otp = currp; + + (currp = dequeue(rlist.p_prev))->p_state = PRCURR; + preempt = CH_TIME_QUANTUM; + chSysSwitchI(&otp->p_ctx, &currp->p_ctx); +} + +/** + * Puts the current thread to sleep into the specified state, the next highest + * priority thread becomes running. The threads states are described into + * \p threads.h + * @param newstate the new thread state + * @return the wakeup message + * @note The function must be called in the system mutex zone. + * @note The function is not meant to be used in the user code directly. + */ +void chSchGoSleepI(t_tstate newstate) { + + currp->p_state = newstate; + nextready(); +} + +/** + * Wakeups a thread, the thread is inserted into the ready list or made + * running directly depending on its relative priority compared to the current + * thread. + * @param tp the Thread to be made ready + * @param msg wakeup message to the awakened thread + * @note The function must be called in the system mutex zone. + * @note The function is not meant to be used in the user code directly. + * @note It is equivalent to a \p chSchReadyI() followed by a + * \p chSchRescheduleI() but much more efficient. + */ +void chSchWakeupI(Thread *tp, t_msg msg) { + Thread *ctp = currp; + + if (tp->p_prio <= ctp->p_prio) + chSchReadyI(tp)->p_rdymsg = msg; + else { + chSchReadyI(ctp); + (currp = tp)->p_state = PRCURR; + tp->p_rdymsg = msg; + preempt = CH_TIME_QUANTUM; + chSysSwitchI(&ctp->p_ctx, &tp->p_ctx); + } +} + +/** + * If a thread with an higher priority than the current thread is in the + * ready list then it becomes running. + * @note The function must be called in the system mutex zone. + */ +void chSchRescheduleI(void) { + + if (isempty(&rlist) || lastprio(&rlist) <= currp->p_prio) + return; + + chSchDoRescheduleI(); +} + +/** + * Performs a reschedulation. It is meant to be called if + * \p chSchRescRequired() evaluates to \p TRUE. + */ +void chSchDoRescheduleI(void) { + + chSchReadyI(currp); + nextready(); +} + +/** + * Evaluates if a reschedulation is required. + * @return \p TRUE if there is a thread that should go in running state + * immediatly else \p FALSE. + */ +BOOL chSchRescRequiredI(void) { + + if (isempty(&rlist)) + return FALSE; + + if (preempt) { + if (lastprio(&rlist) <= currp->p_prio) + return FALSE; + } + else { /* Time quantum elapsed. */ + if (lastprio(&rlist) < currp->p_prio) + return FALSE; + } + return TRUE; +} + +/** + * Preemption routine, this function must be called into an interrupt + * handler invoked by a system timer. + * The frequency of the timer determines the system tick granularity and, + * together with the \p CH_TIME_QUANTUM macro, the round robin interval. + */ +void chSchTimerHandlerI(void) { + + if (preempt) + preempt--; + +#ifdef CH_USE_SYSTEMTIME + stime++; +#endif + +#ifdef CH_USE_VIRTUAL_TIMERS + if (&dlist != (DeltaList *)dlist.dl_next) { + VirtualTimer *vtp; + + --dlist.dl_next->vt_dtime; + while (!(vtp = dlist.dl_next)->vt_dtime) { + vtp->vt_prev->vt_next = vtp->vt_next; + vtp->vt_next->vt_prev = vtp->vt_prev; + vtp->vt_func(vtp->vt_par); + vtp->vt_func = 0; // Required, flags the timer as triggered. + } + } +#endif +} + +/** @} */ diff --git a/src/chsem.c b/src/chsem.c new file mode 100644 index 000000000..1eab23ea4 --- /dev/null +++ b/src/chsem.c @@ -0,0 +1,376 @@ +/* + 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 Semaphores + * @{ + */ + +#include + +#ifdef CH_USE_SEMAPHORES +/** + * Initializes a semaphore with the specified counter value. + * @param sp pointer to a \p Semaphore structure + * @param n initial value of the semaphore counter. Must be non-negative. + * @note Can be called with interrupts disabled or enabled. + */ +void chSemInit(Semaphore *sp, t_semcnt n) { + + sp->s_cnt = n; + sp->s_queue.p_next = sp->s_queue.p_prev = (Thread *)&sp->s_queue; +} + +/** + * Performs a reset operation on the semaphore. + * @param sp pointer to a \p Semaphore structure + * @param n the new value of the semaphore counter. Must be non-negative. + * @note The released threads can recognize they were waked up by a reset + * instead than a signal because the \p p_rdymsg field is set to + * \p RDY_RESET. + */ +void chSemReset(Semaphore *sp, t_semcnt n) { + t_semcnt cnt; + + chSysLock(); + + cnt = sp->s_cnt; + sp->s_cnt = n; + if (cnt < 0) { + while (cnt++) + chSchReadyI(dequeue(sp->s_queue.p_next))->p_rdymsg = RDY_RESET; + chSchRescheduleI(); + } + + chSysUnlock(); +} + +/** + * Performs a reset operation on the semaphore. + * @param sp pointer to a \p Semaphore structure + * @param n the new value of the semaphore counter. Must be non-negative. + * @note The released threads can recognize they were waked up by a reset + * instead than a signal because the \p p_rdymsg field is set to + * \p RDY_RESET. + * @note This function must be called with interrupts disabled. + */ +void chSemResetI(Semaphore *sp, t_semcnt n) { + t_semcnt cnt; + + cnt = sp->s_cnt; + sp->s_cnt = n; + while (cnt++ < 0) + chSchReadyI(dequeue(sp->s_queue.p_next))->p_rdymsg = RDY_RESET; +} + +/** + * Performs a wait operation on a semaphore. + * @param sp pointer to a \p Semaphore structure + */ +void chSemWait(Semaphore *sp) { + + chSysLock(); + + if (--sp->s_cnt < 0) { + enqueue(currp, &sp->s_queue); + chSchGoSleepI(PRWTSEM); + } + + chSysUnlock(); +} + +/** + * Performs a wait operation on a semaphore. + * @param sp pointer to a \p Semaphore structure + * @note This function must be called with interrupts disabled. + * @note This function cannot be called by an interrupt handler. + */ +void chSemWaitS(Semaphore *sp) { + + if (--sp->s_cnt < 0) { + enqueue(currp, &sp->s_queue); + chSchGoSleepI(PRWTSEM); + } +} + +#ifdef CH_USE_SEMAPHORES_TIMEOUT +static void unwait(void *p) { + +// Test removed, it should never happen. +// if (((Thread *)p)->p_state == PRWTSEM) + chSchReadyI(dequeue(p))->p_rdymsg = RDY_TIMEOUT; +} + +/** + * Performs a wait operation on a semaphore with timeout specification. + * @param sp pointer to a \p Semaphore structure + * @param time the number of ticks before the operation fails + * @return the function can return \p RDY_OK. \p RDY_TIMEOUT or \p RDY_RESET. + */ +t_msg chSemWaitTimeout(Semaphore *sp, t_time time) { + t_msg msg; + + chSysLock(); + + if (--sp->s_cnt < 0) { + VirtualTimer vt; + + chVTSetI(&vt, time, unwait, currp); + enqueue(currp, &sp->s_queue); + chSchGoSleepI(PRWTSEM); + msg = currp->p_rdymsg; // Note, got value *before* invoking CH_LEAVE_SYSTEM(). + if (!vt.vt_func) { + sp->s_cnt++; + + chSysUnlock(); + return msg; + } + chVTResetI(&vt); + + chSysUnlock(); + return msg; + } + + chSysUnlock(); + return RDY_OK; +} + +/** + * Performs a wait operation on a semaphore with timeout specification. + * @param sp pointer to a \p Semaphore structure + * @param time the number of ticks before the operation fails + * @return the function can return \p RDY_OK. \p RDY_TIMEOUT or \p RDY_RESET. + * @note This function must be called with interrupts disabled. + * @note This function cannot be called by an interrupt handler. + * @note The function is available only if the \p CH_USE_SEMAPHORES_TIMEOUT + * option is enabled in \p chconf.h. + */ +t_msg chSemWaitTimeoutS(Semaphore *sp, t_time time) { + + if (--sp->s_cnt < 0) { + VirtualTimer vt; + + chVTSetI(&vt, time, unwait, currp); + enqueue(currp, &sp->s_queue); + chSchGoSleepI(PRWTSEM); + if (!vt.vt_func) { + sp->s_cnt++; + return currp->p_rdymsg; + } + chVTResetI(&vt); + return currp->p_rdymsg; + } + return RDY_OK; +} + +#endif /* CH_USE_SEMAPHORES_TIMEOUT */ +/** + * Performs a signal operation on a semaphore. + * @param sp pointer to a \p Semaphore structure + * @note The function is available only if the \p CH_USE_SEMAPHORES + * option is enabled in \p chconf.h. + */ +void chSemSignal(Semaphore *sp) { + + chSysLock(); + + if (sp->s_cnt++ < 0) + chSchWakeupI(dequeue(sp->s_queue.p_next), RDY_OK); + + chSysUnlock(); +} + +/** + * Performs a signal operation on a semaphore. + * @param sp pointer to a \p Semaphore structure + * @note This function must be called with interrupts disabled. + * @note The function is available only if the \p CH_USE_SEMAPHORES + * option is enabled in \p chconf.h. + */ +void chSemSignalI(Semaphore *sp) { + + if (sp->s_cnt++ < 0) + chSchReadyI(dequeue(sp->s_queue.p_next)); +} + +/** + * Performs atomic signal and wait operations on two semaphores. + * @param sps pointer to a \p Semaphore structure to be signaled + * @param spw pointer to a \p Semaphore structure to be wait on + * @note The function is available only if the \p CH_USE_SEMAPHORES + * option is enabled in \p chconf.h. + */ +void chSemSignalWait(Semaphore *sps, Semaphore *spw) { + BOOL flag; + + chSysLock(); + + if (sps->s_cnt++ < 0) + chSchReadyI(dequeue(sps->s_queue.p_next)), flag = TRUE; + else + flag = FALSE; + + if (--spw->s_cnt < 0) { + enqueue(currp, &spw->s_queue); + chSchGoSleepI(PRWTSEM); + } + else if (flag) + chSchRescheduleI(); + + chSysUnlock(); +} + +#ifdef CH_USE_RT_SEMAPHORES +/* + * Inserts a thread into a list ordering it by priority. + * @param tp the pointer to the thread to be inserted in the list + * @param tqp the pointer to the threads list header + * @note Usually you dont need to use this function in the user code unless + * you want to create some custom threads synchronization mechanism. + */ +static void prioenq(Thread *tp, ThreadsQueue *tqp) { + Thread *p; + + p = tqp->p_next; + while ((p != (Thread *)tqp) && (p->p_prio >= tp->p_prio)) + p = p->p_next; + tp->p_next = p; + tp->p_prev = tqp->p_prev; + p->p_prev->p_next = tp; + p->p_prev = tp; +} + +/** + * Performs a wait operation on a semaphore with priority boost. + * @param sp pointer to a \p Semaphore structure + * @note The function is available only if the \p CH_USE_RT_SEMAPHORES + * option is enabled in \p chconf.h. + */ +void chSemRaisePrioWait(Semaphore *sp) { + + chSysLock(); + + if (--sp->s_cnt < 0) { + prioenq(currp, &sp->s_queue); + chSchGoSleepI(PRWTSEM); + } + + if (!currp->p_rtcnt++) + currp->p_prio += MEPRIO; + + chSysUnlock(); +} + +/** + * Performs a signal operation on a semaphore with return to normal priority. + * @param sp pointer to a \p Semaphore structure + * @note The function is available only if the \p CH_USE_RT_SEMAPHORES + * option is enabled in \p chconf.h. + */ +void chSemLowerPrioSignal(Semaphore *sp) { + + chSysLock(); + + if (!--currp->p_rtcnt) { + currp->p_prio = currp->p_bakprio; + if (sp->s_cnt++ < 0) + chSchReadyI(dequeue(sp->s_queue.p_next)); + chSchRescheduleI(); + } + else if (sp->s_cnt++ < 0) + chSchWakeupI(dequeue(sp->s_queue.p_next), RDY_OK); + + chSysUnlock(); +} + +/** + * Performs atomic signal and wait operations on two semaphores with priority + * boost. + * @param sps pointer to a \p Semaphore structure to be signaled + * @param spw pointer to a \p Semaphore structure to be wait on + * @note The function is available only if the \p CH_USE_RT_SEMAPHORES + * option is enabled in \p chconf.h. + */ +void chSemRaisePrioSignalWait(Semaphore *sps, Semaphore *spw) { + BOOL flag; + + chSysLock(); + + if (sps->s_cnt++ < 0) + chSchReadyI(dequeue(sps->s_queue.p_next)), flag = TRUE; + else + flag = FALSE; + + if (--spw->s_cnt < 0) { + prioenq(currp, &spw->s_queue); + chSchGoSleepI(PRWTSEM); + + if (!currp->p_rtcnt++) + currp->p_prio += MEPRIO; + + chSysUnlock(); + return; + } + + if (!currp->p_rtcnt++) { + currp->p_bakprio = currp->p_prio; + currp->p_prio += MEPRIO; + flag = TRUE; + } + + if( flag) + chSchRescheduleI(); + + chSysUnlock(); +} + +/** + * Performs atomic signal and wait operations on two semaphores with return + * to normal priority. + * @param sps pointer to a \p Semaphore structure to be signaled + * @param spw pointer to a \p Semaphore structure to be wait on + * @note The function is available only if the \p CH_USE_RT_SEMAPHORES + * option is enabled in \p chconf.h. + */ +void chSemLowerPrioSignalWait(Semaphore *sps, Semaphore *spw) { + BOOL flag = FALSE; + + chSysLock(); + + if (!--currp->p_rtcnt) + currp->p_prio = currp->p_bakprio, flag = TRUE; + + if (sps->s_cnt++ < 0) + chSchReadyI(dequeue(sps->s_queue.p_next)), flag = TRUE; + + if (--spw->s_cnt < 0) { + enqueue(currp, &spw->s_queue); // enqueue() because the spw is a normal sem. + chSchGoSleepI(PRWTSEM); + } + else if (flag) + chSchRescheduleI(); + + chSysUnlock(); +} + +#endif /* CH_USE_RT_SEMAPHORES */ + +#endif /* CH_USE_SEMAPHORES */ + +/** @} */ diff --git a/src/chserial.c b/src/chserial.c new file mode 100644 index 000000000..54c2f9f7e --- /dev/null +++ b/src/chserial.c @@ -0,0 +1,195 @@ +/* + 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 Serial + * @{ + */ + +#include + +#ifdef CH_USE_SERIAL_FULLDUPLEX + +/** + * Initializes a generic full duplex driver. The HW dependent part of the + * initialization has to be performed outside, usually in the hardware + * initialization code. + * @param sd pointer to a \p FullDuplexDriver structure + * @param ib pointer to a memory area allocated for the Input Queue buffer + * @param isize size of the Input Queue buffer + * @param inotify pointer to a callback function that is invoked when + * some data is read from the Queue. The value can be \p NULL. + * @param ob pointer to a memory area allocated for the Output Queue buffer + * @param osize size of the Output Queue buffer + * @param onotify pointer to a callback function that is invoked when + * some data is written in the Queue. The value can be \p NULL. + */ +void chFDDInit(FullDuplexDriver *sd, + BYTE8 *ib, t_size isize, t_qnotify inotify, + BYTE8 *ob, t_size osize, t_qnotify onotify) { + + chIQInit(&sd->sd_iqueue, ib, isize, inotify); + chEvtInit(&sd->sd_ievent); + chOQInit(&sd->sd_oqueue, ob, osize, onotify); + chEvtInit(&sd->sd_oevent); + chEvtInit(&sd->sd_sevent); + sd->sd_flags = SD_NO_ERROR; +} + +/** + * This function must be called from the input interrupt service routine in + * order to enqueue incoming data and generate the related events. + * @param sd pointer to a \p FullDuplexDriver structure + * @param b the byte to be written in the driver's Input Queue + */ +void chFDDIncomingDataI(FullDuplexDriver *sd, BYTE8 b) { + + if (chIQPutI(&sd->sd_iqueue, b) < Q_OK) + chFDDAddFlagsI(sd, SD_OVERRUN_ERROR); + else + chEvtSendI(&sd->sd_ievent); +} + +/** + * Must be called from the output interrupt service routine in order to get + * the next byte to be transmitted. + * + * @param sd pointer to a \p FullDuplexDriver structure + * @return the byte read from the driver's Output Queue or \p Q_EMPTY if the + * queue is empty (the lower driver usually disables the interrupt + * source when this happens). + */ +t_msg chFDDRequestDataI(FullDuplexDriver *sd) { + + t_msg b = chOQGetI(&sd->sd_oqueue); + if (b < Q_OK) + chEvtSendI(&sd->sd_oevent); + return b; +} + +/** + * Must be called from the I/O interrupt service routine in order to + * notify I/O conditions as errors, signals change etc. + * @param sd pointer to a \p FullDuplexDriver structure + * @param mask condition flags to be added to the mask + */ +void chFDDAddFlagsI(FullDuplexDriver *sd, t_dflags mask) { + + sd->sd_flags |= mask; + chEvtSendI(&sd->sd_sevent); +} + +/** + * This function returns and clears the errors mask associated to the driver. + * @param sd pointer to a \p FullDuplexDriver structure + * @return the condition flags modified since last time this function was + * invoked + */ +t_dflags chFDDGetAndClearFlags(FullDuplexDriver *sd) { + t_dflags mask; + + mask = sd->sd_flags; + sd->sd_flags = SD_NO_ERROR; + return mask; +} + +#endif /* CH_USE_SERIAL_FULLDUPLEX */ + +#ifdef CH_USE_SERIAL_HALFDUPLEX +/** + * Initializes a generic half duplex driver. The HW dependent part of the + * initialization has to be performed outside, usually in the hardware + * initialization code. + * @param sd pointer to a \p HalfDuplexDriver structure + * @param b pointer to a memory area allocated for the queue buffer + * @param size the buffer size + * @param inotify pointer to a callback function that is invoked when + * some data is read from the queue. The value can be \p NULL. + * @param onotify pointer to a callback function that is invoked when + * some data is written in the queue. The value can be \p NULL. + */ +void chHDDInit(HalfDuplexDriver *sd, BYTE8 *b, t_size size, + t_qnotify inotify, t_qnotify onotify) { + + chHDQInit(&sd->sd_queue, b, size, inotify, onotify); + chEvtInit(&sd->sd_ievent); + chEvtInit(&sd->sd_oevent); + chEvtInit(&sd->sd_sevent); + sd->sd_flags = SD_NO_ERROR; +} + +/** + * This function must be called from the input interrupt service routine in + * order to enqueue incoming data and generate the related events. + * @param sd pointer to a \p FullDuplexDriver structure + * @param b the byte to be written in the driver's Input Queue + */ +void chHDDIncomingDataI(HalfDuplexDriver *sd, BYTE8 b) { + + if (chHDQPutReceiveI(&sd->sd_queue, b) < Q_OK) + chHDDAddFlagsI(sd, SD_OVERRUN_ERROR); + else + chEvtSendI(&sd->sd_ievent); +} + +/** + * Must be called from the output interrupt service routine in order to get + * the next byte to be transmitted. + * + * @param sd pointer to a \p HalfDuplexDriver structure + * @return the byte read from the driver's Output Queue or \p Q_EMPTY if the + * queue is empty (the lower driver usually disables the interrupt + * source when this happens). + */ +t_msg chHDDRequestDataI(HalfDuplexDriver *sd) { + + t_msg b = chHDQGetTransmitI(&sd->sd_queue); + if (b < Q_OK) + chEvtSendI(&sd->sd_oevent); + return b; +} + +/** + * Must be called from the I/O interrupt service routine in order to + * notify I/O conditions as errors, signals change etc. + * @param sd pointer to a \p HalfDuplexDriver structure + * @param mask condition flags to be added to the mask + */ +void chHDDAddFlagsI(HalfDuplexDriver *sd, t_dflags mask) { + + sd->sd_flags |= mask; + chEvtSendI(&sd->sd_sevent); +} + +/** + * This function returns and clears the errors mask associated to the driver. + * @param sd pointer to a \p HalfDuplexDriver structure + * @return the condition flags modified since last time this function was + * invoked + */ +t_dflags chHDDGetAndClearFlags(HalfDuplexDriver *sd) { + t_dflags mask; + + mask = sd->sd_flags; + sd->sd_flags = SD_NO_ERROR; + return mask; +} +#endif /* CH_USE_SERIAL_HALFDUPLEX */ + +/** @} */ diff --git a/src/chsleep.c b/src/chsleep.c new file mode 100644 index 000000000..9fedd0244 --- /dev/null +++ b/src/chsleep.c @@ -0,0 +1,79 @@ +/* + 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 Time + * @{ + */ + +#include + +#ifdef CH_USE_SLEEP +/** + * Suspends the invoking thread for the specified time. + * @param time the system ticks number + */ +void chThdSleep(t_time time) { + VirtualTimer vt; + + chSysLock(); + + chVTSetI(&vt, time, (t_vtfunc)chSchReadyI, currp); + chSchGoSleepI(PRSLEEP); + + chSysUnlock(); +} + +#ifdef CH_USE_SYSTEMTIME +/** + * Returns the number of system ticks since the \p chSysInit() invocation. + * @return the system ticks number + * @note The counter can reach its maximum and return to zero. + * @note This function is designed to work with the \p chThdSleepUntil(). + * @note The function is available only if the \p CH_USE_SYSTEMTIME + * option is enabled in \p chconf.h. + */ +t_time chSysGetTime(void) { + + return stime; +} + +/** + * Suspends the invoking thread until the system time arrives to the specified + * value. + * @param time the system time + * @note The function is available only if the \p CH_USE_SYSTEMTIME + * option is enabled in \p chconf.h. + */ +void chThdSleepUntil(t_time time) { + VirtualTimer t; + + chSysLock(); + + chVTSetI(&t, (t_time)(time - stime), (t_vtfunc)chSchReadyI, currp); + chSchGoSleepI(PRSLEEP); + + chSysUnlock(); +} +#endif /* CH_USE_SYSTEMTIME */ + +#endif /* CH_USE_SLEEP */ + +/** @} */ + diff --git a/src/chthreads.c b/src/chthreads.c new file mode 100644 index 000000000..8f7112647 --- /dev/null +++ b/src/chthreads.c @@ -0,0 +1,265 @@ +/* + 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 Threads + * @{ + */ + +#include + +#ifndef CH_OPTIMIZE_SPEED +/* + * Removes a Thread from a list and returns it. + * @param tp the pointer to the thread to be removed from the list + * @return the removed thread pointer + */ +Thread *dequeue(Thread *tp) { + + tp->p_prev->p_next = tp->p_next; + tp->p_next->p_prev = tp->p_prev; + return tp; +} + +/* + * Inserts a thread into a bi-directional list in FIFO order. + * @param tp the pointer to the thread to be inserted in the list + * @param tqp the pointer to the threads list header + */ +void enqueue(Thread *tp, ThreadsQueue *tqp) { + + tp->p_next = (Thread *)tqp; + tp->p_prev = tqp->p_prev; + tqp->p_prev->p_next = tp; + tqp->p_prev = tp; +} +#endif /* CH_OPTIMIZE_SPEED */ + +/* + * Initializes a thread structure. + */ +void _InitThread(t_prio prio, t_tmode mode, Thread *tp) { + + tp->p_flags = mode; + tp->p_prio = prio; + tp->p_rdymsg = RDY_OK; +#ifdef CH_USE_RT_SEMAPHORES + tp->p_rtcnt = 0; + tp->p_bakprio = prio; +#endif +#ifdef CH_USE_WAITEXIT + tp->p_waiting.p_next = (Thread *)&tp->p_waiting; + tp->p_waiting.p_prev = (Thread *)&tp->p_waiting; +#endif +#ifdef CH_USE_MESSAGES + tp->p_msgqueue.p_next = (Thread *)&tp->p_msgqueue; + tp->p_msgqueue.p_prev = (Thread *)&tp->p_msgqueue; +#endif +#ifdef CH_USE_EVENTS + tp->p_epending = 0; +#endif +#ifdef CH_USE_EXIT_EVENT + chEvtInit(&tp->p_exitesource); +#endif +} + +/** + * Creates a new thread. + * @param prio the priority level for the new thread. Usually the threads are + * created with priority \p NORMALPRIO (128), priorities + * can range from \p LOWPRIO (1) to \p HIGHPRIO + * (255). + * @param mode the creation option flags for the thread. The following options + * can be OR'ed in this parameter:
+ *
    + *
  • \p P_SUSPENDED, the thread is created in the + * \p PRSUSPENDED state and a subsequent call to + * \p chThdResume() will make it ready for + * execution.
  • + *
  • \p P_TERMINATED, this flag is usually set + * by the \p chThdTerminate() function and it is not + * normally used as parameter for this function. The + * result would be to create a thread with a termination + * request already pending.
  • + *
+ * @param workspace pointer to a working area dedicated to the thread stack + * @param wsize size of the working area. + * @param pf the thread function. Returning from this function automatically + * terminates the thread. + * @param arg an argument passed to the thread function. It can be \p NULL. + * @return the pointer to the \p Thread structure allocated for the + * thread into the working space area. + * @note A thread can terminate by calling \p chThdExit() or by simply + * returning from its main function. + */ +Thread *chThdCreate(t_prio prio, t_tmode mode, void *workspace, + t_size wsize, t_tfunc pf, void *arg) { + Thread *tp = workspace; + + _InitThread(prio, mode, tp); + SETUP_CONTEXT(workspace, wsize, pf, arg); +#ifdef CH_USE_RESUME + if (tp->p_flags & P_SUSPENDED) + tp->p_state = PRSUSPENDED; + else { +#endif + chSysLock(); + + chSchWakeupI(tp, RDY_OK); + + chSysUnlock(); +#ifdef CH_USE_RESUME + } +#endif + return tp; +} + +/** + * Verifies if the specified thread is in the \p PREXIT state. + * @param tp the pointer to the thread + * @return \p TRUE if the thread is ended else \p FALSE. \p TRUE ensures that + * a subsequent call to \p chThdWait() would not block. + */ +BOOL chThdTerminated(Thread *tp) { + + return tp->p_state == PREXIT; +} + +#ifdef CH_USE_RESUME +/** + * Resumes a thread created with the \p P_SUSPENDED option. + * @param tp the pointer to the thread + * @note The function has no effect on threads in any other state than + * \p PRSUSPENDED. + * @note The function is available only if the \p CH_USE_RESUME + * option is enabled in \p chconf.h. + */ +void chThdResume(Thread *tp) { + + chSysLock(); + + if (tp->p_state == PRSUSPENDED) + chSchWakeupI(tp, RDY_OK); + + chSysUnlock(); +} +#endif + +#ifdef CH_USE_TERMINATE +/** + * Requests a thread termination. + * @param tp the pointer to the thread + * @note The thread is not termitated but a termination request is added to + * its \p p_flags field. The thread can read this status by + * invoking \p chThdShouldTerminate() and then terminate cleanly. + */ +void chThdTerminate(Thread *tp) { + + chSysLock(); + + tp->p_flags |= P_TERMINATE; + + chSysUnlock(); +} + +/** + * Verifies if the current thread has a termination request pending. + * @return \p TRUE if the termination was requested. The thread should terminate + * as soon it is ready to do so. + */ +BOOL chThdShouldTerminate(void) { + + return currp->p_flags & P_TERMINATE ? TRUE : FALSE; +} + +#endif + +/** + * Terminates the current thread by specifying an exit status code. + * @param msg the thread exit code. The code can be retrieved by using + * \p chThdWait(). + */ +void chThdExit(t_msg msg) { + + chSysLock(); + + currp->p_exitcode = msg; /* Post mortem info. */ +#ifdef CH_USE_WAITEXIT + while (notempty(&currp->p_waiting)) + chSchReadyI(dequeue(currp->p_waiting.p_next)); +#endif +#ifdef CH_USE_EXIT_EVENT + chEvtSendI(&currp->p_exitesource); +#endif + chSchGoSleepI(PREXIT); + + chSysUnlock(); /* Never executed. */ +} + +#ifdef CH_USE_WAITEXIT +/** + * Blocks the execution of the invoking thread until the specified thread + * terminates then the exit code is returned. + * @param tp the pointer to the thread + * @return the exit code + * @note The function is available only if the \p CH_USE_WAITEXIT + * option is enabled in \p chconf.h. + */ +t_msg chThdWait(Thread *tp) { + + chSysLock(); + + if (tp->p_state != PREXIT) { + enqueue(currp, &tp->p_waiting); + chSchGoSleepI(PRWAIT); + } + + chSysUnlock(); + return tp->p_exitcode; +} +#endif /* CH_USE_WAITEXIT */ + +#ifdef CH_USE_EXIT_EVENT +/** + * Returns the exit event source for the specified thread. The source is + * signaled when the thread terminates. + * @param tp the pointer to the thread + * @note When registering on a thread termination make sure the thread + * is still alive, if you do that after the thread termination + * then you would miss the event. There are two ways to ensure + * this:
+ *
    + *
  • Create the thread suspended, register on the event source + * and then resume the thread (recommended).
  • + *
  • Create the thread with a lower priority then register on it. + * This does not work if the hardware is capable of multiple + * physical threads.
  • + *
+ * @note You dont need to unregister from a terminated thread because + * the event source becomes inactive. + * @note The function is available only if the \p CH_USE_EXIT_EVENT + * option is enabled in \p chconf.h. + */ +EventSource *chThdGetExitEventSource(Thread *tp) { + + return &tp->p_exitesource; +} +#endif /* CH_USE_EXIT_EVENT */ + +/** @} */ diff --git a/src/include/ch.h b/src/include/ch.h new file mode 100644 index 000000000..80204bb2d --- /dev/null +++ b/src/include/ch.h @@ -0,0 +1,97 @@ +/* + 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 Initialization + * @{ + */ + +#ifndef _CH_H_ +#define _CH_H_ + +typedef struct Thread Thread; + +#ifndef __DOXIGEN__ +#ifndef _CHCONF_H_ +#include +#endif + +#ifndef _CHTYPES_H_ +#include +#endif + +#ifndef _CHCORE_H_ +#include +#endif +#endif /* __DOXIGEN__ */ + +#ifndef _DELTA_H_ +#include "delta.h" +#endif + +#ifndef _SCHEDULER_H_ +#include "scheduler.h" +#endif + +#ifndef _EVENTS_H_ +#include "events.h" +#endif + +#ifndef _MESSAGES_H_ +#include "messages.h" +#endif + +#ifndef _THREADS_H_ +#include "threads.h" +#endif + +#ifndef _SLEEP_H_ +#include "sleep.h" +#endif + +#ifndef _SEMAPHORES_H_ +#include "semaphores.h" +#endif + +#ifndef _QUEUES_H_ +#include "queues.h" +#endif + +#ifndef _SERIAL_H_ +#include "serial.h" +#endif + +/* + * Common values. + */ +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef NULL +#define NULL 0 +#endif + +void chSysInit(void); + +#endif /* _CH_H_ */ + +/** @} */ diff --git a/src/include/delta.h b/src/include/delta.h new file mode 100644 index 000000000..2ae4d887f --- /dev/null +++ b/src/include/delta.h @@ -0,0 +1,83 @@ +/* + 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 VirtualTimers + * @{ + */ + +#ifndef _DELTA_H_ +#define _DELTA_H_ + +#ifdef CH_USE_VIRTUAL_TIMERS + +/** Virtual Timer callback function.*/ +typedef void (*t_vtfunc)(void *); + +typedef struct VirtualTimer VirtualTimer; + +/** + * Virtual Timer descriptor structure. + */ +struct VirtualTimer { + /** Next timer in the delta list.*/ + VirtualTimer *vt_next; + /** Previous timer in the delta list.*/ + VirtualTimer *vt_prev; + /** Time delta before timeout.*/ + t_time vt_dtime; + /** Timer callback function pointer. The pointer is reset to zero after + the callback is invoked.*/ + t_vtfunc vt_func; + /** Timer callback function parameter.*/ + void *vt_par; +}; + +/** + * Delta List header. + * @note The delta list is implemented as a double link bidirectional list in + * order to make the unlink time constant, the reset of a virtual timer + * is often used in the code. An slower implementation using a single + * link list is possible and might be added later with a + * \p CH_OPTIMIZE_SPACE option. + */ +typedef struct { + /** Next timer in the list (the one that will be triggered next).*/ + VirtualTimer *dl_next; + /** Last timer in the list.*/ + VirtualTimer *dl_prev; + /** Not used but it must be set to /p MAXDELTA.*/ + t_time dl_dtime; +} DeltaList; + + +extern DeltaList dlist; + +/* + * Virtual Timers APIs. + */ +void chVTInit(void); +void chVTSetI(VirtualTimer *vtp, t_time time, t_vtfunc vtfunc, void *par); +void chVTResetI(VirtualTimer *vtp); + +#endif /* CH_USE_VIRTUAL_TIMER */ + +#endif /* _DELTA_H_ */ + +/** @} */ diff --git a/src/include/events.h b/src/include/events.h new file mode 100644 index 000000000..c5dfe7438 --- /dev/null +++ b/src/include/events.h @@ -0,0 +1,95 @@ +/* + 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 + * @{ + */ + +#ifndef _EVENTS_H_ +#define _EVENTS_H_ + +#ifdef CH_USE_EVENTS + +/** All events allowed mask.*/ +#define ALL_EVENTS -1 + +typedef struct EventListener EventListener; + +/** + * Event Listener structure. + */ +struct EventListener { + /** Next Event Listener registered on the Event Source.*/ + EventListener *el_next; + /** Thread interested in the Event Source.*/ + Thread *el_listener; + /** Event identifier associated by the thread to the Event Source.*/ + t_eventid el_id; +}; + +/** + * Event Source structure. + */ +typedef struct EventSource { + /** First Event Listener registered on the Event Source.*/ + EventListener *es_next; +} EventSource; + +/** Returns the event mask from the event identifier.*/ +#define EventMask(eid) (1 << (eid)) + +/** + * Initializes an Event Source. + * @param esp pointer to the \p EventSource structure + * @note Can be called with interrupts disabled or enabled. + */ +#define chEvtInit(esp) \ + ((esp)->es_next = (EventListener *)(esp)) + +/** + * Verifies if there is at least one \p EventListener registered on the + * \p EventSource. + * @param esp pointer to the \p EventSource structure + * @note Can be called with interrupts disabled or enabled. + */ +#define chEvtIsListening(esp) \ + ((esp) != (EventSource *)(esp)->es_next) + + +/** Event Handler callback function.*/ +typedef void (*t_evhandler)(t_eventid); + +void chEvtRegister(EventSource *esp, EventListener *elp, t_eventid eid); +void chEvtUnregister(EventSource *esp, EventListener *elp); +void chEvtClear(t_eventmask mask); +void chEvtSend(EventSource *esp); +void chEvtSendI(EventSource *esp); +t_eventid chEvtWait(t_eventmask ewmask, t_evhandler handlers[]); +#ifdef CH_USE_EVENTS_TIMEOUT +t_eventid chEvtWaitTimeout(t_eventmask ewmask, + t_evhandler handlers[], + t_time time); +#endif + +#endif /* CH_USE_EVENTS */ + +#endif /* _EVENTS_H_ */ + +/** @} */ diff --git a/src/include/messages.h b/src/include/messages.h new file mode 100644 index 000000000..a6ce409f3 --- /dev/null +++ b/src/include/messages.h @@ -0,0 +1,59 @@ +/* + 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 Messages + * @{ + */ + +#ifndef _MESSAGES_H_ +#define _MESSAGES_H_ + +#ifdef CH_USE_MESSAGES + +/** + * Evaluates to TRUE if the thread has pending messages. + */ +#define chMsgIsPendingI(tp) \ + ((tp)->p_msgqueue.p_next != (Thread *)&(tp)->p_msgqueue) + +/** + * Returns the first message in the queue. + */ +#define chMsgGetI(tp) \ + ((tp)->p_msgqueue.p_next->p_msg) + +t_msg chMsgSend(Thread *tp, t_msg msg); +t_msg chMsgWait(void); +t_msg chMsgGet(void); +void chMsgRelease(t_msg msg); + +#ifdef CH_USE_MESSAGES_EVENT +t_msg chMsgSendWithEvent(Thread *tp, t_msg msg, EventSource *esp); +#endif + +#ifdef CH_USE_MESSAGES_TIMEOUT +t_msg chMsgSendTimeout(Thread *tp, t_msg msg, t_time time); +#endif + +#endif /* CH_USE_MESSAGES */ + +#endif /* _MESSAGES_H_ */ + +/** @} */ diff --git a/src/include/queues.h b/src/include/queues.h new file mode 100644 index 000000000..117c6e9e8 --- /dev/null +++ b/src/include/queues.h @@ -0,0 +1,172 @@ +/* + 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 IOQueues + * @{ + */ + +#ifndef _QUEUES_H_ +#define _QUEUES_H_ + +/** Queue notification callback type.*/ +typedef void (*t_qnotify)(void); + +/** Returned by the queue functions if the operation is successful.*/ +#define Q_OK RDY_OK +/** Returned by the queue functions if a timeout occurs.*/ +#define Q_TIMEOUT RDY_TIMEOUT +/** Returned by the queue functions if the queue is reset.*/ +#define Q_RESET RDY_RESET +/** Returned by the queue functions if the queue is empty.*/ +#define Q_EMPTY -3 +/** Returned by the queue functions if the queue is full.*/ +#define Q_FULL -4 + +#ifdef CH_USE_QUEUES +/** + * I/O queue structure, it is used by both Input and Output Queues, + * the difference is on how the semaphore is initialized. + */ +typedef struct { + /** Pointer to the queue buffer.*/ + BYTE8 *q_buffer; + /** Pointer to the first location after the buffer.*/ + BYTE8 *q_top; + /** Write pointer.*/ + BYTE8 *q_wrptr; + /** Read pointer.*/ + BYTE8 *q_rdptr; + /** Counter semaphore.*/ + Semaphore q_sem; + /** Data notification callback.*/ + t_qnotify q_notify; +} Queue; + +/** Returns the queue's buffer size.*/ +#define chQSize(q) \ + ((q)->q_top - (q)->q_buffer) + +/** Returns the used space if used on an Input Queue and the empty space if + * used on an Output Queue.*/ +#define chQSpace(q) \ + ((q)->q_sem.s_cnt) + +/** Evaluates to TRUE if the specified Input Queue is empty.*/ +#define chIQIsEmpty(q) \ + (chQSpace(q) <= 0) + +/** Evaluates to TRUE if the specified Input Queue is full.*/ +#define chIQIsFull(q) \ + (chQSpace(q) >= chQSize(q)) + +/** Evaluates to TRUE if the specified Output Queue is empty.*/ +#define chOQIsEmpty(q) \ + (chQSpace(q) >= chQSize(q)) + +/** Evaluates to TRUE if the specified Output Queue is full.*/ +#define chOQIsFull(q) \ + (chQSpace(q) <= 0) + +/* + * Input Queues functions. An Input Queue is usually written into by an + * interrupt handler and read from a thread. + */ +void chIQInit(Queue *qp, BYTE8 *buffer, t_size size, t_qnotify inotify); +void chIQReset(Queue *qp); +t_msg chIQPutI(Queue *qp, BYTE8 b); +t_msg chIQGet(Queue *qp); +t_size chIQRead(Queue *qp, BYTE8 *buffer, t_size n); +#ifdef CH_USE_QUEUES_TIMEOUT +t_msg chIQGetTimeout(Queue *qp, t_time time); +#endif + +/* + * Output Queues functions. An Output Queue is usually written into by a + * thread and read from an interrupt handler. + */ +void chOQInit(Queue *queue, BYTE8 *buffer, t_size size, t_qnotify onotify); +void chOQReset(Queue *queue); +void chOQPut(Queue *queue, BYTE8 b); +t_msg chOQGetI(Queue *queue); +t_size chOQWrite(Queue *queue, BYTE8 *buffer, t_size n); +#endif /* CH_USE_QUEUES */ + +#ifdef CH_USE_QUEUES_HALFDUPLEX +/** + * Half duplex queue structure. + */ +typedef struct { + /** Pointer to the queue buffer.*/ + BYTE8 *hdq_buffer; + /** Pointer to the first location after the buffer.*/ + BYTE8 *hdq_top; + /** Write pointer.*/ + BYTE8 *hdq_wrptr; + /** Read pointer.*/ + BYTE8 *hdq_rdptr; + /** Input counter semaphore.*/ + Semaphore hdq_isem; + /** Output counter semaphore.*/ + Semaphore hdq_osem; + /** Input data notification callback.*/ + t_qnotify hdq_inotify; + /** Output data notification callback.*/ + t_qnotify hdq_onotify; +} HalfDuplexQueue; + +/** Returns the queue's buffer size.*/ +#define chHDQSize(q) \ + ((q)->hdq_top - (q)->hdq_buffer) + +/** Returns the queue space when in transmission mode.*/ +#define chHDQEmptySpace(q) \ + ((q)->hdq_osem.s_cnt) + +/** Returns the number of the bytes in the queue when in receive mode.*/ +#define chHDQFilledSpace(q) \ + ((q)->hdq_isem.s_cnt) + +/** Evaluates to TRUE if the queue is in transmit mode.*/ +#define chHDQIsTransmitting(q) \ + (chHDQEmptySpace(q) < chHDQSize(q)) + +/** Evaluates to TRUE if the queue is in receive mode.*/ +#define chHDQIsReceiving(q) \ + (chHDQEmptySpaceQ(q) >= chHDQSize(q)) + +/** Evaluates to TRUE if the receive queue is full.*/ +#define chHDQIsFullReceive(q) \ + (chHDQFilledSpace(q) >= chHDQSize(q)) + +void chHDQInit(HalfDuplexQueue *qp, BYTE8 *buffer, t_size size, + t_qnotify inotify, t_qnotify onotify); +t_msg chHDQGetReceive(HalfDuplexQueue *qp); +void chHDQPutTransmit(HalfDuplexQueue *qp, BYTE8 b); +t_msg chHDQGetTransmitI(HalfDuplexQueue *qp); +t_msg chHDQPutReceiveI(HalfDuplexQueue *qp, BYTE8 b); +#ifdef CH_USE_QUEUES_TIMEOUT +t_msg chHDQGetReceiveTimeout(HalfDuplexQueue *qp, t_time time); +#endif + +#endif /* CH_USE_QUEUES_HALFDUPLEX */ + +#endif /* _QUEUES_H_ */ + +/** @} */ diff --git a/src/include/scheduler.h b/src/include/scheduler.h new file mode 100644 index 000000000..78fbb4a72 --- /dev/null +++ b/src/include/scheduler.h @@ -0,0 +1,81 @@ +/* + 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 Scheduler + * @{ + */ + +#ifndef _SCHEDULER_H_ +#define _SCHEDULER_H_ + +/** Normal \p chSchReadyI() message.*/ +#define RDY_OK 0 +/** Returned if the thread was made ready because a timeout.*/ +#define RDY_TIMEOUT -1 +/** Returned if the thread was made ready because a reset.*/ +#define RDY_RESET -2 + +/** + * Ready list header. + */ +typedef struct { + /** Highest priority \p Thread in the list.*/ + Thread *p_next; + /** Lowest priority \p Thread in the list.*/ + Thread *p_prev; + /** Alwas set to \p MAXPRIO.*/ + t_prio p_prio; +} ReadyList; + +/* + * Scheduler APIs. + */ +void chSchInit(void); +Thread *chSchReadyI(Thread *tp); +void chSchGoSleepI(t_tstate newstate); +void chSchWakeupI(Thread *tp, t_msg msg); +void chSchRescheduleI(void); +void chSchDoRescheduleI(void); +BOOL chSchRescRequiredI(void); +void chSchTimerHandlerI(void); + +/** + * Current thread pointer. + * @note Dont use this directly but use the \p chThdSelf() + * instead. Direct use of system global variables is discouraged because + * portability reasons. + */ +#ifdef CH_CURRP_REGISTER_CACHE +register Thread *currp asm(CH_CURRP_REGISTER_CACHE); +#else +extern Thread *currp; +#endif + +/** + * System ticks counter. + * @note Dont use this directly but use the \p chSysGetTime() + * instead. Direct use of system global variables is discouraged because + * portability reasons. + */ +extern t_time stime; + +#endif /* _SCHEDULER_H_ */ + +/** @} */ diff --git a/src/include/semaphores.h b/src/include/semaphores.h new file mode 100644 index 000000000..83d4613de --- /dev/null +++ b/src/include/semaphores.h @@ -0,0 +1,82 @@ +/* + 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 Semaphores + * @{ + */ + +#ifndef _SEMAPHORES_H_ +#define _SEMAPHORES_H_ + +#ifdef CH_USE_SEMAPHORES + +/** + * Semaphore structure. + */ +typedef struct { + /** Queue of the threads sleeping on this Semaphore.*/ + ThreadsQueue s_queue; + /** The Semaphore counter.*/ + t_semcnt s_cnt; +} Semaphore; + +void chSemInit(Semaphore *sp, t_semcnt n); +void chSemReset(Semaphore *sp, t_semcnt n); +void chSemResetI(Semaphore *sp, t_semcnt n); +void chSemWait(Semaphore *sp); +void chSemWaitS(Semaphore *sp); +t_msg chSemWaitTimeout(Semaphore *sp, t_time time); +t_msg chSemWaitTimeoutS(Semaphore *sp, t_time time); +void chSemSignal(Semaphore *sp); +void chSemSignalI(Semaphore *sp); +void chSignalWait(Semaphore *sps, Semaphore *spw); + +#ifdef CH_USE_RT_SEMAPHORES +void chSemRaisePrioWait(Semaphore *sp); +void chSemLowerPrioSignal(Semaphore *sp); +void chSemRaisePrioSignalWait(Semaphore *sps, Semaphore *spw); +void chSemLowerPrioSignalWait(Semaphore *sps, Semaphore *spw); +#endif + +/** + * Decreases the semaphore counter, this macro can be used when it is ensured + * that the counter would not become negative. + */ +#define chSemFastWaitS(sp) \ + ((sp)->s_cnt--) + +/** + * Increases the semaphore counter, this macro can be used when the counter is + * not negative. + */ +#define chSemFastSignalI(sp) \ + ((sp)->s_cnt++) + +/** + * Returns the semaphore counter current value. + */ +#define chSemGetCounter(sp) \ + ((sp)->s_cnt) + +#endif /* CH_USE_SEMAPHORES */ + +#endif /* _SEM_H_ */ + +/** @} */ diff --git a/src/include/serial.h b/src/include/serial.h new file mode 100644 index 000000000..3d33975b1 --- /dev/null +++ b/src/include/serial.h @@ -0,0 +1,154 @@ +/* + 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 Serial + * @{ + */ + +#ifndef _SERIAL_H_ +#define _SERIAL_H_ + +/** No pending conditions.*/ +#define SD_NO_ERROR 0 +/** Connection happened.*/ +#define SD_CONNECTED 1 +/** Disconnection happened.*/ +#define SD_DISCONNECTED 2 +/** Parity error happened.*/ +#define SD_PARITY_ERROR 4 +/** Framing error happened.*/ +#define SD_FRAMING_ERROR 8 +/** Overflow happened.*/ +#define SD_OVERRUN_ERROR 16 +/** Break detected.*/ +#define SD_BREAK_DETECTED 32 + +/** Serial Driver condition flags type.*/ +typedef UWORD16 t_dflags; + +#ifdef CH_USE_SERIAL_FULLDUPLEX + +/** + * Full Duplex Serial Driver main structure. + */ +typedef struct { + + /** Input queue. Incoming data can be read from this queue by using the + * queues APIs.*/ + Queue sd_iqueue; + /** Data Available \p EventSource. This event is generated when some incoming + * data is inserted in the Input \p Queue.*/ + EventSource sd_ievent; + + /** Output queue. Outgoing data can be written to this Output \p Queue by + * using the queues APIs.*/ + Queue sd_oqueue; + /** Data Transmitted \p EventSource. This event is generated when the + * Output \p Queue is empty.*/ + EventSource sd_oevent; + + /** I/O driver status flags. This field should not be read directly but + * the \p chFDDGetAndClearFlags() funtion should be used instead.*/ + t_dflags sd_flags; + /** Status Change \p EventSource. This event is generated when a + * condition flag was changed.*/ + EventSource sd_sevent; +} FullDuplexDriver; + +void chFDDInit(FullDuplexDriver *sd, + BYTE8 *ib, t_size isize, t_qnotify inotify, + BYTE8 *ob, t_size osize, t_qnotify onotify); +void chFDDIncomingDataI(FullDuplexDriver *sd, BYTE8 b); +t_msg chFDDRequestDataI(FullDuplexDriver *sd); +void chFDDAddFlagsI(FullDuplexDriver *sd, t_dflags mask); +t_dflags chFDDGetAndClearFlags(FullDuplexDriver *sd); + +/** @see chIQRead()*/ +#define chFDDRead(sd, b, n) \ + chIQRead(&(sd)->sd_iqueue, b, n) + +/** @see chOQWrite()*/ +#define chFDDWrite(sd, b, n) \ + chOQWrite(&(sd)->sd_oqueue, b, n) + +/** @see chIQGet()*/ +#define chFDDGet(sd) \ + chIQGet(&(sd)->sd_iqueue) + +/** @see chIQGetTimeout()*/ +#define chFDDGetTimeout(sd, t) \ + chIQGetTimeout(&(sd)->sd_iqueue, t) + +/** @see chOQPut()*/ +#define chFDDPut(sd, b) \ + chOQPut(&(sd)->sd_oqueue, b) + +#endif /* CH_USE_SERIAL_FULLDUPLEX */ + +#ifdef CH_USE_SERIAL_HALFDUPLEX + +/** + * Full Duplex Serial Driver main structure. + */ +typedef struct { + + /** Data queue. Transmit/receive \p HalfDuplexQueue.*/ + HalfDuplexQueue sd_queue; + /** Data Available \p EventSource. This event is generated when some + * incoming data is inserted in the receive queue.*/ + EventSource sd_ievent; + /** Data Transmitted \p EventSource. This event is generated when the + * transmission queue is empty and the driver can either transmit more + * data or enter receive mode.*/ + EventSource sd_oevent; + + /** I/O driver status flags. This field should not be read directly but + * the \p chHDDGetAndClearFlags() funtion should be used + * instead.*/ + t_dflags sd_flags; + /** Status Change Event Source. This event is generated when a condition + * flag was changed.*/ + EventSource sd_sevent; +} HalfDuplexDriver; + +void chHDDInit(HalfDuplexDriver *sd, BYTE8 *b, t_size size, + t_qnotify inotify, t_qnotify onotify); +void chHDDIncomingDataI(HalfDuplexDriver *sd, BYTE8 b); +t_msg chHDDRequestDataI(HalfDuplexDriver *sd); +void chHDDAddFlagsI(HalfDuplexDriver *sd, t_dflags mask); +t_dflags chHDDGetAndClearFlags(HalfDuplexDriver *sd); + +/** @see chHDQGetReceive()*/ +#define chHDDGetReceive(sd) \ + chHDQGetReceive(&(sd)->sd_queue) + +/** @see chHDQGetReceiveTimeout()*/ +#define chHDDGetReceiveTimeout(sd, t) \ + chHDQGetReceiveTimeout(&(sd)->sd_queue, t) + +/** @see chHDQPutTransmit()*/ +#define chHDDPutTransmit(sd, b) \ + chHDQPutTransmit(&(sd)->sd_queue, b) + +#endif /* CH_USE_SERIAL_HALFDUPLEX */ + +#endif /* _SERIAL_H_ */ + +/** @} */ diff --git a/src/include/sleep.h b/src/include/sleep.h new file mode 100644 index 000000000..265500908 --- /dev/null +++ b/src/include/sleep.h @@ -0,0 +1,43 @@ +/* + 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 Time + * @{ + */ + +#ifndef _SLEEP_H_ +#define _SLEEP_H_ + +#ifdef CH_USE_SLEEP + +void chThdSleep(t_time time); + +#ifdef CH_USE_SYSTEMTIME + +void chThdSleepUntil(t_time time); +t_time chSysGetTime(void); + +#endif /* CH_USE_SYSTEMTIME */ + +#endif /* CH_USE_SLEEP */ + +#endif /* _SLEEP_H_ */ + +/** @} */ diff --git a/src/include/threads.h b/src/include/threads.h new file mode 100644 index 000000000..d8937433f --- /dev/null +++ b/src/include/threads.h @@ -0,0 +1,203 @@ +/* + 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 Threads + * @{ + */ + +#ifndef _THREADS_H_ +#define _THREADS_H_ + +#define isempty(qp) ((qp)->p_next == (Thread *)(qp)) +#define notempty(qp) ((qp)->p_next != (Thread *)(qp)) +#define firstprio(qp) ((qp)->p_next->p_prio) +#define lastprio(qp) ((qp)->p_prev->p_prio) + +/** + * Generic threads queue header and element. + */ +typedef struct { + /** First \p Thread in the queue.*/ + Thread *p_next; + /** Last \p Thread in the queue.*/ + Thread *p_prev; +} ThreadsQueue; + +/** + * Structure representing a thread. + * @note Not all the listed fields are always needed, by switching off some + * not needed ChibiOS/RT subsystems it is possible to save RAM space by + * shrinking the \p Thread structure. + */ +struct Thread { + /** Next \p Thread in the threads list.*/ + Thread *p_next; + /** Previous \p Thread in the threads list.*/ + Thread *p_prev; + /* End of the fields shared with the ThreadsQueue structure. */ + /** The thread priority.*/ + t_prio p_prio; + /* End of the fields shared with the ReadyList structure. */ + /** Current thread state.*/ + t_tstate p_state; + /** Mode flags.*/ + t_tmode p_flags; + /* + * The following fields are merged in an union because they are all + * state-specific fields. This trick saves some extra space for each + * thread in the system. + */ + union { + /** Thread wakeup code, normally set to \p RDY_OK by the \p chSchReadyI() + * (only while in \p PRCURR or \p PRREADY states).*/ + t_msg p_rdymsg; + /** The thread exit code (only while in \p PREXIT state).*/ + t_msg p_exitcode; +#ifdef CH_USE_EVENTS + /** Enabled events mask (only while in \p PRWTEVENT state).*/ + t_eventmask p_ewmask; +#endif +#ifdef CH_USE_MESSAGES + /** Message (only while in \p PRSNDMSG state).*/ + t_msg p_msg; +#endif + }; + /** Machine dependent processor context.*/ + Context p_ctx; + /* + * Start of the optional fields. Note, the null thread may also let its + * stack overwrite the following fields since it never uses semaphores, + * events, messages, exit etc, this can save some space on RAM starved + * systems, be caruful in doing so. + */ +#ifdef CH_USE_WAITEXIT + /** The queue of the threads waiting for this thread termination.*/ + ThreadsQueue p_waiting; +#endif +#ifdef CH_USE_EXIT_EVENT + /** The thread termination \p EventSource.*/ + EventSource p_exitesource; +#endif +#ifdef CH_USE_MESSAGES + ThreadsQueue p_msgqueue; +#endif +#ifdef CH_USE_EVENTS + /** Pending events mask.*/ + t_eventmask p_epending; +#endif +#ifdef CH_USE_RT_SEMAPHORES + /** Priority backup after acquiring a RT semaphore.*/ + t_prio p_bakprio; + /** RT semaphores depth counter.*/ + WORD16 p_rtcnt; +#endif +}; + +/** Thread state: Reserved.*/ +#define PRFREE 0 +/** Thread state: Current.*/ +#define PRCURR 1 +/** Thread state: Thread in the ready list.*/ +#define PRREADY 2 +/** Thread state: Thread created in suspended state.*/ +#define PRSUSPENDED 3 +/** Thread state: Waiting on a semaphore.*/ +#define PRWTSEM 4 +/** Thread state: Waiting in \p chThdSleep() or \p chThdSleepUntil().*/ +#define PRSLEEP 5 +/** Thread state: Waiting in \p chThdWait().*/ +#define PRWAIT 6 +/** Thread state: Waiting in \p chEvtWait().*/ +#define PRWTEVENT 7 +/** Thread state: Waiting in \p chMsgSend().*/ +#define PRSNDMSG 8 +/** Thread state: Waiting in \p chMsgWait().*/ +#define PRWTMSG 9 +/** Thread state: After termination.*/ +#define PREXIT 10 + +/** Thread option: Termination requested flag.*/ +#define P_TERMINATE 1 +/** Thread option: Create suspended thread.*/ +#define P_SUSPENDED 2 + +/** Idle thread priority.*/ +#define IDLEPRIO 0 +/** Lowest user priority.*/ +#define LOWPRIO 1 +/** Normal user priority.*/ +#define NORMALPRIO 128 +/** Highest user priority.*/ +#define HIGHPRIO 255 +/** Boosted base priority.*/ +#define MEPRIO 256 +/** Absolute priority.*/ +#define ABSPRIO 512 + +/* Not an API, don't use into the application code.*/ +void _InitThread(t_prio prio, t_tmode mode, Thread *tp); + +/** Thread function.*/ +typedef t_msg (*t_tfunc)(void *); + +/* + * Threads Lists functions. + */ +#ifndef CH_OPTIMIZE_SPEED +void enqueue(Thread *tp, ThreadsQueue *tqp); +Thread *dequeue(Thread *tp); +#else +static INLINE Thread *dequeue(Thread *tp) { + + tp->p_prev->p_next = tp->p_next; + tp->p_next->p_prev = tp->p_prev; + return tp; +} + +static INLINE void enqueue(Thread *tp, ThreadsQueue *tqp) { + + tp->p_next = (Thread *)tqp; + tp->p_prev = tqp->p_prev; + tqp->p_prev->p_next = tp; + tqp->p_prev = tp; +} +#endif + +/* + * Threads APIs. + */ +#define chThdSelf() currp +Thread *chThdCreate(t_prio prio, t_tmode mode, void *workspace, + t_size wsize, t_tfunc pf, void *arg); +void chThdResume(Thread *tp); +void chThdTerminate(Thread *tp); +BOOL chThdShouldTerminate(void); +BOOL chThdTerminated(Thread *tp); +void chThdExit(t_msg msg); +#ifdef CH_USE_WAITEXIT +t_msg chThdWait(Thread *tp); +#endif +#ifdef CH_USE_EXIT_EVENT +EventSource *chThdGetExitEventSource(Thread *tp); +#endif + +#endif /* _THREADS_H_ */ + +/** @} */ diff --git a/src/templates/chconf.h b/src/templates/chconf.h new file mode 100644 index 000000000..abb996899 --- /dev/null +++ b/src/templates/chconf.h @@ -0,0 +1,154 @@ +/* + 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 Config + * @{ + */ + +#ifndef _CHCONF_H_ +#define _CHCONF_H_ + +/* + * NOTE: this is just documentation for doxigen, the real configuration file + * is the one into the project directories. + */ + +/** Configuration option: if specified then time efficient rather than space + * efficient code is used when two possible implementations exist, note + * that this is not related to the compiler optimization options.*/ +#define CH_OPTIMIZE_SPEED + +/** Configuration option: if specified then the Virtual Timers subsystem is + * included in the kernel.*/ +#define CH_USE_VIRTUAL_TIMERS + +/** Configuration option: if specified then the System Timer subsystem is + * included in the kernel.*/ +#define CH_USE_SYSTEMTIME + +/** Configuration option: if specified then the \p chThdSleep() function is + * included in the kernel. + * @note requires \p CH_USE_VIRTUAL_TIMERS.*/ +#define CH_USE_SLEEP + +/** Configuration option: if specified then the \p chThdResume() + * function is included in the kernel.*/ +#define CH_USE_RESUME + +/** Configuration option: if specified then the \p chThdTerminate() + * and \p chThdShouldTerminate() functions are included in the kernel.*/ +#define CH_USE_TERMINATE + +/** Configuration option: if specified then the \p chThdWait() function + * is included in the kernel.*/ +#define CH_USE_WAITEXIT + +/** Configuration option: if specified then the Semaphores APIs are included + * in the kernel.*/ +#define CH_USE_SEMAPHORES + +/** Configuration option: if specified then the Semaphores with timeout APIs + * are included in the kernel. + * @note requires \p CH_USE_SEMAPHORES. + * @note requires \p CH_USE_VIRTUAL_TIMERS.*/ +#define CH_USE_SEMAPHORES_TIMEOUT + +/** Configuration option: if specified then the Semaphores APIs with priority + * shift are included in the kernel. + * @note requires \p CH_USE_SEMAPHORES.*/ +#define CH_USE_RT_SEMAPHORES + +/** Configuration option: if specified then the Events APIs are included in + * the kernel.*/ +#define CH_USE_EVENTS + +/** Configuration option: if specified then the \p chEvtWaitTimeout() + * function is included in the kernel. + * @note requires \p CH_USE_EVENTS. + * @note requires \p CH_USE_VIRTUAL_TIMERS.*/ +#define CH_USE_EVENTS_TIMEOUT + +/** Configuration option: if specified then the Synchronous Messages APIs are + * included in the kernel.*/ +#define CH_USE_MESSAGES + +/** Configuration option: if specified then the \p chMsgSendTimeout() + * function is included in the kernel. + * @note requires \p CH_USE_MESSAGES. + * @note requires \p CH_USE_VIRTUAL_TIMERS.*/ +#define CH_USE_MESSAGES_TIMEOUT + +/** Configuration option: if specified then the \p chMsgSendWithEvent() + * function is included in the kernel. + * @note requires \p CH_USE_MESSAGES. + * @note requires \p CH_USE_VIRTUAL_TIMERS.*/ +#define CH_USE_MESSAGES_EVENT + +/** Configuration option: if specified then the + * \p chThdGetExitEventSource() function is included in the kernel. + * @note requires \p CH_USE_MESSAGES. + * @note requires \p CH_USE_EVENTS.*/ +#define CH_USE_EXIT_EVENT + +/** Configuration option: if specified then the I/O queues APIs are included + * in the kernel.*/ +#define CH_USE_QUEUES + +/** Configuration option: if specified then the halfduplex queue APIs are + * included in the kernel.*/ +#define CH_USE_QUEUES_HALFDUPLEX + +/** Configuration option: if specified then the I/O queues with timeout + * APIs are included in the kernel. + * @note requires \p CH_USE_SEMAPHORES_TIMEOUT.*/ +#define CH_USE_QUEUES_TIMEOUT + +/** Configuration option: if specified then the full duplex serial driver APIs + * are included in the kernel.*/ +#define CH_USE_SERIAL_FULLDUPLEX + +/** Configuration option: if specified then the half duplex serial driver APIs + * are included in the kernel.*/ +#define CH_USE_SERIAL_HALFDUPLEX + +/** Configuration option: Frequency of the system timer that drives the system + * ticks. This also defines the system time unit.*/ +#define CH_FREQUENCY 100 + +/** Configuration option: This constant is the number of ticks allowed for the + * threads before preemption occurs.*/ +#define CH_TIME_QUANTUM 10 + +/** Configuration option: Defines a CPU register to be used as storage for the + * global \p currp variable. Caching this variable in a register can greatly + * improve both space and time efficiency of the generated code. Another side + * effect is that one less register has to be saved during the context switch + * resulting in lower RAM usage and faster code. + * @note This option is only useable with the GCC compiler and is only useful + * on processors with many registers like ARM cores. + * @note If this option is enabled then ALL the libraries linked to the + * ChibiOS/RT code must be recompiled with the GCC option \p + * -ffixed-\. + */ +#define CH_CURRP_REGISTER_CACHE "reg" + +#endif /* _CHCONF_H_ */ + +/** @} */ diff --git a/src/templates/chcore.c b/src/templates/chcore.c new file mode 100644 index 000000000..29a809378 --- /dev/null +++ b/src/templates/chcore.c @@ -0,0 +1,50 @@ +/* + 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 Core + * @{ + */ + +#include + +/* + * This file is just a template, it contains the function prototypes and the + * doxigen documentation. The implementation of the following functions is + * architecture/compiler specific. + */ + +/** + * This function implements the idle thread infinite loop. The function should + * put the processor in the lowest power mode capable to serve interrupts. + */ +void chSysPause(void) {} + +/** + * Abonormal system termination handler. Invoked by the ChobiOS/RT when an + * abnormal unrecoverable condition is met. + */ +void chSysHalt(void) {} + +/** + * Context switch. + */ +void chSysSwitchI(struct ctxswc **oldp, struct ctxswc *new) {} + +/** @} */ diff --git a/src/templates/chcore.h b/src/templates/chcore.h new file mode 100644 index 000000000..895e2b685 --- /dev/null +++ b/src/templates/chcore.h @@ -0,0 +1,69 @@ +/* + 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 Core + * @{ + */ + +#ifndef _CHCORE_H_ +#define _CHCORE_H_ + +/* + * Stack saved context. + */ +struct stackregs { +}; + +/** + * Platform dependent part of the \p chThdCreate() API. + */ +#define SETUP_CONTEXT(workspace, wsize, pf, arg) \ +{ \ +} + +/** + * Enters the ChobiOS/RT system mutual exclusion zone, the implementation is + * architecture dependent, on single core systems usually this function + * just disables the interrupts. + * @note The code in the system mutual exclusion zone must be as light and + * fast as possible, the system performance is affected by this. + * @note The use of system mutual exclusion zones are not recommended in + * the user code, it is a better idea to use the Semaphores instead. + */ +#define chSysLock() + +/** + * Leaves the ChobiOS/RT system mutual exclusion zone, the implementation is + * architecture dependent, on single core systems usually this function + * just enables the interrupts. + * @note The code in the system mutual exclusion zone must be as light and + * fast as possible, the system performance is affected by this. + * @note The use of system mutual exclusion zones are not recommended in + * the user code, it is a better idea to use the Semaphores instead. + */ +#define chSysUnlock() + +void chSysHalt(void); +void chSysPause(void); +void chSysSwitchI(struct ctxswc **oldp, struct ctxswc *new); + +#endif /* _CHCORE_H_ */ + +/** @} */ diff --git a/src/templates/chtypes.h b/src/templates/chtypes.h new file mode 100644 index 000000000..0d6547311 --- /dev/null +++ b/src/templates/chtypes.h @@ -0,0 +1,62 @@ +/* + 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 Core + * @{ + */ + +#ifndef _CHTYPES_H_ +#define _CHTYPES_H_ + +/* + * Generic types often dependant on the compiler. + */ +#define BOOL char +#define BYTE8 unsigned char +#define WORD16 short +#define UWORD16 unsigned short +#define LONG32 int +#define ULONG32 unsigned int +#define PTR_EQ int + +#define INT_REQUIRED_STACK 0 + +typedef BYTE8 t_tmode; +typedef BYTE8 t_tstate; +typedef WORD16 t_prio; +typedef PTR_EQ t_msg; +typedef LONG32 t_eventid; +typedef ULONG32 t_eventmask; +typedef ULONG32 t_time; +typedef LONG32 t_semcnt; +typedef ULONG32 t_size; + +#define MINPRIO 0x8000 +#define MAXPRIO 0x7fff + +#define MINDELTA 0 +#define MAXDELTA 0xffff + +#define THREAD +#define INLINE inline + +#endif /* _CHTYPES_H_ */ + +/** @} */ diff --git a/src/templates/readme.txt b/src/templates/readme.txt new file mode 100644 index 000000000..c7dd925d9 --- /dev/null +++ b/src/templates/readme.txt @@ -0,0 +1 @@ +Files that need to be copied in each project/port directory and configured. -- cgit v1.2.3