]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/lib/printf/PrintfP.nc
Updated to use generic printf functionality if none provided easily by their native...
[tinyos-2.x.git] / tos / lib / printf / PrintfP.nc
index 0065b0abc38aae8ed411e3d77516618b7f1cb130..b620e5e416f6a8b06caff9ade78afc9bb130ce7e 100644 (file)
  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
  * MODIFICATIONS."
  */
+ /*
+ * Copyright (c) 2007 Stanford University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - Neither the name of the Stanford University 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 COPYRIGHT HOLDERS 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 STANFORD
+ * UNIVERSITY OR ITS 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 is the PrintfP component.  It provides the printf service for printing
  * data over the serial interface using the standard c-style printf command.  
- * It must be started via the SplitControl interface it provides.  Data
- * printed using printf are buffered and only sent over the serial line after
- * making a call to PrintfFlush.flush().  This buffer has a maximum size of 
- * 250 bytes at present.  After calling start on this component, printf
- * statements can be made anywhere throughout your code, so long as you include
- * the "printf.h" header file in every file you wish to use it.  Standard
- * practice is to start the printf service in the main application, and set up 
- * a timer to periodically flush the printf buffer (500ms should do).  In future
- * versions, user defined buffer sizes as well as well as automatic flushing at 
- * user defined intervals will be supported.  
+ * Data printed using printf are buffered and only sent over the serial line after
+ * the buffer is half full or an explicit call to printfflush() is made.  This 
+ * buffer has a maximum size of 250 bytes at present.  This component is wired
+ * to a shadowed MainC component so that printf statements can be made anywhere 
+ * throughout your code, so long as you include the "printf.h" header file in 
+ * every file you wish to use it.  Take a look at the printf tutorial (lesson 15)
+ * for more details.
  *
  * The printf service is currently only available for msp430 based motes 
- * (i.e. telos, eyes) and atmega128 based motes (i.e. mica2, micaz).  On the
- * atmega platforms, avr-libc version 1.4 or above mus tbe used.
- * 
- *
- * @author Kevin Klues (klueska@cs.wustl.edu)
- * @version $Revision$
- * @date $Date$
+ * (i.e. telos, eyes) and atmega128x based motes (i.e. mica2, micaz, iris).  On the
+ * atmega platforms, avr-libc version 1.4 or above musbe used.
+ */
+/**
+ * @author Kevin Klues <klueska@cs.stanford.edu>
+ * @date September 18, 2007
  */
 
 #include "printf.h"
 
 #ifdef _H_atmega128hardware_H
 static int uart_putchar(char c, FILE *stream);
-static FILE atm128_stdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
+static FILE atm128_stdout = 
+       FDEV_SETUP_STREAM(TCAST(int (*)(char c, FILE *stream), uart_putchar), 
+       NULL, _FDEV_SETUP_WRITE);
 #endif
 
