From: klueska Date: Thu, 12 Jun 2008 12:33:47 +0000 (+0000) Subject: Updated Printf library to new way of not requiring explicit wiring of any interfaces... X-Git-Tag: release_tinyos_2_1_0_0~318 X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=commitdiff_plain;h=7e3e9dc68fd8299266a07e07357853271d424cdb Updated Printf library to new way of not requiring explicit wiring of any interfaces. Moved old implementation down into a 2_0_2 directory so that people can still use the old implementation if desired by simply changing the path to the lib in their Makefile --- diff --git a/tos/lib/printf/2_0_2/PrintfC.nc b/tos/lib/printf/2_0_2/PrintfC.nc new file mode 100644 index 00000000..a9a8b738 --- /dev/null +++ b/tos/lib/printf/2_0_2/PrintfC.nc @@ -0,0 +1,62 @@ +/* + * "Copyright (c) 2006 Washington University in St. Louis. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL WASHINGTON UNIVERSITY IN ST. LOUIS BE LIABLE TO ANY PARTY + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING + * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF WASHINGTON + * UNIVERSITY IN ST. LOUIS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * WASHINGTON UNIVERSITY IN ST. LOUIS SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND WASHINGTON UNIVERSITY IN ST. LOUIS HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + * MODIFICATIONS." + */ + +/** + * This is the PrintfC 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. + * + * @author Kevin Klues (klueska@cs.wustl.edu) + * @version $Revision$ + * @date $Date$ + */ + +#include "printf.h" + +configuration PrintfC { + provides { + interface SplitControl as PrintfControl; + interface PrintfFlush; + } +} +implementation { + components SerialActiveMessageC; + components new SerialAMSenderC(AM_PRINTF_MSG); + components PrintfP; + + PrintfControl = PrintfP; + PrintfFlush = PrintfP; + + PrintfP.SerialControl -> SerialActiveMessageC; + PrintfP.AMSend -> SerialAMSenderC; + PrintfP.Packet -> SerialAMSenderC; +} + diff --git a/tos/lib/printf/2_0_2/PrintfFlush.nc b/tos/lib/printf/2_0_2/PrintfFlush.nc new file mode 100644 index 00000000..64b247fe --- /dev/null +++ b/tos/lib/printf/2_0_2/PrintfFlush.nc @@ -0,0 +1,36 @@ +/* + * "Copyright (c) 2006 Washington University in St. Louis. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL WASHINGTON UNIVERSITY IN ST. LOUIS BE LIABLE TO ANY PARTY + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING + * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF WASHINGTON + * UNIVERSITY IN ST. LOUIS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * WASHINGTON UNIVERSITY IN ST. LOUIS SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND WASHINGTON UNIVERSITY IN ST. LOUIS HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + * MODIFICATIONS." + */ + +/** + * + * @author Kevin Klues (klueska@cs.wustl.edu) + * @version $Revision$ + * @date $Date$ + */ + +#include "printf.h" + +interface PrintfFlush +{ + command error_t flush(); + event void flushDone(error_t error); +} diff --git a/tos/lib/printf/2_0_2/PrintfP.nc b/tos/lib/printf/2_0_2/PrintfP.nc new file mode 100644 index 00000000..5f4ae231 --- /dev/null +++ b/tos/lib/printf/2_0_2/PrintfP.nc @@ -0,0 +1,179 @@ +/* + * "Copyright (c) 2006 Washington University in St. Louis. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL WASHINGTON UNIVERSITY IN ST. LOUIS BE LIABLE TO ANY PARTY + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING + * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF WASHINGTON + * UNIVERSITY IN ST. LOUIS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * WASHINGTON UNIVERSITY IN ST. LOUIS SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND WASHINGTON UNIVERSITY IN ST. LOUIS HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + * MODIFICATIONS." + */ + +/** + * 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. + * + * 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$ + */ + +#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); +#endif + +module PrintfP { + provides { + interface SplitControl as PrintfControl; + interface PrintfFlush; + } + uses { + interface SplitControl as SerialControl; + interface AMSend; + interface Packet; + } +} +implementation { + + enum { + S_STARTED, + S_STOPPED, + S_FLUSHING, + }; + + message_t printfMsg; + nx_uint8_t buffer[PRINTF_BUFFER_SIZE]; + norace nx_uint8_t* next_byte; + uint8_t state = S_STOPPED; + uint32_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, sizeof(printf_msg_t)); + length_to_send = (bytes_left_to_flush < sizeof(printf_msg_t)) ? bytes_left_to_flush : sizeof(printf_msg_t); + memset(m->buffer, 0, sizeof(printf_msg_t)); + memcpy(m->buffer, (nx_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 SerialControl.startDone(error_t error) { + if(error != SUCCESS) { + signal PrintfControl.startDone(error); + return; + } +#ifdef _H_atmega128hardware_H + 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; + } + 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; + } + + 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(); + } + +#ifdef _H_msp430hardware_h + int putchar(int c) __attribute__((noinline)) @C() @spontaneous() { +#endif +#ifdef _H_atmega128hardware_H + int uart_putchar(char c, FILE *stream) __attribute__((noinline)) @C() @spontaneous() { +#endif + atomic { + if(state == S_STARTED && ((next_byte-buffer) < PRINTF_BUFFER_SIZE)) { + *(next_byte++) = c; + return 0; + } + else return -1; + } + } +} diff --git a/tos/lib/printf/2_0_2/avr_stdio.h b/tos/lib/printf/2_0_2/avr_stdio.h new file mode 100644 index 00000000..8d1808d0 --- /dev/null +++ b/tos/lib/printf/2_0_2/avr_stdio.h @@ -0,0 +1,1094 @@ +/* Copyright (c) 2002, 2005, Joerg Wunsch + All rights reserved. + + Portions of documentation Copyright (c) 1990, 1991, 1993 + The Regents of the University of California. + + 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 copyright holders nor the names of + 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 THE COPYRIGHT OWNER 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. + + $Id$ +*/ + +#ifndef _STDIO_H_ +#define _STDIO_H_ 1 + +#ifndef __ASSEMBLER__ + +#include +#include + +#define __need_NULL +#define __need_size_t +#include + +/** \defgroup avr_stdio : Standard IO facilities + \code #include \endcode + +

