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 +