aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2007-09-18 12:40:26 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2007-09-18 12:40:26 +0000
commit30f0bb1d66f016d6d8366aa483ca12a4724bd599 (patch)
treeaf369b2f1302da6261e5fc8feb7bfe933fba6e89
parentf712427135d6c180e413a3a22ba75290bb19a6b5 (diff)
downloadChibiOS-30f0bb1d66f016d6d8366aa483ca12a4724bd599.tar.gz
ChibiOS-30f0bb1d66f016d6d8366aa483ca12a4724bd599.tar.bz2
ChibiOS-30f0bb1d66f016d6d8366aa483ca12a4724bd599.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r--src/chdelta.c84
-rw-r--r--src/chevents.c247
-rw-r--r--src/chinit.c59
-rw-r--r--src/chmsg.c194
-rw-r--r--src/chqueues.c478
-rw-r--r--src/chschd.c205
-rw-r--r--src/chsem.c376
-rw-r--r--src/chserial.c195
-rw-r--r--src/chsleep.c79
-rw-r--r--src/chthreads.c265
-rw-r--r--src/include/ch.h97
-rw-r--r--src/include/delta.h83
-rw-r--r--src/include/events.h95
-rw-r--r--src/include/messages.h59
-rw-r--r--src/include/queues.h172
-rw-r--r--src/include/scheduler.h81
-rw-r--r--src/include/semaphores.h82
-rw-r--r--src/include/serial.h154
-rw-r--r--src/include/sleep.h43
-rw-r--r--src/include/threads.h203
-rw-r--r--src/templates/chconf.h154
-rw-r--r--src/templates/chcore.c50
-rw-r--r--src/templates/chcore.h69
-rw-r--r--src/templates/chtypes.h62
-rw-r--r--src/templates/readme.txt1
25 files changed, 3587 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup VirtualTimers
+ * @{
+ */
+
+#include <ch.h>
+
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Events
+ * @{
+ */
+#include <ch.h>
+
+#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.<br>
+ * 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.<br>
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Initialization
+ * @{
+ */
+
+#include <ch.h>
+
+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.<br><br>
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Messages
+ * @{
+ */
+#include <ch.h>
+
+#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.<br>
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup IOQueues
+ * @{
+ */
+
+#include <ch.h>
+
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Scheduler
+ * @{
+ */
+
+#include <ch.h>
+
+/** @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Semaphores
+ * @{
+ */
+
+#include <ch.h>
+
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Serial
+ * @{
+ */
+
+#include <ch.h>
+
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Time
+ * @{
+ */
+
+#include <ch.h>
+
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Threads
+ * @{
+ */
+
+#include <ch.h>
+
+#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:<br>
+ * <ul>
+ * <li>\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.</li>
+ * <li>\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.</li>
+ * </ul>
+ * @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:<br>
+ * <ul>
+ * <li>Create the thread suspended, register on the event source
+ * and then resume the thread (recommended).</li>
+ * <li>Create the thread with a lower priority then register on it.
+ * This does not work if the hardware is capable of multiple
+ * physical threads.</li>
+ * </ul>
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Initialization
+ * @{
+ */
+
+#ifndef _CH_H_
+#define _CH_H_
+
+typedef struct Thread Thread;
+
+#ifndef __DOXIGEN__
+#ifndef _CHCONF_H_
+#include <chconf.h>
+#endif
+
+#ifndef _CHTYPES_H_
+#include <chtypes.h>
+#endif
+
+#ifndef _CHCORE_H_
+#include <chcore.h>
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <b>must</b> be recompiled with the GCC option \p
+ * -ffixed-\<reg\>.
+ */
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @addtogroup Core
+ * @{
+ */
+
+#include <ch.h>
+
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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.