Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:ee91220d7bea, committed 2010-11-30
- Comitter:
- taoxh
- Date:
- Tue Nov 30 23:53:06 2010 +0000
- Commit message:
- HW2 PROTOTHREAD
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lc-addrlabels.h Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the Contiki operating system.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc-addrlabels.h,v 1.4 2006/06/03 11:29:43 adam Exp $
+ */
+
+/**
+ * \addtogroup lc
+ * @{
+ */
+
+/**
+ * \file
+ * Implementation of local continuations based on the "Labels as
+ * values" feature of gcc
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ * This implementation of local continuations is based on a special
+ * feature of the GCC C compiler called "labels as values". This
+ * feature allows assigning pointers with the address of the code
+ * corresponding to a particular C label.
+ *
+ * For more information, see the GCC documentation:
+ * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
+ *
+ */
+
+#ifndef __LC_ADDRLABELS_H__
+#define __LC_ADDRLABELS_H__
+
+/** \hideinitializer */
+typedef void * lc_t;
+
+#define LC_INIT(s) s = NULL
+
+#define LC_RESUME(s) \
+ do { \
+ if(s != NULL) { \
+ goto *s; \
+ } \
+ } while(0)
+
+#define LC_CONCAT2(s1, s2) s1##s2
+#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2)
+
+#define LC_SET(s) \
+ do { \
+ LC_CONCAT(LC_LABEL, __LINE__): \
+ (s) = &&LC_CONCAT(LC_LABEL, __LINE__); \
+ } while(0)
+
+#define LC_END(s)
+
+#endif /* __LC_ADDRLABELS_H__ */
+/** @} */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lc-switch.h Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the Contiki operating system.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc-switch.h,v 1.4 2006/06/03 11:29:43 adam Exp $
+ */
+
+/**
+ * \addtogroup lc
+ * @{
+ */
+
+/**
+ * \file
+ * Implementation of local continuations based on switch() statment
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ * This implementation of local continuations uses the C switch()
+ * statement to resume execution of a function somewhere inside the
+ * function's body. The implementation is based on the fact that
+ * switch() statements are able to jump directly into the bodies of
+ * control structures such as if() or while() statmenets.
+ *
+ * This implementation borrows heavily from Simon Tatham's coroutines
+ * implementation in C:
+ * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
+ */
+
+#ifndef __LC_SWITCH_H__
+#define __LC_SWITCH_H__
+
+/* WARNING! lc implementation using switch() does not work if an
+ LC_SET() is done within another switch() statement! */
+
+/** \hideinitializer */
+typedef unsigned short lc_t;
+
+#define LC_INIT(s) s = 0;
+
+#define LC_RESUME(s) switch(s) { case 0:
+
+#define LC_SET(s) s = __LINE__; case __LINE__:
+
+#define LC_END(s) }
+
+#endif /* __LC_SWITCH_H__ */
+
+/** @} */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lc.h Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the protothreads library.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc.h,v 1.2 2005/02/24 10:36:59 adam Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \defgroup lc Local continuations
+ * @{
+ *
+ * Local continuations form the basis for implementing protothreads. A
+ * local continuation can be <i>set</i> in a specific function to
+ * capture the state of the function. After a local continuation has
+ * been set can be <i>resumed</i> in order to restore the state of the
+ * function at the point where the local continuation was set.
+ *
+ *
+ */
+
+/**
+ * \file lc.h
+ * Local continuations
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifdef DOXYGEN
+/**
+ * Initialize a local continuation.
+ *
+ * This operation initializes the local continuation, thereby
+ * unsetting any previously set continuation state.
+ *
+ * \hideinitializer
+ */
+#define LC_INIT(lc)
+
+/**
+ * Set a local continuation.
+ *
+ * The set operation saves the state of the function at the point
+ * where the operation is executed. As far as the set operation is
+ * concerned, the state of the function does <b>not</b> include the
+ * call-stack or local (automatic) variables, but only the program
+ * counter and such CPU registers that needs to be saved.
+ *
+ * \hideinitializer
+ */
+#define LC_SET(lc)
+
+/**
+ * Resume a local continuation.
+ *
+ * The resume operation resumes a previously set local continuation, thus
+ * restoring the state in which the function was when the local
+ * continuation was set. If the local continuation has not been
+ * previously set, the resume operation does nothing.
+ *
+ * \hideinitializer
+ */
+#define LC_RESUME(lc)
+
+/**
+ * Mark the end of local continuation usage.
+ *
+ * The end operation signifies that local continuations should not be
+ * used any more in the function. This operation is not needed for
+ * most implementations of local continuation, but is required by a
+ * few implementations.
+ *
+ * \hideinitializer
+ */
+#define LC_END(lc)
+
+/**
+ * \var typedef lc_t;
+ *
+ * The local continuation type.
+ *
+ * \hideinitializer
+ */
+#endif /* DOXYGEN */
+
+#ifndef __LC_H__
+#define __LC_H__
+
+
+#ifdef LC_INCLUDE
+#include LC_INCLUDE
+#else
+#include "lc-switch.h"
+#endif /* LC_INCLUDE */
+
+#endif /* __LC_H__ */
+
+/** @} */
+/** @} */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,185 @@
+/**
+ * This is hw2_3 that shows the implementation of
+ * protothreads. The program consists of three protothreads that wait
+ * for each other to toggle a variable.
+ */
+
+/* We must always include pt.h in our protothreads code. */
+#include "pt.h"
+#include "mbed.h"
+#include "pre_work.h"
+
+/* Three flags that the three protothread functions use. */
+static int protothread1_flag, protothread2_flag, protothread3_flag;
+
+ int count=0;
+ int pre_cir_pro=0; // in case of initial trigger fault
+ int judge=1;
+ int shown=0;
+/**
+ * The first protothread function. It achieves the pc input part.
+ *
+ * The protothread function is driven by the main loop further down in
+ * the code.
+ */
+static int
+protothread1(struct pt *pt)
+{
+ PT_BEGIN(pt);
+ /* We loop forever here. */
+ while(1) {
+ /* Wait until the other protothread has set its flag. */
+ PT_WAIT_UNTIL(pt, protothread2_flag != 0 || pc.readable());//wait until pc inputs
+ // printf("Protothread 1 running\n");
+ /* We then reset the other protothread's flag, and set our own
+ flag so that the other protothread can run. */
+ protothread2_flag = 0;
+ protothread1_flag = 1;
+ char temp;
+ if (pc.readable()) {
+ temp=pc.getc();
+ if (temp=='E'&& length!=0){pc.printf("Input ends");}
+ else if (temp=='E'&& length==0){pc.printf("Error. No 'S' before 'E'");}
+ else if (temp=='S'){pc.printf("It is a new start.");length=0;count=0;}
+ else if (temp=='1'){
+ str[length]='1';length++;}
+ else if (temp=='0'){
+ str[length]='0';length++;}
+ else if (temp==' '){}
+ else senderror2();
+ if (length>40) {pc.printf("The allocated space is too small.");}
+ for (int i=0;i<length; i++)
+ { pc.putc(str[i]);}
+ pc.printf("\n");
+
+ }
+ // PT_WAIT_UNTIL(pt, pc.readable());
+ // pc.printf("I am here. Start inputing.");
+ // pc.getc();
+ // length=gtchar();
+ /* And we loop. */
+ protothread3_flag=1;
+ }
+
+ /* All protothread functions must end with PT_END() which takes a
+ pointer to a struct pt. */
+ PT_END(pt);
+}
+
+/**
+ * The second protothread function. This is almost the same as the
+ * first one. This part helps with the sensor input.
+ */
+static int
+protothread2(struct pt *pt)
+{
+ PT_BEGIN(pt);
+ while(1) {
+ /* Let the other protothread run. */
+ protothread2_flag = 1;
+ /* Wait until the other protothread has set its flag. */
+ PT_WAIT_UNTIL(pt, protothread1_flag != 0); //This part always usually has not trigger info
+ // printf("Protothread 2 running\n");
+ /* We then reset the other protothread's flag. */
+ protothread1_flag = 0;
+ if (touchSense1()&& !touchSense2()) { //T0 happens
+ myled1 = 1;
+ myled2=0;
+ pc.putc('a');
+ shown=0;
+ while(1) {if (!test1()){break;} if (touchSense2()&& touchSense1()) {break;}}
+ // if (str[count]=='0') {judge=0;}
+ // judge=1;
+ // pc.putc(str[count]);
+ if (count>=length){
+ for (int i=1;i<count;i++)
+ { str2[i-1]=str2[i];
+ pc.putc(str2[i-1]);
+ }
+ str2[count-1]='1';
+ pc.putc(str2[count-1]);}
+ else { str2[count]='1';count++;}
+ //process_char();
+ } else if (touchSense2()&& !touchSense1()) { //T1 happens
+ if (pre_cir_pro>30){
+ myled1 = 0;
+ myled2=1;
+ pc.putc('b');
+ shown=0;
+ while(1) {if (!test2()){break;} if (touchSense2()&& touchSense1()) {break;} }
+ // if (str[count]=='1') {judge=0;}
+ // judge=0;
+ // pc.putc(str[count]);
+ if (count>=length){
+ for (int i=1;i<count;i++)
+ { str2[i-1]=str2[i];
+ pc.putc(str2[i-1]);
+ }
+ str2[count-1]='0';
+ pc.putc(str2[count-1]);}
+ else { str2[count]='0';count++;}
+ }
+ } else if (touchSense2()&& touchSense1()) { //Touch error
+ myled1 = 1;
+ myled2=1;
+ senderror();
+ } else { //anything else
+ myled1=0;
+ myled2=0;
+ }
+ pre_cir_pro++;
+ /* And we loop. */
+ protothread3_flag=1;
+ }
+ PT_END(pt);
+}
+
+static int
+protothread3(struct pt *pt)
+{
+ /* A protothread function must begin with PT_BEGIN() which takes a
+ pointer to a struct pt. Match judging and output */
+ PT_BEGIN(pt);
+ /* We loop forever here. */
+ while(1) {
+ PT_WAIT_UNTIL(pt,count>=length &&count!=0 && protothread3_flag==1 );
+ // pc.printf("here");
+ for (int i=0;i<length;i++)
+ { if (str[i]!=str2[i]) {judge=0;} }
+ if (judge==1 && shown==0) {pc.printf("\nMATCH");shown=1;}
+ judge=1;
+ protothread3_flag=0;
+ // PT_WAIT_UNTIL(pt, pc.readable());
+ // pc.printf("I am here. Start inputing.");
+ // pc.getc();
+ // length=gtchar();
+ /* And we loop. */
+ }
+
+ /* All protothread functions must end with PT_END() which takes a
+ pointer to a struct pt. */
+ PT_END(pt);
+}
+
+
+/**
+ * Finally, we have the main loop. Here is where the protothreads are
+ * initialized and scheduled. Almost nothing in it.
+ */
+static struct pt pt1,pt2,pt3;
+int
+main(void)
+{
+ /* Initialize the protothread state variables with PT_INIT(). */
+ PT_INIT(&pt1);
+ PT_INIT(&pt2);
+ PT_INIT(&pt3);
+ /*
+ * Then we schedule the three protothreads by repeatedly calling their
+ * protothread functions and passing a pointer to the protothread
+ * state variables as arguments.
+ */while(1){ protothread2(&pt2);
+ protothread1(&pt1);
+ protothread3(&pt3);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Nov 30 23:53:06 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pre_work.h Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,79 @@
+#include "mbed.h"
+
+#define numsamples 1
+int touchSense1(void);
+int touchSense2(void);
+int senderror ();
+int senderror2 ();
+int test1();
+int test2();
+DigitalOut myled1(LED1);
+AnalogIn input1(p20);
+DigitalIn charger1(p19);
+DigitalOut ground1(p18);
+
+DigitalOut myled2(LED2);
+AnalogIn input2(p15);
+DigitalIn charger2(p16);
+DigitalOut ground2(p17);
+Serial pc(USBTX, USBRX); // tx, rx
+char str[40];
+char str2[40];
+int length=0;
+int touchSense1(void) {
+ float sample;
+ ground1 = 0;
+ charger1.mode(PullUp);
+ charger1.mode(PullNone);
+ sample=input1.read();
+ if (sample < 0.3) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int touchSense2(void) {
+ float sample;
+ ground2 = 0;
+ charger2.mode(PullUp);
+ charger2.mode(PullNone);
+ sample=input2.read();
+ if (sample < 0.3) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int senderror () {
+ pc.printf("Touch Error");
+ return 0;
+ }
+
+int senderror2 () {
+ pc.printf("Host Error");
+ return 0;
+ }
+
+
+
+
+
+ int test1()
+ {
+ int j=1000;
+ int judge=0;
+ for (int i=0;i<j;i++)
+ { if(touchSense1()) {judge=1;}}
+ return judge;
+ }
+
+ int test2()
+ {
+ int j=1000;
+ int judge=0;
+ for (int i=0;i<j;i++)
+ { if(touchSense2()) {judge=1;}}
+ return judge;
+ }
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pt-sem.h Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the protothreads library.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: pt-sem.h,v 1.2 2005/02/24 10:36:59 adam Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \defgroup ptsem Protothread semaphores
+ * @{
+ *
+ * This module implements counting semaphores on top of
+ * protothreads. Semaphores are a synchronization primitive that
+ * provide two operations: "wait" and "signal". The "wait" operation
+ * checks the semaphore counter and blocks the thread if the counter
+ * is zero. The "signal" operation increases the semaphore counter but
+ * does not block. If another thread has blocked waiting for the
+ * semaphore that is signalled, the blocked thread will become
+ * runnable again.
+ *
+ * Semaphores can be used to implement other, more structured,
+ * synchronization primitives such as monitors and message
+ * queues/bounded buffers (see below).
+ *
+ * The following example shows how the producer-consumer problem, also
+ * known as the bounded buffer problem, can be solved using
+ * protothreads and semaphores. Notes on the program follow after the
+ * example.
+ *
+ \code
+#include "pt-sem.h"
+
+#define NUM_ITEMS 32
+#define BUFSIZE 8
+
+static struct pt_sem mutex, full, empty;
+
+PT_THREAD(producer(struct pt *pt))
+{
+ static int produced;
+
+ PT_BEGIN(pt);
+
+ for(produced = 0; produced < NUM_ITEMS; ++produced) {
+
+ PT_SEM_WAIT(pt, &full);
+
+ PT_SEM_WAIT(pt, &mutex);
+ add_to_buffer(produce_item());
+ PT_SEM_SIGNAL(pt, &mutex);
+
+ PT_SEM_SIGNAL(pt, &empty);
+ }
+
+ PT_END(pt);
+}
+
+PT_THREAD(consumer(struct pt *pt))
+{
+ static int consumed;
+
+ PT_BEGIN(pt);
+
+ for(consumed = 0; consumed < NUM_ITEMS; ++consumed) {
+
+ PT_SEM_WAIT(pt, &empty);
+
+ PT_SEM_WAIT(pt, &mutex);
+ consume_item(get_from_buffer());
+ PT_SEM_SIGNAL(pt, &mutex);
+
+ PT_SEM_SIGNAL(pt, &full);
+ }
+
+ PT_END(pt);
+}
+
+PT_THREAD(driver_thread(struct pt *pt))
+{
+ static struct pt pt_producer, pt_consumer;
+
+ PT_BEGIN(pt);
+
+ PT_SEM_INIT(&empty, 0);
+ PT_SEM_INIT(&full, BUFSIZE);
+ PT_SEM_INIT(&mutex, 1);
+
+ PT_INIT(&pt_producer);
+ PT_INIT(&pt_consumer);
+
+ PT_WAIT_THREAD(pt, producer(&pt_producer) &
+ consumer(&pt_consumer));
+
+ PT_END(pt);
+}
+ \endcode
+ *
+ * The program uses three protothreads: one protothread that
+ * implements the consumer, one thread that implements the producer,
+ * and one protothread that drives the two other protothreads. The
+ * program uses three semaphores: "full", "empty" and "mutex". The
+ * "mutex" semaphore is used to provide mutual exclusion for the
+ * buffer, the "empty" semaphore is used to block the consumer is the
+ * buffer is empty, and the "full" semaphore is used to block the
+ * producer is the buffer is full.
+ *
+ * The "driver_thread" holds two protothread state variables,
+ * "pt_producer" and "pt_consumer". It is important to note that both
+ * these variables are declared as <i>static</i>. If the static
+ * keyword is not used, both variables are stored on the stack. Since
+ * protothreads do not store the stack, these variables may be
+ * overwritten during a protothread wait operation. Similarly, both
+ * the "consumer" and "producer" protothreads declare their local
+ * variables as static, to avoid them being stored on the stack.
+ *
+ *
+ */
+
+/**
+ * \file
+ * Couting semaphores implemented on protothreads
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __PT_SEM_H__
+#define __PT_SEM_H__
+
+#include "pt.h"
+
+struct pt_sem {
+ unsigned int count;
+};
+
+/**
+ * Initialize a semaphore
+ *
+ * This macro initializes a semaphore with a value for the
+ * counter. Internally, the semaphores use an "unsigned int" to
+ * represent the counter, and therefore the "count" argument should be
+ * within range of an unsigned int.
+ *
+ * \param s (struct pt_sem *) A pointer to the pt_sem struct
+ * representing the semaphore
+ *
+ * \param c (unsigned int) The initial count of the semaphore.
+ * \hideinitializer
+ */
+#define PT_SEM_INIT(s, c) (s)->count = c
+
+/**
+ * Wait for a semaphore
+ *
+ * This macro carries out the "wait" operation on the semaphore. The
+ * wait operation causes the protothread to block while the counter is
+ * zero. When the counter reaches a value larger than zero, the
+ * protothread will continue.
+ *
+ * \param pt (struct pt *) A pointer to the protothread (struct pt) in
+ * which the operation is executed.
+ *
+ * \param s (struct pt_sem *) A pointer to the pt_sem struct
+ * representing the semaphore
+ *
+ * \hideinitializer
+ */
+#define PT_SEM_WAIT(pt, s) \
+ do { \
+ PT_WAIT_UNTIL(pt, (s)->count > 0); \
+ --(s)->count; \
+ } while(0)
+
+/**
+ * Signal a semaphore
+ *
+ * This macro carries out the "signal" operation on the semaphore. The
+ * signal operation increments the counter inside the semaphore, which
+ * eventually will cause waiting protothreads to continue executing.
+ *
+ * \param pt (struct pt *) A pointer to the protothread (struct pt) in
+ * which the operation is executed.
+ *
+ * \param s (struct pt_sem *) A pointer to the pt_sem struct
+ * representing the semaphore
+ *
+ * \hideinitializer
+ */
+#define PT_SEM_SIGNAL(pt, s) ++(s)->count
+
+#endif /* __PT_SEM_H__ */
+
+/** @} */
+/** @} */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pt.h Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the Contiki operating system.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: pt.h,v 1.7 2006/10/02 07:52:56 adam Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \file
+ * Protothreads implementation.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __PT_H__
+#define __PT_H__
+
+#include "lc.h"
+
+struct pt {
+ lc_t lc;
+};
+
+#define PT_WAITING 0
+#define PT_YIELDED 1
+#define PT_EXITED 2
+#define PT_ENDED 3
+
+/**
+ * \name Initialization
+ * @{
+ */
+
+/**
+ * Initialize a protothread.
+ *
+ * Initializes a protothread. Initialization must be done prior to
+ * starting to execute the protothread.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \sa PT_SPAWN()
+ *
+ * \hideinitializer
+ */
+#define PT_INIT(pt) LC_INIT((pt)->lc)
+
+/** @} */
+
+/**
+ * \name Declaration and definition
+ * @{
+ */
+
+/**
+ * Declaration of a protothread.
+ *
+ * This macro is used to declare a protothread. All protothreads must
+ * be declared with this macro.
+ *
+ * \param name_args The name and arguments of the C function
+ * implementing the protothread.
+ *
+ * \hideinitializer
+ */
+#define PT_THREAD(name_args) char name_args
+
+/**
+ * Declare the start of a protothread inside the C function
+ * implementing the protothread.
+ *
+ * This macro is used to declare the starting point of a
+ * protothread. It should be placed at the start of the function in
+ * which the protothread runs. All C statements above the PT_BEGIN()
+ * invokation will be executed each time the protothread is scheduled.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)
+
+/**
+ * Declare the end of a protothread.
+ *
+ * This macro is used for declaring that a protothread ends. It must
+ * always be used together with a matching PT_BEGIN() macro.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
+ PT_INIT(pt); return PT_ENDED; }
+
+/** @} */
+
+/**
+ * \name Blocked wait
+ * @{
+ */
+
+/**
+ * Block and wait until condition is true.
+ *
+ * This macro blocks the protothread until the specified condition is
+ * true.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param condition The condition.
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_UNTIL(pt, condition) \
+ do { \
+ LC_SET((pt)->lc); \
+ if(!(condition)) { \
+ return PT_WAITING; \
+ } \
+ } while(0)
+
+/**
+ * Block and wait while condition is true.
+ *
+ * This function blocks and waits while condition is true. See
+ * PT_WAIT_UNTIL().
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param cond The condition.
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))
+
+/** @} */
+
+/**
+ * \name Hierarchical protothreads
+ * @{
+ */
+
+/**
+ * Block and wait until a child protothread completes.
+ *
+ * This macro schedules a child protothread. The current protothread
+ * will block until the child protothread completes.
+ *
+ * \note The child protothread must be manually initialized with the
+ * PT_INIT() function before this function is used.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param thread The child protothread with arguments
+ *
+ * \sa PT_SPAWN()
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))
+
+/**
+ * Spawn a child protothread and wait until it exits.
+ *
+ * This macro spawns a child protothread and waits until it exits. The
+ * macro can only be used within a protothread.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param child A pointer to the child protothread's control structure.
+ * \param thread The child protothread with arguments
+ *
+ * \hideinitializer
+ */
+#define PT_SPAWN(pt, child, thread) \
+ do { \
+ PT_INIT((child)); \
+ PT_WAIT_THREAD((pt), (thread)); \
+ } while(0)
+
+/** @} */
+
+/**
+ * \name Exiting and restarting
+ * @{
+ */
+
+/**
+ * Restart the protothread.
+ *
+ * This macro will block and cause the running protothread to restart
+ * its execution at the place of the PT_BEGIN() call.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_RESTART(pt) \
+ do { \
+ PT_INIT(pt); \
+ return PT_WAITING; \
+ } while(0)
+
+/**
+ * Exit the protothread.
+ *
+ * This macro causes the protothread to exit. If the protothread was
+ * spawned by another protothread, the parent protothread will become
+ * unblocked and can continue to run.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_EXIT(pt) \
+ do { \
+ PT_INIT(pt); \
+ return PT_EXITED; \
+ } while(0)
+
+/** @} */
+
+/**
+ * \name Calling a protothread
+ * @{
+ */
+
+/**
+ * Schedule a protothread.
+ *
+ * This function shedules a protothread. The return value of the
+ * function is non-zero if the protothread is running or zero if the
+ * protothread has exited.
+ *
+ * \param f The call to the C function implementing the protothread to
+ * be scheduled
+ *
+ * \hideinitializer
+ */
+#define PT_SCHEDULE(f) ((f) < PT_EXITED)
+
+/** @} */
+
+/**
+ * \name Yielding from a protothread
+ * @{
+ */
+
+/**
+ * Yield from the current protothread.
+ *
+ * This function will yield the protothread, thereby allowing other
+ * processing to take place in the system.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_YIELD(pt) \
+ do { \
+ PT_YIELD_FLAG = 0; \
+ LC_SET((pt)->lc); \
+ if(PT_YIELD_FLAG == 0) { \
+ return PT_YIELDED; \
+ } \
+ } while(0)
+
+/**
+ * \brief Yield from the protothread until a condition occurs.
+ * \param pt A pointer to the protothread control structure.
+ * \param cond The condition.
+ *
+ * This function will yield the protothread, until the
+ * specified condition evaluates to true.
+ *
+ *
+ * \hideinitializer
+ */
+#define PT_YIELD_UNTIL(pt, cond) \
+ do { \
+ PT_YIELD_FLAG = 0; \
+ LC_SET((pt)->lc); \
+ if((PT_YIELD_FLAG == 0) || !(cond)) { \
+ return PT_YIELDED; \
+ } \
+ } while(0)
+
+/** @} */
+
+#endif /* __PT_H__ */
+
+/** @} */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timer.h Tue Nov 30 23:53:06 2010 +0000
@@ -0,0 +1,126 @@
+#ifndef TIMER_H
+#define TIMER_H
+
+#include <ctime>
+#include <iostream>
+#include <iomanip>
+
+class timer
+{
+ friend std::ostream& operator<<(std::ostream& os, timer& t);
+
+ private:
+ bool running;
+ clock_t start_clock;
+ time_t start_time;
+ double acc_time;
+
+ double elapsed_time();
+
+ public:
+ // 'running' is initially false. A timer needs to be explicitly started
+ // using 'start' or 'restart'
+ timer() : running(false), start_clock(0), start_time(0), acc_time(0) { }
+
+ void start(const char* msg = 0);
+ void restart(const char* msg = 0);
+ void stop(const char* msg = 0);
+ void check(const char* msg = 0);
+
+}; // class timer
+
+//===========================================================================
+// Return the total time that the timer has been in the "running"
+// state since it was first "started" or last "restarted". For
+// "short" time periods (less than an hour), the actual cpu time
+// used is reported instead of the elapsed time.
+
+inline double timer::elapsed_time()
+{
+ time_t acc_sec = time(0) - start_time;
+ if (acc_sec < 3600)
+ return (clock() - start_clock) / (1.0 * CLOCKS_PER_SEC);
+ else
+ return (1.0 * acc_sec);
+
+} // timer::elapsed_time
+
+//===========================================================================
+// Start a timer. If it is already running, let it continue running.
+// Print an optional message.
+
+inline void timer::start(const char* msg)
+{
+ // Print an optional message, something like "Starting timer t";
+ if (msg) std::cout << msg << std::endl;
+
+ // Return immediately if the timer is already running
+ if (running) return;
+
+ // Set timer status to running and set the start time
+ running = true;
+ start_clock = clock();
+ start_time = time(0);
+
+} // timer::start
+
+//===========================================================================
+// Turn the timer off and start it again from 0. Print an optional message.
+
+inline void timer::restart(const char* msg)
+{
+ // Print an optional message, something like "Restarting timer t";
+ if (msg) std::cout << msg << std::endl;
+
+ // Set timer status to running, reset accumulated time, and set start time
+ running = true;
+ acc_time = 0;
+ start_clock = clock();
+ start_time = time(0);
+
+} // timer::restart
+
+//===========================================================================
+// Stop the timer and print an optional message.
+
+inline void timer::stop(const char* msg)
+{
+ // Print an optional message, something like "Stopping timer t";
+ if (msg) std::cout << msg << std::endl;
+
+ // Compute accumulated running time and set timer status to not running
+ if (running) acc_time += elapsed_time();
+ running = false;
+
+} // timer::stop
+
+//===========================================================================
+// Print out an optional message followed by the current timer timing.
+
+inline void timer::check(const char* msg)
+{
+ // Print an optional message, something like "Checking timer t";
+ if (msg) std::cout << msg << " : ";
+
+ std::cout << "Elapsed time [" << std::setiosflags(std::ios::fixed)
+ << std::setprecision(2)
+ << acc_time + (running ? elapsed_time() : 0) << "] seconds\n";
+
+} // timer::check
+
+//===========================================================================
+// Allow timers to be printed to ostreams using the syntax 'os << t'
+// for an ostream 'os' and a timer 't'. For example, "cout << t" will
+// print out the total amount of time 't' has been "running".
+
+inline std::ostream& operator<<(std::ostream& os, timer& t)
+{
+ os << std::setprecision(2) << std::setiosflags(std::ios::fixed)
+ << t.acc_time + (t.running ? t.elapsed_time() : 0);
+ return os;
+}
+
+//===========================================================================
+
+#endif // TIMER_H
+