Introduction to the Standard IO facilities

+ + This file declares the standard IO facilities that are implemented + in \c avr-libc. Due to the nature of the underlying hardware, + only a limited subset of standard IO is implemented. There is no + actual file implementation available, so only device IO can be + performed. Since there's no operating system, the application + needs to provide enough details about their devices in order to + make them usable by the standard IO facilities. + + Due to space constraints, some functionality has not been + implemented at all (like some of the \c printf conversions that + have been left out). Nevertheless, potential users of this + implementation should be warned: the \c printf and \c scanf families of functions, although + usually associated with presumably simple things like the + famous "Hello, world!" program, are actually fairly complex + which causes their inclusion to eat up a fair amount of code space. + Also, they are not fast due to the nature of interpreting the + format string at run-time. Whenever possible, resorting to the + (sometimes non-standard) predetermined conversion facilities that are + offered by avr-libc will usually cost much less in terms of speed + and code size. + +

Tunable options for code size vs. feature set

+ + In order to allow programmers a code size vs. functionality tradeoff, + the function vfprintf() which is the heart of the printf family can be + selected in different flavours using linker options. See the + documentation of vfprintf() for a detailed description. The same + applies to vfscanf() and the \c scanf family of functions. + +

Outline of the chosen API

+ + The standard streams \c stdin, \c stdout, and \c stderr are + provided, but contrary to the C standard, since avr-libc has no + knowledge about applicable devices, these streams are not already + pre-initialized at application startup. Also, since there is no + notion of "file" whatsoever to avr-libc, there is no function + \c fopen() that could be used to associate a stream to some device. + (See \ref stdio_note1 "note 1".) Instead, the function \c fdevopen() + is provided to associate a stream to a device, where the device + needs to provide a function to send a character, to receive a + character, or both. There is no differentiation between "text" and + "binary" streams inside avr-libc. Character \c \\n is sent + literally down to the device's \c put() function. If the device + requires a carriage return (\c \\r) character to be sent before + the linefeed, its \c put() routine must implement this (see + \ref stdio_note2 "note 2"). + + As an alternative method to fdevopen(), the macro + fdev_setup_stream() might be used to setup a user-supplied FILE + structure. + + It should be noted that the automatic conversion of a newline + character into a carriage return - newline sequence breaks binary + transfers. If binary transfers are desired, no automatic + conversion should be performed, but instead any string that aims + to issue a CR-LF sequence must use "\r\n" explicitly. + + For convenience, the first call to \c fdevopen() that opens a + stream for reading will cause the resulting stream to be aliased + to \c stdin. Likewise, the first call to \c fdevopen() that opens + a stream for writing will cause the resulting stream to be aliased + to both, \c stdout, and \c stderr. Thus, if the open was done + with both, read and write intent, all three standard streams will + be identical. Note that these aliases are indistinguishable from + each other, thus calling \c fclose() on such a stream will also + effectively close all of its aliases (\ref stdio_note3 "note 3"). + + It is possible to tie additional user data to a stream, using + fdev_set_udata(). The backend put and get functions can then + extract this user data using fdev_get_udata(), and act + appropriately. For example, a single put function could be used + to talk to two different UARTs that way, or the put and get + functions could keep internal state between calls there. + +

Format strings in flash ROM

+ + All the \c printf and \c scanf family functions come in two flavours: the + standard name, where the format string is expected to be in + SRAM, as well as a version with the suffix "_P" where the format + string is expected to reside in the flash ROM. The macro + \c PSTR (explained in \ref avr_pgmspace) becomes very handy + for declaring these format strings. + + \anchor stdio_without_malloc +

Running stdio without malloc()