-module PrintfP {
+module PrintfP @safe() {
   provides {
-    interface SplitControl as PrintfControl;
-    interface PrintfFlush;
+    interface Boot;
   }
   uses {
-       interface SplitControl as SerialControl;
-    interface Leds;
+    interface Boot as MainBoot;
+    interface SplitControl as SerialControl;
+    interface PrintfQueue<uint8_t> as Queue;
+
     interface AMSend;
     interface Packet;
+    interface Leds;
   }
 }
 implementation {
-       
+  
   enum {
-       S_STARTED,
-       S_STOPPED,
-       S_FLUSHING,
+    S_STOPPED,
+    S_STARTED,
+    S_FLUSHING,
   };
-  
+
   message_t printfMsg;
-  nx_uint8_t buffer[PRINTF_BUFFER_SIZE];
-  norace nx_uint8_t* next_byte;
   uint8_t state = S_STOPPED;
-  uint8_t bytes_left_to_flush;
-  uint8_t length_to_send;
-  
-  task void retrySend() {
-    if(call AMSend.send(AM_BROADCAST_ADDR, &printfMsg, sizeof(printf_msg_t)) != SUCCESS)
-      post retrySend();
-  }
-  
-  void sendNext() {
-       printf_msg_t* m = (printf_msg_t*)call Packet.getPayload(&printfMsg, NULL);
-       length_to_send = (bytes_left_to_flush < sizeof(printf_msg_t)) ? bytes_left_to_flush : sizeof(printf_msg_t);
-       memset(m->buffer, 0, sizeof(printfMsg));
-       memcpy(m->buffer, (uint8_t*)next_byte, length_to_send);
-    if(call AMSend.send(AM_BROADCAST_ADDR, &printfMsg, sizeof(printf_msg_t)) != SUCCESS)
-      post retrySend();  
-    else {
-      bytes_left_to_flush -= length_to_send;
-      next_byte += length_to_send;
-    }
-  }
-
-  command error_t PrintfControl.start() {
-       if(state == S_STOPPED)
-      return call SerialControl.start();
-    return FAIL;
-  }
   
-  command error_t PrintfControl.stop() {
-       if(state == S_STARTED)
-      return call SerialControl.stop();
-    return FAIL;
+  event void MainBoot.booted() {
+    call SerialControl.start();
   }
 
   event void SerialControl.startDone(error_t error) {
-       if(error != SUCCESS) {
-         signal PrintfControl.startDone(error);
-         return;
-       }
+    if (state == S_STOPPED) {
 #ifdef _H_atmega128hardware_H
-       stdout = &atm128_stdout;
+      stdout = &atm128_stdout;
 #endif
-    atomic {
-      memset(buffer, 0, sizeof(buffer));
-      next_byte = buffer;
-      bytes_left_to_flush = 0; 
-      length_to_send = 0;
-      state = S_STARTED;
+      atomic state = S_STARTED;
+      signal Boot.booted();
     }
-    signal PrintfControl.startDone(error); 
   }
 
   event void SerialControl.stopDone(error_t error) {
-       if(error != SUCCESS) {
-         signal PrintfControl.stopDone(error);
-         return;
-       }
     atomic state = S_STOPPED;
-    signal PrintfControl.stopDone(error); 
   }
   
-  command error_t PrintfFlush.flush() {
-       atomic {
-         if(state == S_STARTED && (next_byte > buffer)) {
-           state = S_FLUSHING;
-        bytes_left_to_flush = next_byte - buffer;
-           next_byte = buffer;
-         }
-         else return FAIL;
-       }
-       sendNext();
-       return SUCCESS;
+  task void retrySend() {
+    if(call AMSend.send(AM_BROADCAST_ADDR, &printfMsg, sizeof(printf_msg_t)) != SUCCESS)
+      post retrySend();
+  }
+  
+  void sendNext() {
+    int i;
+    printf_msg_t* m = (printf_msg_t*)call Packet.getPayload(&printfMsg, sizeof(printf_msg_t));
+    uint16_t length_to_send = (call Queue.size() < sizeof(printf_msg_t)) ? call Queue.size() : sizeof(printf_msg_t);
+    memset(m->buffer, 0, sizeof(printf_msg_t));
+    for(i=0; i<length_to_send; i++)
+      m->buffer[i] = call Queue.dequeue();
+    if(call AMSend.send(AM_BROADCAST_ADDR, &printfMsg, sizeof(printf_msg_t)) != SUCCESS)
+      post retrySend();  
+  }
+  
+  int printfflush() @C() @spontaneous() {
+    atomic {
+      if(state == S_FLUSHING)
+        return SUCCESS;
+      if(call Queue.empty())
+        return FAIL;
+      state = S_FLUSHING;
+    }
+    sendNext();
+    return SUCCESS;
   }
     
   event void AMSend.sendDone(message_t* msg, error_t error) {    
-       if(error == SUCCESS) {
-         if(bytes_left_to_flush > 0)
-           sendNext();
-         else {
-        next_byte = buffer;
-        bytes_left_to_flush = 0; 
-       length_to_send = 0;
-        atomic state = S_STARTED;
-           signal PrintfFlush.flushDone(error);
-         }
-       }
-       else post retrySend();
+    if(error == SUCCESS) {
+      if(call Queue.size() > 0)
+        sendNext();
+      else state = S_STARTED;
+    }
+    else post retrySend();
   }
   
 #ifdef _H_msp430hardware_h
   int putchar(int c) __attribute__((noinline)) @C() @spontaneous() {
-#endif
+#else
 #ifdef _H_atmega128hardware_H
   int uart_putchar(char c, FILE *stream) __attribute__((noinline)) @C() @spontaneous() {
+#else
+#ifdef __M16C62PHARDWARE_H__
+  int lowlevel_putc(int c) __attribute__((noinline)) @C() @spontaneous() {
+#else
+  int lowlevel_putc(int c) __attribute__((noinline)) @C() @spontaneous() {
 #endif
-       atomic {
-         if(state == S_STARTED && ((next_byte-buffer+1) < PRINTF_BUFFER_SIZE)) {
-           *next_byte = c;
-           next_byte++;
-           return 0;
-         }
-         else return -1;
-       }
+#endif
+#endif
+    if((state == S_STARTED) && (call Queue.size() >= ((PRINTF_BUFFER_SIZE)/2))) {
+      state = S_FLUSHING;
+      sendNext();
+    }
+    atomic {
+      if(call Queue.enqueue(c) == SUCCESS)
+        return 0;
+      else return -1;
+    }
   }
 }