diff --git a/README.md b/README.md index fdcac2b6..a68754e5 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ void setup() { } ``` -## Using cin an cout -When you include this header file you automatically get cin and cout based on Serial. There isn't yet a way to select you own device at runtime. Using cin and cout is +## Using ```cin``` an ```cout``` +When you include this header file you automatically get cin and cout based on ```Serial```. See below for how to specify your own device. Here's an example sketch using ```cin``` and ```cout``` . ```c++ #include @@ -47,10 +47,40 @@ void loop() { } } ``` +## Changing the Serial Port +You can change what serial port that ```cin```, ```cout``` and ```printf()``` use. You can use built-in serial ports (e.g. ```Serial1``` on Leonardo) or you can use software serial ports that implement ```Stream```. + +### Using a Built-in Port +In ```src/ArduinoSTL.cpp``` change the value of ```ARDUINOSTL_DEFAULT_SERIAL```. Leave the other defaults uncommented. + +### Using a SoftwareSerial port. +Set ```ARDUINO_DEFAULT_SERAL``` to ```NULL```. Comment out the other defaults. + +Here's an example sketch that uses SofwareSerial: + +```c++ +#include +#include + +SoftwareSerial mySerial(0, 1); + +namespace std { + ohserialstream cout(mySerial); + ihserialstream cin(mySerial); +} + +void setup() { + mySerial.begin(9600); + ArduinoSTL_Serial.connect(mySerial); +} +``` + +## Avoiding Instantiation of ```cin``` and ```cout``` +Comment out ```ARDUINOSTL_DEFAULT_CIN_COUT``` and nothing will be instantiated. You must comment out this flag if you intend to select a non-default serial port. There's no appreciable overhead for using ```printf()``` so you cannot currently avoid initializaing it. ## Known Issues -Printing of floats and doubles using cout ignores format specifiers. +Printing of floats and doubles using ```cout``` ignores format specifiers. uClibc seems to be fairly complete. Strings and vectors both work, even with the limited amount of heap available to Arduino. The uClibc++ status page can be found here: diff --git a/library.properties b/library.properties index e392dbb9..464d0ce3 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=ArduinoSTL -version=1.0.5 +version=1.1.0 author=Mike Matera maintainer=Mike Matera sentence=A port of uClibc++ packaged as an Arduino library. -paragraph=This library includes important C++ functions, including cout and cin, printf and scanf. It also includes STL containers like vector and algorithms. +paragraph=This library includes important C++ functions, including cout and cin, printf and scanf. It also includes STL containers like vector and algorithm. category=Other url=https://github.com/mike-matera/ArduinoSTL architectures=avr,samd diff --git a/src/ArduinoSTL.cpp b/src/ArduinoSTL.cpp index 20612bcb..6d321070 100644 --- a/src/ArduinoSTL.cpp +++ b/src/ArduinoSTL.cpp @@ -1,15 +1,35 @@ #include #include +// +// Configuration Help +// +// If you're using a serial port that's statically declared somewhere in +// Arduino (e.g. Serial1 on Leonardo) +// 1. Set ARDUINOSTL_SERIAL_DEVICE to your device +// 2. Uncomment the ARDUINOSTL_DEFAULT_CIN_COUT flag. +// +// If you're using a sofware serial port: +// 1. Set ARDUINOSTL_DEFAULT_SERIAL to NULL +// 2. Comment out ARDUINOSTL_DEFAULT_CIN_COUT +// Your sketch must contain delarations of cin and cout, and a call to +// ArduinoSTL_serial.connect(). +// + +#define ARDUINOSTL_DEFAULT_SERIAL Serial +#define ARDUINOSTL_DEFAULT_CIN_COUT + using namespace std; +#ifdef ARDUINOSTL_DEFAULT_CIN_COUT // Create cout and cin.. there doesn't seem to be a way // to control what serial device at runtime. Grr. namespace std { - ohserialstream cout(Serial); - ihserialstream cin(Serial); + ohserialstream cout(ARDUINOSTL_DEFAULT_SERIAL); + ihserialstream cin(ARDUINOSTL_DEFAULT_SERIAL); } +#endif // ARDUINOSTL_DEFAULT_CIN_COUT /* * Implementation of printf() is highly libc dependent. @@ -21,22 +41,8 @@ namespace std * ARDUINO_ARCH_* - ARMs are probably the same as above. */ #if defined(ARDUINO_ARCH_AVR) -// -// This is a hack to make C stdio work on "Serial" without -// having to be manually initialized. It works becuase I can -// call a constructor before setup(). -// -class __Arduino_STDIO_hack { -public: - __Arduino_STDIO_hack(Stream *u); - Stream *getUart() { - return uart; - } -private: - Stream *uart; -}; -static __Arduino_STDIO_hack __stdio_wrapper(&Serial); +ArduinoSTL_STDIO ArduinoSTL_Serial(ARDUINOSTL_DEFAULT_SERIAL); // arduino_putchar(char, FILE*) // Output a single character to the serial port. @@ -46,7 +52,7 @@ static __Arduino_STDIO_hack __stdio_wrapper(&Serial); // automatically addes a \r when it sees a \n // static int arduino_putchar(char c, FILE* f) { - Stream *uart = __stdio_wrapper.getUart(); + Stream *uart = ArduinoSTL_Serial.getUart(); if (c == '\n') uart->write('\r'); return uart->write(c) == 1? 0 : 1; } @@ -57,18 +63,18 @@ static int arduino_putchar(char c, FILE* f) { // returns: The character or -1 on a read error // static int arduino_getchar(FILE *f) { - Stream *uart = __stdio_wrapper.getUart(); + Stream *uart = ArduinoSTL_Serial.getUart(); while (! uart->available()) { /* wait */ } return uart->read(); } -// Initialize STDIO using a pointer to whatever Serial is. -// Serial.begin() must be called at some point. -// -__Arduino_STDIO_hack::__Arduino_STDIO_hack(Stream *u) { +void ArduinoSTL_STDIO::connect(Stream *u) { + if (file != NULL) + free (file); uart = u; - fdevopen(arduino_putchar, arduino_getchar); + file = fdevopen(arduino_putchar, arduino_getchar); } + #else #warning "printf() will not be functional on this platform." #endif diff --git a/src/ArduinoSTL.h b/src/ArduinoSTL.h index db4a1b9a..3fb432f8 100644 --- a/src/ArduinoSTL.h +++ b/src/ArduinoSTL.h @@ -19,4 +19,37 @@ namespace std extern ihserialstream cin; } -#endif +#if defined(ARDUINO_ARCH_AVR) + +class ArduinoSTL_STDIO { +public: + // Initialize STDIO using a pointer to whatever Serial is. + // Serial.begin() must be called at some point. + ArduinoSTL_STDIO(Stream *u) : file(NULL) { + connect(u); + } + + ArduinoSTL_STDIO(Stream &u) : file(NULL) { + connect(u); + } + + Stream *getUart() { + return uart; + } + + void connect(Stream *u); + + inline void connect(Stream &u) { + connect(static_cast(&u)); + } + +private: + Stream *uart; + FILE *file; +}; + +extern ArduinoSTL_STDIO ArduinoSTL_Serial; + +#endif // ARDUINO_ARCH_AVR + +#endif // ARDUINOSTL_M_H