+ + By default, fdevopen() as well as the floating-point versions of + the printf and scanf family require malloc(). As this is often + not desired in the limited environment of a microcontroller, an + alternative option is provided to run completely without malloc(). + + The macro fdev_setup_stream() is provided to prepare a + user-supplied FILE buffer for operation with stdio. If + floating-point operation is desired, a user-supplied buffer can as + well be passed for the internal buffering for the floating-point + numbers (and processing of \%[ scanf data). + +

Example

+ + \code + #include + + static int uart_putchar(char c, FILE *stream); + + static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, + _FDEV_SETUP_WRITE); + + static int + uart_putchar(char c, FILE *stream) + { + + if (c == '\n') + uart_putchar('\r', stream); + loop_until_bit_is_set(UCSRA, UDRE); + UDR = c; + return 0; + } + + int + main(void) + { + init_uart(); + stdout = &mystdout; + printf("Hello, world!\n"); + + return 0; + } + \endcode + + This example uses the initializer form FDEV_SETUP_STREAM() rather + than the function-like fdev_setup_stream(), so all data + initialization happens during C start-up. + + If streams initialized that way are no longer needed, they can be + destroyed by first calling the macro fdev_close(), and then + destroying the object itself. No call to fclose() should be + issued for these streams. While calling fclose() itself is + harmless, it will cause an undefined reference to free() and thus + cause the linker to link the malloc module into the application. + +

Notes

+ + \anchor stdio_note1 \par Note 1: + It might have been possible to implement a device abstraction that + is compatible with \c fopen() but since this would have required + to parse a string, and to take all the information needed either + out of this string, or out of an additional table that would need to be + provided by the application, this approach was not taken. + + \anchor stdio_note2 \par Note 2: + This basically follows the Unix approach: if a device such as a + terminal needs special handling, it is in the domain of the + terminal device driver to provide this functionality. Thus, a + simple function suitable as \c put() for \c fdevopen() that talks + to a UART interface might look like this: + + \code + int + uart_putchar(char c, FILE *stream) + { + + if (c == '\n') + uart_putchar('\r'); + loop_until_bit_is_set(UCSRA, UDRE); + UDR = c; + return 0; + } + \endcode + + \anchor stdio_note3 \par Note 3: + This implementation has been chosen because the cost of maintaining + an alias is considerably smaller than the cost of maintaining full + copies of each stream. Yet, providing an implementation that offers + the complete set of standard streams was deemed to be useful. Not + only that writing \c printf() instead of fprintf(mystream, ...) + saves typing work, but since avr-gcc needs to resort to pass all + arguments of variadic functions on the stack (as opposed to passing + them in registers for functions that take a fixed number of + parameters), the ability to pass one parameter less by implying + \c stdin will also save some execution time. +*/ + +#if !defined(__DOXYGEN__) + +/* + * This is an internal structure of the library that is subject to be + * changed without warnings at any time. Please do *never* reference + * elements of it beyond by using the official interfaces provided. + */ +struct __file { + char *buf; /* buffer pointer */ + unsigned char unget; /* ungetc() buffer */ + uint8_t flags; /* flags, see below */ +#define __SRD 0x0001 /* OK to read */ +#define __SWR 0x0002 /* OK to write */ +#define __SSTR 0x0004 /* this is an sprintf/snprintf string */ +#define __SPGM 0x0008 /* fmt string is in progmem */ +#define __SERR 0x0010 /* found error */ +#define __SEOF 0x0020 /* found EOF */ +#define __SUNGET 0x040 /* ungetc() happened */ +#define __SMALLOC 0x80 /* handle is malloc()ed */ +#if 0 +/* possible future extensions, will require uint16_t flags */ +#define __SRW 0x0100 /* open for reading & writing */ +#define __SLBF 0x0200 /* line buffered */ +#define __SNBF 0x0400 /* unbuffered */ +#define __SMBF 0x0800 /* buf is from malloc */ +#endif + int size; /* size of buffer */ + int len; /* characters read or written so far */ + int (*put)(char, struct __file *); /* function to write one char to device */ + int (*get)(struct __file *); /* function to read one char from device */ + void *udata; /* User defined and accessible data. */ +}; + +#endif /* not __DOXYGEN__ */ + +/*@{*/ +/** + \c FILE is the opaque structure that is passed around between the + various standard IO functions. +*/ +#define FILE struct __file + +/** + Stream that will be used as an input stream by the simplified + functions that don't take a \c stream argument. + + The first stream opened with read intent using \c fdevopen() + will be assigned to \c stdin. +*/ +#define stdin (__iob[0]) + +/** + Stream that will be used as an output stream by the simplified + functions that don't take a \c stream argument. + + The first stream opened with write intent using \c fdevopen() + will be assigned to both, \c stdin, and \c stderr. +*/ +#define stdout (__iob[1]) + +/** + Stream destined for error output. Unless specifically assigned, + identical to \c stdout. + + If \c stderr should point to another stream, the result of + another \c fdevopen() must be explicitly assigned to it without + closing the previous \c stderr (since this would also close + \c stdout). +*/ +#define stderr (__iob[2]) + +/** + \c EOF declares the value that is returned by various standard IO + functions in case of an error. Since the AVR platform (currently) + doesn't contain an abstraction for actual files, its origin as + "end of file" is somewhat meaningless here. +*/ +#define EOF (-1) + +/** This macro inserts a pointer to user defined data into a FILE + stream object. + + The user data can be useful for tracking state in the put and get + functions supplied to the fdevopen() function. */ +#define fdev_set_udata(stream, u) do { (stream)->udata = u; } while(0) + +/** This macro retrieves a pointer to user defined data from a FILE + stream object. */ +#define fdev_get_udata(stream) ((stream)->udata) + +#if defined(__DOXYGEN__) +/** + \brief Setup a user-supplied buffer as an stdio stream + + This macro takes a user-supplied buffer \c stream, and sets it up + as a stream that is valid for stdio operations, similar to one that + has been obtained dynamically from fdevopen(). The buffer to setup + must be of type FILE. + + The arguments \c put and \c get are identical to those that need to + be passed to fdevopen(). + + The \c rwflag argument can take one of the values _FDEV_SETUP_READ, + _FDEV_SETUP_WRITE, or _FDEV_SETUP_RW, for read, write, or read/write + intent, respectively. + + \note No assignments to the standard streams will be performed by + fdev_setup_stream(). If standard streams are to be used, these + need to be assigned by the user. See also under + \ref stdio_without_malloc "Running stdio without malloc()". + */ +#define fdev_setup_stream(stream, put, get, rwflag) +#else /* !DOXYGEN */ +#define fdev_setup_stream(stream, p, g, f) \ + do { \ + (stream)->put = p; \ + (stream)->get = g; \ + (stream)->flags = f; \ + (stream)->udata = 0; \ + } while(0) +#endif /* DOXYGEN */ + +#define _FDEV_SETUP_READ __SRD /**< fdev_setup_stream() with read intent */ +#define _FDEV_SETUP_WRITE __SWR /**< fdev_setup_stream() with write intent */ +#define _FDEV_SETUP_RW (__SRD|__SWR) /**< fdev_setup_stream() with read/write intent */ + +/** + * Return code for an error condition during device read. + * + * To be used in the get function of fdevopen(). + */ +#define _FDEV_ERR (-1) + +/** + * Return code for an end-of-file condition during device read. + * + * To be used in the get function of fdevopen(). + */ +#define _FDEV_EOF (-2) + +#if defined(__DOXYGEN__) +/** + \brief Initializer for a user-supplied stdio stream + + This macro acts similar to fdev_setup_stream(), but it is to be + used as the initializer of a variable of type FILE. + + The remaining arguments are to be used as explained in + fdev_setup_stream(). + */ +#define FDEV_SETUP_STREAM(put, get, rwflag) +#else /* !DOXYGEN */ +#define FDEV_SETUP_STREAM(p, g, f) \ + { \ + .put = p, \ + .get = g, \ + .flags = f, \ + .udata = 0, \ + } +#endif /* DOXYGEN */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__DOXYGEN__) +/* + * Doxygen documentation can be found in fdevopen.c. + */ + +extern struct __file *__iob[]; + +#if defined(__STDIO_FDEVOPEN_COMPAT_12) +/* + * Declare prototype for the discontinued version of fdevopen() that + * has been in use up to avr-libc 1.2.x. The new implementation has + * some backwards compatibility with the old version. + */ +extern FILE *fdevopen(int (*__put)(char), int (*__get)(void), + int __opts __attribute__((unused))); +#else /* !defined(__STDIO_FDEVOPEN_COMPAT_12) */ +/* New prototype for avr-libc 1.4 and above. */ +extern FILE *fdevopen(int (*__put)(char, FILE*), int (*__get)(FILE*)); +#endif /* defined(__STDIO_FDEVOPEN_COMPAT_12) */ + +#endif /* not __DOXYGEN__ */ + +/** + This function closes \c stream, and disallows and further + IO to and from it. + + When using fdevopen() to setup the stream, a call to fclose() is + needed in order to free the internal resources allocated. + + If the stream has been set up using fdev_setup_stream() or + FDEV_SETUP_STREAM(), use fdev_close() instead. + + It currently always returns 0 (for success). +*/ +extern int fclose(FILE *__stream); + +/** + This macro frees up any library resources that might be associated + with \c stream. It should be called if \c stream is no longer + needed, right before the application is going to destroy the + \c stream object itself. + + (Currently, this macro evaluates to nothing, but this might change + in future versions of the library.) +*/ +#if defined(__DOXYGEN__) +# define fdev_close() +#else +# define fdev_close() ((void)0) +#endif + +/** + \c vfprintf is the central facility of the \c printf family of + functions. It outputs values to \c stream under control of a + format string passed in \c fmt. The actual values to print are + passed as a variable argument list \c ap. + + \c vfprintf returns the number of characters written to \c stream, + or \c EOF in case of an error. Currently, this will only happen + if \c stream has not been opened with write intent. + + The format string is composed of zero or more directives: ordinary + characters (not \c %), which are copied unchanged to the output + stream; and conversion specifications, each of which results in + fetching zero or more subsequent arguments. Each conversion + specification is introduced by the \c % character. The arguments must + properly correspond (after type promotion) with the conversion + specifier. After the \c %, the following appear in sequence: + + - Zero or more of the following flags: +
    +
  • \c # The value should be converted to an "alternate form". For + c, d, i, s, and u conversions, this option has no effect. + For o conversions, the precision of the number is + increased to force the first character of the output + string to a zero (except if a zero value is printed with + an explicit precision of zero). For x and X conversions, + a non-zero result has the string `0x' (or `0X' for X + conversions) prepended to it.
  • +
  • \c 0 (zero) Zero padding. For all conversions, the converted + value is padded on the left with zeros rather than blanks. + If a precision is given with a numeric conversion (d, i, + o, u, i, x, and X), the 0 flag is ignored.
  • +
  • \c - A negative field width flag; the converted value is to be + left adjusted on the field boundary. The converted value + is padded on the right with blanks, rather than on the + left with blanks or zeros. A - overrides a 0 if both are + given.
  • +
  • ' ' (space) A blank should be left before a positive number + produced by a signed conversion (d, or i).
  • +
  • \c + A sign must always be placed before a number produced by a + signed conversion. A + overrides a space if both are + used.
  • +
+ + - An optional decimal digit string specifying a minimum field width. + If the converted value has fewer characters than the field width, it + will be padded with spaces on the left (or right, if the left-adjust­ + ment flag has been given) to fill out the field width. + - An optional precision, in the form of a period . followed by an + optional digit string. If the digit string is omitted, the + precision is taken as zero. This gives the minimum number of + digits to appear for d, i, o, u, x, and X conversions, or the + maximum number of characters to be printed from a string for \c s + conversions. + - An optional \c l length modifier, that specifies that the + argument for the d, i, o, u, x, or X conversion is a \c "long int" + rather than \c int. + - A character that specifies the type of conversion to be applied. + + The conversion specifiers and their meanings are: + + - \c diouxX The int (or appropriate variant) argument is converted + to signed decimal (d and i), unsigned octal (o), unsigned + decimal (u), or unsigned hexadecimal (x and X) notation. + The letters "abcdef" are used for x conversions; the + letters "ABCDEF" are used for X conversions. The + precision, if any, gives the minimum number of digits that + must appear; if the converted value requires fewer digits, + it is padded on the left with zeros. + - \c p The void * argument is taken as an unsigned integer, + and converted similarly as a %\#x command would do. + - \c c The \c int argument is converted to an \c "unsigned char", and the + resulting character is written. + - \c s The \c "char *" argument is expected to be a pointer to an array + of character type (pointer to a string). Characters from + the array are written up to (but not including) a + terminating NUL character; if a precision is specified, no + more than the number specified are written. If a precision + is given, no null character need be present; if the + precision is not specified, or is greater than the size of + the array, the array must contain a terminating NUL + character. + - \c % A \c % is written. No argument is converted. The complete + conversion specification is "%%". + - \c eE The double argument is rounded and converted in the format + \c "[-]d.ddde±dd" where there is one digit before the + decimal-point character and the number of digits after it + is equal to the precision; if the precision is missing, it + is taken as 6; if the precision is zero, no decimal-point + character appears. An \e E conversion uses the letter \c 'E' + (rather than \c 'e') to introduce the exponent. The exponent + always contains two digits; if the value is zero, + the exponent is 00. + - \c fF The double argument is rounded and converted to decimal notation + in the format \c "[-]ddd.ddd", where the number of digits after the + decimal-point character is equal to the precision specification. + If the precision is missing, it is taken as 6; if the precision + is explicitly zero, no decimal-point character appears. If a + decimal point appears, at least one digit appears before it. + - \c gG The double argument is converted in style \c f or \c e (or + \c F or \c E for \c G conversions). The precision + specifies the number of significant digits. If the + precision is missing, 6 digits are given; if the precision + is zero, it is treated as 1. Style \c e is used if the + exponent from its conversion is less than -4 or greater + than or equal to the precision. Trailing zeros are removed + from the fractional part of the result; a decimal point + appears only if it is followed by at least one digit. + - \c S Similar to the \c s format, except the pointer is expected to + point to a program-memory (ROM) string instead of a RAM string. + + In no case does a non-existent or small field width cause truncation of a + numeric field; if the result of a conversion is wider than the field + width, the field is expanded to contain the conversion result. + + Since the full implementation of all the mentioned features becomes + fairly large, three different flavours of vfprintf() can be + selected using linker options. The default vfprintf() implements + all the mentioned functionality except floating point conversions. + A minimized version of vfprintf() is available that only implements + the very basic integer and string conversion facilities, but none + of the additional options that can be specified using conversion + flags (these flags are parsed correctly from the format + specification, but then simply ignored). This version can be + requested using the following \ref gcc_minusW "compiler options": + + \code + -Wl,-u,vfprintf -lprintf_min + \endcode + + If the full functionality including the floating point conversions + is required, the following options should be used: + + \code + -Wl,-u,vfprintf -lprintf_flt -lm + \endcode + + \par Limitations: + - The specified width and precision can be at most 127. + - For floating-point conversions, trailing digits will be lost if + a number close to DBL_MAX is converted with a precision > 0. + + */ + +extern int vfprintf(FILE *__stream, const char *__fmt, va_list __ap); + +/** + Variant of \c vfprintf() that uses a \c fmt string that resides + in program memory. +*/ +extern int vfprintf_P(FILE *__stream, const char *__fmt, va_list __ap); + +/** + The function \c fputc sends the character \c c (though given as type + \c int) to \c stream. It returns the character, or \c EOF in case + an error occurred. +*/ +extern int fputc(int __c, FILE *__stream); + +#if !defined(__DOXYGEN__) + +/* putc() function implementation, required by standard */ +extern int putc(int __c, FILE *__stream); + +/* putchar() function implementation, required by standard */ +extern int putchar(int __c); + +#endif /* not __DOXYGEN__ */ + +/** + The macro \c putc used to be a "fast" macro implementation with a + functionality identical to fputc(). For space constraints, in + \c avr-libc, it is just an alias for \c fputc. +*/ +#define putc(__c, __stream) fputc(__c, __stream) + +/** + The macro \c putchar sends character \c c to \c stdout. +*/ +#define putchar(__c) fputc(__c, stdout) + +/** + The function \c printf performs formatted output to stream + \c stderr. See \c vfprintf() for details. +*/ +extern int printf(const char *__fmt, ...); + +/** + Variant of \c printf() that uses a \c fmt string that resides + in program memory. +*/ +extern int printf_P(const char *__fmt, ...); + +/** + The function \c vprintf performs formatted output to stream + \c stdout, taking a variable argument list as in vfprintf(). + + See vfprintf() for details. +*/ +extern int vprintf(const char *__fmt, va_list __ap); + +/** + Variant of \c printf() that sends the formatted characters + to string \c s. +*/ +extern int sprintf(char *__s, const char *__fmt, ...); + +/** + Variant of \c sprintf() that uses a \c fmt string that resides + in program memory. +*/ +extern int sprintf_P(char *__s, const char *__fmt, ...); + +/** + Like \c sprintf(), but instead of assuming \c s to be of infinite + size, no more than \c n characters (including the trailing NUL + character) will be converted to \c s. + + Returns the number of characters that would have been written to + \c s if there were enough space. +*/ +extern int snprintf(char *__s, size_t __n, const char *__fmt, ...); + +/** + Variant of \c snprintf() that uses a \c fmt string that resides + in program memory. +*/ +extern int snprintf_P(char *__s, size_t __n, const char *__fmt, ...); + +/** + Like \c sprintf() but takes a variable argument list for the + arguments. +*/ +extern int vsprintf(char *__s, const char *__fmt, va_list ap); + +/** + Variant of \c vsprintf() that uses a \c fmt string that resides + in program memory. +*/ +extern int vsprintf_P(char *__s, const char *__fmt, va_list ap); + +/** + Like \c vsprintf(), but instead of assuming \c s to be of infinite + size, no more than \c n characters (including the trailing NUL + character) will be converted to \c s. + + Returns the number of characters that would have been written to + \c s if there were enough space. +*/ +extern int vsnprintf(char *__s, size_t __n, const char *__fmt, va_list ap); + +/** + Variant of \c vsnprintf() that uses a \c fmt string that resides + in program memory. +*/ +extern int vsnprintf_P(char *__s, size_t __n, const char *__fmt, va_list ap); +/** + The function \c fprintf performs formatted output to \c stream. + See \c vfprintf() for details. +*/ +extern int fprintf(FILE *__stream, const char *__fmt, ...); + +/** + Variant of \c fprintf() that uses a \c fmt string that resides + in program memory. +*/ +extern int fprintf_P(FILE *__stream, const char *__fmt, ...); + +/** + Write the string pointed to by \c str to stream \c stream. + + Returns 0 on success and EOF on error. +*/ +extern int fputs(const char *__str, FILE *__stream); + +/** + Variant of fputs() where \c str resides in program memory. +*/ +extern int fputs_P(const char *__str, FILE *__stream); + +/** + Write the string pointed to by \c str, and a trailing newline + character, to \c stdout. +*/ +extern int puts(const char *__str); + +/** + Variant of puts() where \c str resides in program memory. +*/ +extern int puts_P(const char *__str); + +/** + Write \c nmemb objects, \c size bytes each, to \c stream. + The first byte of the first object is referenced by \c ptr. + + Returns the number of objects successfully written, i. e. + \c nmemb unless an output error occured. + */ +extern size_t fwrite(const void *__ptr, size_t __size, size_t __nmemb, + FILE *__stream); + +/** + The function \c fgetc reads a character from \c stream. It returns + the character, or \c EOF in case end-of-file was encountered or an + error occurred. The routines feof() or ferror() must be used to + distinguish between both situations. +*/ +extern int fgetc(FILE *__stream); + +#if !defined(__DOXYGEN__) + +/* getc() function implementation, required by standard */ +extern int getc(FILE *__stream); + +/* getchar() function implementation, required by standard */ +extern int getchar(void); + +#endif /* not __DOXYGEN__ */ + +/** + The macro \c getc used to be a "fast" macro implementation with a + functionality identical to fgetc(). For space constraints, in + \c avr-libc, it is just an alias for \c fgetc. +*/ +#define getc(__stream) fgetc(__stream) + +/** + The macro \c getchar reads a character from \c stdin. Return + values and error handling is identical to fgetc(). +*/ +#define getchar() fgetc(stdin) + +/** + The ungetc() function pushes the character \c c (converted to an + unsigned char) back onto the input stream pointed to by \c stream. + The pushed-back character will be returned by a subsequent read on + the stream. + + Currently, only a single character can be pushed back onto the + stream. + + The ungetc() function returns the character pushed back after the + conversion, or \c EOF if the operation fails. If the value of the + argument \c c character equals \c EOF, the operation will fail and + the stream will remain unchanged. +*/ +extern int ungetc(int __c, FILE *__stream); + +/** + Read at most size - 1 bytes from \c stream, until a + newline character was encountered, and store the characters in the + buffer pointed to by \c str. Unless an error was encountered while + reading, the string will then be terminated with a \c NUL + character. + + If an error was encountered, the function returns NULL and sets the + error flag of \c stream, which can be tested using ferror(). + Otherwise, a pointer to the string will be returned. */ +extern char *fgets(char *__str, int __size, FILE *__stream); + +/** + Similar to fgets() except that it will operate on stream \c stdin, + and the trailing newline (if any) will not be stored in the string. + It is the caller's responsibility to provide enough storage to hold + the characters read. */ +extern char *gets(char *__str); + +/** + Read \c nmemb objects, \c size bytes each, from \c stream, + to the buffer pointed to by \c ptr. + + Returns the number of objects successfully read, i. e. + \c nmemb unless an input error occured or end-of-file was + encountered. feof() and ferror() must be used to distinguish + between these two conditions. + */ +extern size_t fread(void *__ptr, size_t __size, size_t __nmemb, + FILE *__stream); + +/** + Clear the error and end-of-file flags of \c stream. + */ +extern void clearerr(FILE *__stream); + +#if !defined(__DOXYGEN__) +/* fast inlined version of clearerr() */ +#define clearerror(s) do { (s)->flags &= ~(__SERR | __SEOF); } while(0) +#endif /* !defined(__DOXYGEN__) */ + +/** + Test the end-of-file flag of \c stream. This flag can only be cleared + by a call to clearerr(). + */ +extern int feof(FILE *__stream); + +#if !defined(__DOXYGEN__) +/* fast inlined version of feof() */ +#define feof(s) ((s)->flags & __SEOF) +#endif /* !defined(__DOXYGEN__) */ + +/** + Test the error flag of \c stream. This flag can only be cleared + by a call to clearerr(). + */ +extern int ferror(FILE *__stream); + +#if !defined(__DOXYGEN__) +/* fast inlined version of ferror() */ +#define ferror(s) ((s)->flags & __SERR) +#endif /* !defined(__DOXYGEN__) */ + +/** + Formatted input. This function is the heart of the \c scanf + family of functions. + + Characters are read from \c stream and processed in a way + described by \c fmt. Conversion results will be assigned to the + parameters passed via \c ap. + + The format string \c fmt is scanned for conversion specifications. + Anything that doesn't comprise a conversion specification is taken + as text that is matched literally against the input. White space + in the format string will match any white space in the data + (including none), all other characters match only itself. + Processing is aborted as soon as the data and format string no + longer match, or there is an error or end-of-file condition on + \c stream. + + Most conversions skip leading white space before starting the + actual conversion. + + Conversions are introduced with the character \b %. Possible + options can follow the \b %: + + - a \c * indicating that the conversion should be performed but + the conversion result is to be discarded; no parameters will + be processed from \c ap, + - the character \c h indicating that the argument is a pointer + to short int (rather than int), + - the character \c l indicating that the argument is a pointer + to long int (rather than int, for integer + type conversions), or a pointer to \c double (for floating + point conversions). + + In addition, a maximal field width may be specified as a nonzero + positive decimal integer, which will restrict the conversion to at + most this many characters from the input stream. This field width + is limited to at most 127 characters which is also the default + value (except for the %c conversion that defaults to 1). + + The following conversion flags are supported: + + - \c % Matches a literal \c % character. This is not a conversion. + - \c d Matches an optionally signed decimal integer; the next + pointer must be a pointer to \c int. + - \c i Matches an optionally signed integer; the next pointer must + be a pointer to \c int. The integer is read in base 16 if it + begins with \b 0x or \b 0X, in base 8 if it begins with \b 0, and + in base 10 otherwise. Only characters that correspond to the + base are used. + - \c o Matches an octal integer; the next pointer must be a pointer to + unsigned int. + - \c u Matches an optionally signed decimal integer; the next + pointer must be a pointer to unsigned int. + - \c x Matches an optionally signed hexadecimal integer; the next + pointer must be a pointer to unsigned int. + - \c f Matches an optionally signed floating-point number; the next + pointer must be a pointer to \c float. + - e, g, E, G Equivalent to \c f. + - \c s + Matches a sequence of non-white-space characters; the next pointer + must be a pointer to \c char, and the array must be large enough to + accept all the sequence and the terminating \c NUL character. The + input string stops at white space or at the maximum field width, + whichever occurs first. + - \c c + Matches a sequence of width count characters (default 1); the next + pointer must be a pointer to \c char, and there must be enough room + for all the characters (no terminating \c NUL is added). The usual + skip of leading white space is suppressed. To skip white space + first, use an explicit space in the format. + - \c [ + Matches a nonempty sequence of characters from the specified set + of accepted characters; the next pointer must be a pointer to \c + char, and there must be enough room for all the characters in the + string, plus a terminating \c NUL character. The usual skip of + leading white space is suppressed. The string is to be made up + of characters in (or not in) a particular set; the set is defined + by the characters between the open bracket \c [ character and a + close bracket \c ] character. The set excludes those characters + if the first character after the open bracket is a circumflex + \c ^. To include a close bracket in the set, make it the first + character after the open bracket or the circumflex; any other + position will end the set. The hyphen character \c - is also + special; when placed between two other characters, it adds all + intervening characters to the set. To include a hyphen, make it + the last character before the final close bracket. For instance, + [^]0-9-] means the set of everything except close + bracket, zero through nine, and hyphen. The string ends + with the appearance of a character not in the (or, with a + circumflex, in) set or when the field width runs out. + - \c p + Matches a pointer value (as printed by %p in printf()); the + next pointer must be a pointer to \c void. + - \c n + Nothing is expected; instead, the number of characters consumed + thus far from the input is stored through the next pointer, which + must be a pointer to \c int. This is not a conversion, although it + can be suppressed with the \c * flag. + + These functions return the number of input items assigned, which + can be fewer than provided for, or even zero, in the event of a + matching failure. Zero indicates that, while there was input + available, no conversions were assigned; typically this is due + to an invalid input character, such as an alphabetic character + for a %d conversion. The value \c EOF is returned if an input + failure occurs before any conversion such as an end-of-file + occurs. If an error or end-of-file occurs after conversion has + begun, the number of conversions which were successfully + completed is returned. + + By default, all the conversions described above are available + except the floating-point conversions, and the \%[ conversion. + These conversions will be available in the extended version + provided by the library \c libscanf_flt.a. Note that either of + these conversions requires the availability of a buffer that + needs to be obtained at run-time using malloc(). If this buffer + cannot be obtained, the operation is aborted, returning the + value \c EOF. To link a program against the extended version, + use the following compiler flags in the link stage: + + \code + -Wl,-u,vfscanf -lscanf_flt -lm + \endcode + + A third version is available for environments that are tight + on space. This version is provided in the library + \c libscanf_min.a, and can be requested using the following + options in the link stage: + + \code + -Wl,-u,vfscanf -lscanf_min -lm + \endcode + + In addition to the restrictions of the standard version, this + version implements no field width specification, no conversion + assignment suppression flag (\c *), no %n specification, and + no general format character matching at all. All characters in + \c fmt that do not comprise a conversion specification will + simply be ignored, including white space (that is normally used + to consume \e any amount of white space in the input stream). + However, the usual skip of initial white space in the formats + that support it is implemented. +*/ +extern int vfscanf(FILE *__stream, const char *__fmt, va_list __ap); + +/** + Variant of vfscanf() using a \c fmt string in program memory. + */ +extern int vfscanf_P(FILE *__stream, const char *__fmt, va_list __ap); + +/** + The function \c fscanf performs formatted input, reading the + input data from \c stream. + + See vfscanf() for details. + */ +extern int fscanf(FILE *__stream, const char *__fmt, ...); + +/** + Variant of fscanf() using a \c fmt string in program memory. + */ +extern int fscanf_P(FILE *__stream, const char *__fmt, ...); + +/** + The function \c scanf performs formatted input from stream \c stdin. + + See vfscanf() for details. + */ +extern int scanf(const char *__fmt, ...); + +/** + Variant of scanf() where \c fmt resides in program memory. + */ +extern int scanf_P(const char *__fmt, ...); + +/** + The function \c vscanf performs formatted input from stream + \c stdin, taking a variable argument list as in vfscanf(). + + See vfscanf() for details. +*/ +extern int vscanf(const char *__fmt, va_list __ap); + +/** + The function \c sscanf performs formatted input, reading the + input data from the buffer pointed to by \c buf. + + See vfscanf() for details. + */ +extern int sscanf(const char *__buf, const char *__fmt, ...); + +/** + Variant of sscanf() using a \c fmt string in program memory. + */ +extern int sscanf_P(const char *__buf, const char *__fmt, ...); + +#if defined(__DOXYGEN__) +/** + Flush \c stream. + + This is a null operation provided for source-code compatibility + only, as the standard IO implementation currently does not perform + any buffering. + */ +extern int fflush(FILE *stream); +#else +static __inline__ int fflush(FILE *stream __attribute__((unused))) +{ + return 0; +} +#endif + +#ifdef __cplusplus +} +#endif + +/*@}*/ + +/* + * The following constants are currently not used by avr-libc's + * stdio subsystem. They are defined here since the gcc build + * environment expects them to be here. + */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#endif /* __ASSEMBLER */ + +#endif /* _STDLIB_H_ */ diff --git a/tos/lib/printf/2_0_2/printf.h b/tos/lib/printf/2_0_2/printf.h new file mode 100644 index 00000000..fcaee280 --- /dev/null +++ b/tos/lib/printf/2_0_2/printf.h @@ -0,0 +1,54 @@ +/* + * "Copyright (c) 2006 Washington University in St. Louis. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL WASHINGTON UNIVERSITY IN ST. LOUIS BE LIABLE TO ANY PARTY + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING + * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF WASHINGTON + * UNIVERSITY IN ST. LOUIS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * WASHINGTON UNIVERSITY IN ST. LOUIS SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND WASHINGTON UNIVERSITY IN ST. LOUIS HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + * MODIFICATIONS." + */ + +/** + * + * @author Kevin Klues (klueska@cs.wustl.edu) + * @version $Revision$ + * @date $Date$ + */ + +#ifndef PRINTF_H +#define PRINTF_H + +#ifndef PRINTF_BUFFER_SIZE +#define PRINTF_BUFFER_SIZE 250 +#endif + +#ifdef _H_msp430hardware_h + #include +#endif +#ifdef _H_atmega128hardware_H + #include "avr_stdio.h" +#endif +#include "message.h" + +typedef nx_struct printf_msg { + nx_uint8_t buffer[TOSH_DATA_LENGTH]; +} printf_msg_t; + +enum { + AM_PRINTF_MSG = 100, +}; + +#endif //PRINTF_H + diff --git a/tos/lib/printf/MainC.nc b/tos/lib/printf/MainC.nc new file mode 100644 index 00000000..7c805fe8 --- /dev/null +++ b/tos/lib/printf/MainC.nc @@ -0,0 +1,61 @@ +// $Id$ + +/* tab:4 + * "Copyright (c) 2000-2003 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." + * + * Copyright (c) 2002-2003 Intel Corporation + * All rights reserved. + * + * This file is distributed under the terms in the attached INTEL-LICENSE + * file. If you do not find these files, copies can be found by writing to + * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, + * 94704. Attention: Intel License Inquiry. + * + * Date last modified: $Id$ + */ + +/** + * MainC is the system interface the TinyOS boot sequence. It wires the + * boot sequence implementation to the scheduler and hardware resources. + * + * @author Philip Levis + * @author Kevin Klues + * @date August 6 2005 + */ + +#include "hardware.h" + +configuration MainC { + provides interface Boot; + uses interface Init as SoftwareInit; +} +implementation { + components PlatformC, RealMainP, TinySchedulerC; + components PrintfC; + + RealMainP.Scheduler -> TinySchedulerC; + RealMainP.PlatformInit -> PlatformC; + PrintfC.MainBoot -> RealMainP; + + // Export the SoftwareInit and Booted for applications + SoftwareInit = RealMainP.SoftwareInit; + Boot = PrintfC; +} + diff --git a/tos/lib/printf/PrintfC.nc b/tos/lib/printf/PrintfC.nc index a9a8b738..94dc3d52 100644 --- a/tos/lib/printf/PrintfC.nc +++ b/tos/lib/printf/PrintfC.nc @@ -38,25 +38,29 @@ * @version $Revision$ * @date $Date$ */ - #include "printf.h" configuration PrintfC { provides { - interface SplitControl as PrintfControl; - interface PrintfFlush; + interface Boot; } + uses interface Boot as MainBoot @exactlyonce(); } implementation { components SerialActiveMessageC; components new SerialAMSenderC(AM_PRINTF_MSG); - components PrintfP; + components new PrintfQueueC(uint8_t, PRINTF_BUFFER_SIZE) as QueueC; - PrintfControl = PrintfP; - PrintfFlush = PrintfP; + components PrintfP; + components LedsC; + + MainBoot = PrintfP.MainBoot; + Boot = PrintfP.Boot; PrintfP.SerialControl -> SerialActiveMessageC; + PrintfP.Queue -> QueueC; PrintfP.AMSend -> SerialAMSenderC; PrintfP.Packet -> SerialAMSenderC; + PrintfP.Leds -> LedsC; } diff --git a/tos/lib/printf/PrintfP.nc b/tos/lib/printf/PrintfP.nc index 5f4ae231..78595a8d 100644 --- a/tos/lib/printf/PrintfP.nc +++ b/tos/lib/printf/PrintfP.nc @@ -19,6 +19,37 @@ * 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 @@ -38,10 +69,11 @@ * (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$ + */ + +/** + * @author Kevin Klues + * @date September 18, 2007 */ #include "printf.h" @@ -53,95 +85,68 @@ static FILE atm128_stdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WR module PrintfP { provides { - interface SplitControl as PrintfControl; - interface PrintfFlush; + interface Boot; } uses { + interface Boot as MainBoot; interface SplitControl as SerialControl; + interface PrintfQueue as Queue; + interface AMSend; interface Packet; + interface Leds; } } implementation { enum { - S_STARTED, 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; - uint32_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, sizeof(printf_msg_t)); - length_to_send = (bytes_left_to_flush < sizeof(printf_msg_t)) ? bytes_left_to_flush : sizeof(printf_msg_t); - memset(m->buffer, 0, sizeof(printf_msg_t)); - memcpy(m->buffer, (nx_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; - } #ifdef _H_atmega128hardware_H 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; - } - signal PrintfControl.startDone(error); + atomic state = S_STARTED; + signal Boot.booted(); } 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() { + 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; ibuffer[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_STARTED && (next_byte > buffer)) { - state = S_FLUSHING; - bytes_left_to_flush = next_byte - buffer; - next_byte = buffer; - } - else return FAIL; + if(state == S_FLUSHING) + return SUCCESS; + if(call Queue.empty()) + return FAIL; + state = S_FLUSHING; } sendNext(); return SUCCESS; @@ -149,17 +154,11 @@ implementation { event void AMSend.sendDone(message_t* msg, error_t error) { if(error == SUCCESS) { - if(bytes_left_to_flush > 0) + if(call Queue.size() > 0) sendNext(); - else { - next_byte = buffer; - bytes_left_to_flush = 0; - length_to_send = 0; - atomic state = S_STARTED; - signal PrintfFlush.flushDone(error); + else state = S_STARTED; } - } - else post retrySend(); + else post retrySend(); } #ifdef _H_msp430hardware_h @@ -168,11 +167,13 @@ implementation { #ifdef _H_atmega128hardware_H int uart_putchar(char c, FILE *stream) __attribute__((noinline)) @C() @spontaneous() { #endif + if((state == S_STARTED) && (call Queue.size() >= 5*sizeof(printf_msg_t))) { + state = S_FLUSHING; + sendNext(); + } atomic { - if(state == S_STARTED && ((next_byte-buffer) < PRINTF_BUFFER_SIZE)) { - *(next_byte++) = c; + if(call Queue.enqueue(c) == SUCCESS) return 0; - } else return -1; } } diff --git a/tos/lib/printf/printf.h b/tos/lib/printf/printf.h index fcaee280..835e40e0 100644 --- a/tos/lib/printf/printf.h +++ b/tos/lib/printf/printf.h @@ -31,7 +31,15 @@ #define PRINTF_H #ifndef PRINTF_BUFFER_SIZE -#define PRINTF_BUFFER_SIZE 250 +#define PRINTF_BUFFER_SIZE 250 +#endif + +#if PRINTF_BUFFER_SIZE > 255 + #define PrintfQueueC BigQueueC + #define PrintfQueue BigQueue +#else + #define PrintfQueueC QueueC + #define PrintfQueue Queue #endif #ifdef _H_msp430hardware_h