diff --git a/examples/arduino_uno/basic/read_analog_voltage/project.xml b/examples/arduino_uno/basic/read_analog_voltage/project.xml
index 9da9af1055..c43285ab08 100644
--- a/examples/arduino_uno/basic/read_analog_voltage/project.xml
+++ b/examples/arduino_uno/basic/read_analog_voltage/project.xml
@@ -2,6 +2,7 @@
modm:arduino-uno
+
modm:platform:adc
diff --git a/examples/avr/block_device_mirror/project.xml b/examples/avr/block_device_mirror/project.xml
index b4b432f583..f83a2b8abc 100644
--- a/examples/avr/block_device_mirror/project.xml
+++ b/examples/avr/block_device_mirror/project.xml
@@ -3,6 +3,7 @@
+
modm:debug
diff --git a/examples/avr/can/mcp2515/project.xml b/examples/avr/can/mcp2515/project.xml
index 0c4bbafe63..b8763c8eb9 100644
--- a/examples/avr/can/mcp2515/project.xml
+++ b/examples/avr/can/mcp2515/project.xml
@@ -3,6 +3,7 @@
+
modm:driver:mcp2515
diff --git a/examples/avr/can/mcp2515_uart/project.xml b/examples/avr/can/mcp2515_uart/project.xml
index 0e42b1af09..1ac9a5bc65 100644
--- a/examples/avr/can/mcp2515_uart/project.xml
+++ b/examples/avr/can/mcp2515_uart/project.xml
@@ -3,6 +3,7 @@
+
modm:architecture:interrupt
diff --git a/examples/avr/xpcc/receiver/project.xml b/examples/avr/xpcc/receiver/project.xml
index 58d8921185..21c391b0a0 100644
--- a/examples/avr/xpcc/receiver/project.xml
+++ b/examples/avr/xpcc/receiver/project.xml
@@ -5,6 +5,8 @@
+
+
modm:communication:xpcc:generator
diff --git a/examples/avr/xpcc/sender/project.xml b/examples/avr/xpcc/sender/project.xml
index 98ebd973fc..95bc99b025 100644
--- a/examples/avr/xpcc/sender/project.xml
+++ b/examples/avr/xpcc/sender/project.xml
@@ -5,6 +5,8 @@
+
+
modm:communication:xpcc:generator
diff --git a/src/modm/architecture/interface/accessor_flash.hpp b/src/modm/architecture/interface/accessor_flash.hpp
index ab598d83ed..ca11ca6eb3 100644
--- a/src/modm/architecture/interface/accessor_flash.hpp
+++ b/src/modm/architecture/interface/accessor_flash.hpp
@@ -37,7 +37,7 @@
/// Declare a flash string inline
/// @ingroup modm_architecture_accessor
-#define PSTR(s) ((const char *)(s))
+#define IFSS(s) ((const char *)(s))
#else // !__DOXYGEN__
diff --git a/src/modm/io/iostream.cpp b/src/modm/io/iostream.cpp
index 505601c4cc..b55bc253e4 100644
--- a/src/modm/io/iostream.cpp
+++ b/src/modm/io/iostream.cpp
@@ -2,7 +2,7 @@
* Copyright (c) 2009-2010, Martin Rosekeit
* Copyright (c) 2009-2012, Fabian Greif
* Copyright (c) 2011, Georgi Grinshpun
- * Copyright (c) 2012-2014, Niklas Hauser
+ * Copyright (c) 2012-2014, 2019 Niklas Hauser
* Copyright (c) 2016, Sascha Schade
*
* This file is part of the modm project.
@@ -13,256 +13,129 @@
*/
// ----------------------------------------------------------------------------
-#include
-
-#include
-#include
-
#include "iostream.hpp"
+#include
-FLASH_STORAGE(uint16_t base[]) = { 10, 100, 1000, 10000 };
-
-// ----------------------------------------------------------------------------
-modm::IOStream::IOStream(IODevice& outputDevice) :
- device(&outputDevice),
- mode(Mode::Ascii)
+namespace modm
{
-}
-// ----------------------------------------------------------------------------
-void
-modm::IOStream::writeInteger(int16_t value)
+IOStream&
+IOStream::get(char* s, size_t n)
{
- if (value < 0) {
- this->device->write('-');
- this->writeInteger(static_cast(-value));
- }
- else{
- this->writeInteger(static_cast(value));
+ if(n < 1) {
+ return *this;
}
-}
-
-void
-modm::IOStream::writeInteger(uint16_t value)
-{
- accessor::Flash basePtr = modm::accessor::asFlash(base);
-
- bool zero = true;
- uint8_t i = 4;
- do {
- i--;
- char d;
- for (d = static_cast('0'); value >= basePtr[i]; value -= basePtr[i])
- {
- d++;
- zero = false;
- }
- if (!zero) {
- this->device->write(d);
+ char cc;
+ size_t ii;
+ for(ii = 0; ii < (n-1); ++ii) {
+ if(device->read(cc)) {
+ s[ii] = cc;
+ } else {
+ break;
}
- } while (i);
-
- this->device->write(static_cast(value) + '0');
-}
-
-void
-modm::IOStream::writeInteger(int32_t value)
-{
-#if defined(MODM_CPU_AVR)
- char buffer[ArithmeticTraits::decimalDigits + 1]; // +1 for '\0'
-
- // Uses the optimized non standard function 'ltoa()' which is
- // not always available.
-
- this->device->write(ltoa(value, buffer, 10));
-#else
- if (value < 0) {
- this->device->write('-');
- this->writeInteger(static_cast(-value));
- }
- else{
- this->writeInteger(static_cast(value));
- }
-#endif
-}
-
-void
-modm::IOStream::writeInteger(uint32_t value)
-{
-#if defined(MODM_CPU_AVR)
- char buffer[ArithmeticTraits::decimalDigits + 1]; // +1 for '\0'
-
- // Uses the optimized non standard function 'ultoa()' which is
- // not always available.
- this->device->write(ultoa(value, buffer, 10));
-#else
- char buffer[ArithmeticTraits::decimalDigits + 1]; // +1 for '\0'
-
- // ptr points to the end of the string, it will be filled backwards
- char *ptr = buffer + ArithmeticTraits::decimalDigits;
-
- *ptr = '\0';
-
- // calculate the string backwards
- do{
- uint32_t quot = value / 10;
- uint8_t rem = value - quot*10;
- *(--ptr) = static_cast(rem) + '0';
- value = quot;
- }while (value != 0);
-
- // write string
- this->device->write(ptr);
-#endif
-}
-
-#ifndef MODM_CPU_AVR
-void
-modm::IOStream::writeInteger(int64_t value)
-{
- if (value < 0) {
- this->device->write('-');
- this->writeInteger(static_cast(-value));
}
- else{
- this->writeInteger(static_cast(value));
- }
-}
-
-void
-modm::IOStream::writeInteger(uint64_t value)
-{
- char buffer[ArithmeticTraits::decimalDigits + 1]; // +1 for '\0'
-
- // ptr points to the end of the string, it will be filled backwards
- char *ptr = buffer + ArithmeticTraits::decimalDigits;
-
- *ptr = '\0';
-
- // calculate the string backwards
- do{
- uint64_t quot = value / 10;
- uint8_t rem = value - quot*10;
- *(--ptr) = static_cast(rem) + '0';
- value = quot;
- }while (value != 0);
-
- // write string
- this->device->write(ptr);
+ s[ii] = '\0';
+ return *this;
}
-#endif
// ----------------------------------------------------------------------------
-void
-modm::IOStream::writeHex(const char* s)
-{
- while (*s != '\0') {
- this->writeHex(*s);
- s++;
- }
-}
-
-void
-modm::IOStream::writeBin(const char* s)
+IOStream&
+IOStream::operator << (const bool& v)
{
- while (*s != '\0') {
- this->writeBin(*s);
- s++;
+ switch (mode)
+ {
+ case Mode::Ascii:
+ *this << (v ? IFSS("true") : IFSS("false"));
+ break;
+ case Mode::Hexadecimal:
+ device->write('0');
+ // fallthrough
+ case Mode::Binary:
+ device->write(v ? '1' : '0');
+ break;
}
+ return *this;
}
// ----------------------------------------------------------------------------
void
-modm::IOStream::writeHexNibble(uint8_t nibble)
+IOStream::writeHex(uint8_t value)
{
- char character;
- if (nibble > 9) {
- character = nibble + 'A' - 10;
- }
- else {
- character = nibble + '0';
- }
- this->device->write(character);
+ const auto fn_nibble = [this](uint8_t nibble)
+ {
+ device->write( nibble + (nibble > 9 ? 'A' - 10 : '0') );
+ };
+ fn_nibble(value >> 4);
+ fn_nibble(value & 0xF);
}
// ----------------------------------------------------------------------------
void
-modm::IOStream::writeHex(uint8_t value)
-{
- writeHexNibble(value >> 4);
- writeHexNibble(value & 0xF);
-}
-
-void
-modm::IOStream::writeBin(uint8_t value)
+IOStream::writeBin(uint8_t value)
{
for (uint_fast8_t ii = 0; ii < 8; ii++)
{
- if (value & 0x80) {
- this->device->write('1');
- }
- else {
- this->device->write('0');
- }
+ device->write(value & 0x80 ? '1' : '0');
value <<= 1;
}
-
}
// ----------------------------------------------------------------------------
-modm::IOStream&
-modm::IOStream::operator << (const myfunc& value)
+void
+IOStream::writePointer(const void* p)
{
- unsigned char *p = (unsigned char *)&value;
-
- for (std::size_t i = 0; i < sizeof(myfunc); i++)
- {
- writeHex(p[sizeof(myfunc) - i - 1]);
- }
- return *this;
-}
+ device->write('0');
+ device->write('x');
+ const uintptr_t value = reinterpret_cast(p);
-modm::IOStream&
-modm::IOStream::operator << (const void* p)
-{
#if MODM_SIZEOF_POINTER == 2
- this->device->write('0');
- this->device->write('x');
-
- uint16_t value = reinterpret_cast(p);
-
writeHex(value >> 8);
writeHex(value);
#elif MODM_SIZEOF_POINTER == 4
- this->device->write('0');
- this->device->write('x');
+ for (uint8_t ii=24; ii < 32; ii -= 8)
+ writeHex(value >> ii);
- uint32_t value = reinterpret_cast(p);
+#elif MODM_SIZEOF_POINTER == 8
- writeHex(value >> 24);
- writeHex(value >> 16);
- writeHex(value >> 8);
- writeHex(value);
+ for (uint8_t ii=56; ii < 64; ii -= 8)
+ writeHex(value >> ii);
-#elif MODM_SIZEOF_POINTER == 8
+#endif
+}
- this->device->write('0');
- this->device->write('x');
+IOStream&
+black(IOStream& ios)
+{ return ios << IFSS("\033[30m"); }
- uint64_t value = reinterpret_cast(p);
+IOStream&
+red(IOStream& ios)
+{ return ios << IFSS("\033[31m"); }
- writeHex(value >> 56);
- writeHex(value >> 48);
- writeHex(value >> 40);
- writeHex(value >> 32);
- writeHex(value >> 24);
- writeHex(value >> 16);
- writeHex(value >> 8);
- writeHex(value);
+IOStream&
+green(IOStream& ios)
+{ return ios << IFSS("\033[32m"); }
-#endif
- return *this;
-}
+IOStream&
+yellow(IOStream& ios)
+{ return ios << IFSS("\033[33m"); }
+
+IOStream&
+blue(IOStream& ios)
+{ return ios << IFSS("\033[34m"); }
+
+IOStream&
+magenta(IOStream& ios)
+{ return ios << IFSS("\033[35m"); }
+
+IOStream&
+cyan(IOStream& ios)
+{ return ios << IFSS("\033[36m"); }
+
+IOStream&
+white(IOStream& ios)
+{ return ios << IFSS("\033[37m"); }
+
+} // namespace modm
diff --git a/src/modm/io/iostream.hpp b/src/modm/io/iostream.hpp
deleted file mode 100644
index 582bfe47e5..0000000000
--- a/src/modm/io/iostream.hpp
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright (c) 2009-2010, Martin Rosekeit
- * Copyright (c) 2009-2012, Fabian Greif
- * Copyright (c) 2011, Georgi Grinshpun
- * Copyright (c) 2011-2017, Niklas Hauser
- * Copyright (c) 2012, 2015-2016, Sascha Schade
- * Copyright (c) 2015-2016, Kevin Läufer
- * Copyright (c) 2017, Marten Junga
- *
- * This file is part of the modm project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-// ----------------------------------------------------------------------------
-
-#ifndef MODM_IOSTREAM_HPP
-#define MODM_IOSTREAM_HPP
-
-#include
-
-#include
-#include
-
-#include // va_list
-
-#include "iodevice.hpp"
-#include "iodevice_wrapper.hpp"
-
-namespace modm
-{
-
-/**
- * This formats all primary types into a string stream for
- * output or it reads values from a input and converts them to
- * a given type;
- *
- * @ingroup modm_io
- * @author Martin Rosekeit
- */
-class IOStream
-{
-public:
- /**
- * @param device device to write the stream to
- *
- * @code
- * MyIODevice device;
- * IOStream stream( device );
- * @endcode
- */
- IOStream(IODevice& device);
-
- inline IOStream&
- write(char c)
- {
- this->device->write(c);
- return *this;
- }
-
- static constexpr char eof = -1;
-
- /// Reads one character and returns it if available. Otherwise, returns IOStream::eof.
- inline IOStream&
- get(char& c)
- {
- if(!this->device->read(c)) {
- c = IOStream::eof;
- }
- return *this;
- }
-
- /// reads characters into NULL delimited c string
- /// in contrast to the standard implementation, this does not care about
- /// newline characters in the input
- inline IOStream&
- get(char* s, size_t n)
- {
- if(n < 1) {
- return *this;
- }
- char cc;
- size_t ii;
- for(ii = 0; ii < (n-1); ++ii) {
- if(this->device->read(cc)) {
- s[ii] = cc;
- } else {
- break;
- }
- }
- s[ii] = '\0';
- return *this;
- }
-
- template
- inline IOStream&
- get(char (&s)[N])
- {
- return this->get(s, N);
- }
-
-
-
- inline IOStream&
- flush()
- {
- this->device->flush();
- this->mode = Mode::Ascii;
- return *this;
- }
-
- /// set the output mode to binary style for `char` and `char*`
- modm_always_inline IOStream&
- bin()
- {
- this->mode = Mode::Binary;
- return *this;
- }
-
- /// set the output mode to hexadecimal style for `char` and `char*`
- modm_always_inline IOStream&
- hex()
- {
- this->mode = Mode::Hexadecimal;
- return *this;
- }
-
- /// set the output mode to ASCII style for `char` and `char*`
- modm_always_inline IOStream&
- ascii()
- {
- this->mode = Mode::Ascii;
- return *this;
- }
-
-
- IOStream&
- operator << (const unsigned char& v)
- {
- if (this->mode == Mode::Ascii) {
- this->writeInteger(static_cast(v));
- }
- else if (this->mode == Mode::Binary) {
- this->writeBin(v);
- }
- else {
- this->writeHex(v);
- }
- return *this;
- }
-
- IOStream&
- operator << (const bool& v)
- {
- switch (this->mode)
- {
- case Mode::Ascii:
- this->device->write(v ? "true" : "false");
- break;
- case Mode::Binary:
- // upper nibble
- this->device->write('0');
- this->device->write('0');
- this->device->write('0');
- this->device->write('0');
-
- // lower nibble
- this->device->write('0');
- this->device->write('0');
- // fallthrough
- case Mode::Hexadecimal:
- this->device->write('0');
- this->device->write(v ? '1' : '0');
- break;
- }
- return *this;
- }
-
- IOStream&
- operator << (const char& v)
- {
- if (this->mode == Mode::Ascii) {
- this->device->write(v);
- }
- else if (this->mode == Mode::Binary) {
- this->writeBin(v);
- }
- else {
- this->writeHex(v);
- }
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const uint16_t& v)
- {
- if (this->mode == Mode::Ascii) {
- this->writeInteger(v);
- }
- else if (this->mode == Mode::Binary) {
- this->writeBin(static_cast(v >> 8));
- this->writeBin(static_cast(v & 0xff));
- }
- else {
- this->writeHex(static_cast(v >> 8));
- this->writeHex(static_cast(v));
- }
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const int16_t& v)
- {
- if (this->mode == Mode::Ascii) {
- this->writeInteger(v);
- }
- else if (this->mode == Mode::Binary) {
- this->writeBin(static_cast(v >> 8));
- this->writeBin(static_cast(v));
- }
- else {
- this->writeHex(static_cast(v >> 8));
- this->writeHex(static_cast(v));
- }
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const uint32_t& v)
- {
- if (this->mode == Mode::Ascii) {
- this->writeInteger(v);
- }
- else if (this->mode == Mode::Binary) {
- this->writeBin(static_cast(v >> 24));
- this->writeBin(static_cast(v >> 16));
- this->writeBin(static_cast(v >> 8));
- this->writeBin(static_cast(v));
- }
- else {
- this->writeHex(static_cast(v >> 24));
- this->writeHex(static_cast(v >> 16));
- this->writeHex(static_cast(v >> 8));
- this->writeHex(static_cast(v));
- }
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const int32_t& v)
- {
- if (this->mode == Mode::Ascii) {
- this->writeInteger(v);
- }
- else if (this->mode == Mode::Binary) {
- this->writeBin(static_cast(v >> 24));
- this->writeBin(static_cast(v >> 16));
- this->writeBin(static_cast(v >> 8));
- this->writeBin(static_cast(v));
- }
- else {
- this->writeHex(static_cast(v >> 24));
- this->writeHex(static_cast(v >> 16));
- this->writeHex(static_cast(v >> 8));
- this->writeHex(static_cast(v));
- }
- return *this;
- }
-
-#if defined(MODM_OS_OSX) || defined(MODM_CPU_I386)
- // For OSX 'int64_t' is of type 'int'. Therefore there is no
- // function here for the default type 'long int'. As 'long int' has the same
- // width as 'int64_t' we just use a typedef here.
- modm_always_inline IOStream&
- operator << (const long int& v)
- {
- this->writeInteger(static_cast(v));
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const long unsigned int& v)
- {
- this->writeInteger(static_cast(v));
- return *this;
- }
-#endif
-
-#if defined(MODM_CPU_ARM) && defined(MODM_OS_NONE)
- // For ARM 'int32_t' is of type 'long'. Therefore there is no
- // function here for the default type 'int'. As 'int' has the same
- // width as 'int32_t' we just use a typedef here.
- modm_always_inline IOStream&
- operator << (const int& v)
- {
- this->writeInteger(static_cast(v));
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const unsigned int& v)
- {
- this->writeInteger(static_cast(v));
- return *this;
- }
-#endif
-
-// The 64-bit types on the AVR are extremely slow and are
-// therefore excluded here
-#if not defined(MODM_CPU_AVR)
- modm_always_inline IOStream&
- operator << (const uint64_t& v)
- {
- this->writeInteger(v);
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const int64_t& v)
- {
- this->writeInteger(v);
- return *this;
- }
-#endif
-
- modm_always_inline IOStream&
- operator << (const float& v)
- {
- this->writeFloat(v);
- return *this;
- }
-
- modm_always_inline IOStream&
- operator << (const double& v)
- {
-#if defined(MODM_CPU_AVR)
- this->writeFloat(static_cast(v));
-#else
- this->writeDouble(v);
-#endif
- return *this;
- }
-
- IOStream&
- operator << (const char* s)
- {
- if( this->mode == Mode::Ascii ) {
- this->device->write(s);
- }
- else if( this->mode == Mode::Binary ) {
- this->writeBin(s);
- }
- else {
- this->writeHex(s);
- }
- return *this;
- }
-
- /// write the hex value of a pointer
- IOStream&
- operator << (const void* p);
-
- modm_always_inline IOStream&
- operator << (IOStream& (*function)(IOStream&))
- {
- return function(*this);
- }
-
- typedef void (*myfunc)();
-
- IOStream&
- operator << (const myfunc& value);
-
- /// Write the hex value of a function pointer, catches all kinds of function pointers.
- template
- IOStream&
- operator << (Ret(*pointer)(Args...) )
- {
- unsigned char *p = (unsigned char *)&pointer;
-
- for (std::size_t i = 0; i < sizeof(myfunc); i++)
- {
- writeHex(p[sizeof(myfunc) - i - 1]);
- }
-
- return *this;
- }
-
- /**
- * @param fmt Format string
- */
- IOStream&
- printf(const char* fmt, ...) __attribute__((format(printf, 2, 3)));
-
- IOStream&
- vprintf(const char *fmt, va_list vlist) __attribute__((format(printf, 2, 0)));
-
-protected:
- void
- writeInteger(int16_t value);
-
- void
- writeInteger(uint16_t value);
-
- void
- writeInteger(int32_t value);
-
- void
- writeInteger(uint32_t value);
-
- void
- writeInteger(int64_t value);
-
- void
- writeInteger(uint64_t value);
-
- void
- writeHex(const char* s);
-
- void
- writeBin(const char* s);
-
- void
- writeHexNibble(uint8_t nibble);
-
- void
- writeHex(uint8_t value);
-
- void
- writeBin(uint8_t value);
-
- void
- writeFloat(const float& value);
-
-#if not defined(MODM_CPU_AVR)
- void
- writeDouble(const double& value);
-#endif
-
- void
- writeUnsignedInteger(unsigned long unsignedValue, uint_fast8_t base, size_t width, char fill, bool isNegative);
-#if not defined(MODM_CPU_AVR)
- void
- writeUnsignedLongLong(unsigned long long unsignedValue, uint_fast8_t base, size_t width, char fill, bool isNegative);
-#endif
-
-
-private:
- enum class
- Mode
- {
- Ascii,
- Hexadecimal,
- Binary
- };
-
- IOStream(const IOStream&);
-
- IOStream&
- operator =(const IOStream&);
-
-private:
- IODevice* const device;
- Mode mode;
-};
-
-/// @ingroup modm_io
-/// @{
-
-/// Flushes the output stream.
-/// This manipulator simply calls the stream's flush() member function.
-inline IOStream&
-flush(IOStream& ios)
-{
- return ios.flush();
-}
-
-//// Write a newline and flush the stream.
-inline IOStream&
-endl(IOStream& ios)
-{
- return flush(ios.write('\n'));
-}
-
-/// set the output mode to binary style for `char` and `char*`
-inline IOStream&
-bin(IOStream& ios)
-{
- return ios.bin();
-}
-
-/// set the output mode to hexadecimal style for `char` and `char*`
-inline IOStream&
-hex(IOStream& ios)
-{
- return ios.hex();
-}
-
-/// set the output mode to ASCII style for `char` and `char*`
-inline IOStream&
-ascii(IOStream& ios)
-{
- return ios.ascii();
-}
-
-/// Set the foreground colour on ANSI terminals.
-inline IOStream&
-black(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('0');
- ios.write('m');
- return ios;
-}
-
-inline IOStream&
-red(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('1');
- ios.write('m');
- return ios;
-}
-
-inline IOStream&
-green(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('2');
- ios.write('m');
- return ios;
-}
-
-inline IOStream&
-yellow(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('3');
- ios.write('m');
- return ios;
-}
-
-inline IOStream&
-blue(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('4');
- ios.write('m');
- return ios;
-}
-
-inline IOStream&
-magenta(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('1');
- ios.write('m');
- return ios;
-}
-
-inline IOStream&
-cyan(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('6');
- ios.write('m');
- return ios;
-}
-
-inline IOStream&
-white(IOStream& ios)
-{
- ios.write('\033');
- ios.write('[');
- ios.write('3');
- ios.write('7');
- ios.write('m');
- return ios;
-}
-/// @}
-
-} // namespace modm
-
-#endif // MODM_IOSTREAM_HPP
diff --git a/src/modm/io/iostream.hpp.in b/src/modm/io/iostream.hpp.in
new file mode 100644
index 0000000000..0c0c7d54dd
--- /dev/null
+++ b/src/modm/io/iostream.hpp.in
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2009-2010, Martin Rosekeit
+ * Copyright (c) 2009-2012, Fabian Greif
+ * Copyright (c) 2011, Georgi Grinshpun
+ * Copyright (c) 2011-2017, 2019 Niklas Hauser
+ * Copyright (c) 2012, 2015-2016, Sascha Schade
+ * Copyright (c) 2015-2016, Kevin Läufer
+ * Copyright (c) 2017, Marten Junga
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#ifndef MODM_IOSTREAM_HPP
+#define MODM_IOSTREAM_HPP
+
+#include
+#include
+
+#include // va_list
+#include
+#include
+
+#include "iodevice.hpp"
+#include "iodevice_wrapper.hpp" // convenience
+
+namespace modm
+{
+
+/**
+ * @ingroup modm_io
+ * @author Martin Rosekeit
+ * @author Niklas Hauser
+ */
+class IOStream
+{
+public:
+ /**
+ * @param device device to write the stream to
+ *
+ * @code
+ * MyIODevice device;
+ * IOStream stream( device );
+ * @endcode
+ */
+ inline IOStream(IODevice& odevice) :
+ device(&odevice)
+ {}
+
+ // Acccessors -------------------------------------------------------------
+ inline IOStream&
+ write(char c)
+ { device->write(c); return *this; }
+
+ static constexpr char eof = -1;
+
+ /// Reads one character and returns it if available. Otherwise, returns IOStream::eof.
+ inline IOStream&
+ get(char& c)
+ {
+ if(!device->read(c)) {
+ c = IOStream::eof;
+ }
+ return *this;
+ }
+
+ /// reads characters into NULL delimited c string
+ /// in contrast to the standard implementation, this does not care about
+ /// newline characters in the input
+ inline IOStream&
+ get(char* s, size_t n);
+
+ template
+ inline IOStream&
+ get(char (&s)[N])
+ { return get(s, N); }
+
+ // Modes ------------------------------------------------------------------
+ inline IOStream&
+ flush()
+ {
+ device->flush();
+ mode = Mode::Ascii;
+ return *this;
+ }
+
+ /// set the output mode to binary style for integer types
+ inline IOStream&
+ bin()
+ { mode = Mode::Binary; return *this; }
+
+ /// set the output mode to hexadecimal style for integer types
+ inline IOStream&
+ hex()
+ { mode = Mode::Hexadecimal; return *this; }
+
+ /// set the output mode to ASCII style for integer types
+ inline IOStream&
+ ascii()
+ { mode = Mode::Ascii; return *this; }
+
+ // Types ------------------------------------------------------------------
+ IOStream&
+ operator << (const bool& v);
+
+ // char is equal to int8_t!
+ inline IOStream&
+ operator << (const char& v)
+ {
+ if (mode == Mode::Ascii)
+ device->write(v);
+ else if (mode == Mode::Binary)
+ writeBin(static_cast(v));
+ else
+ writeHex(static_cast(v));
+ return *this;
+ }
+ inline IOStream&
+ operator << (const uint8_t& v)
+ {
+ if (mode == Mode::Ascii)
+ writeInteger(static_cast(v));
+ else if (mode == Mode::Binary)
+ writeBin(v);
+ else
+ writeHex(v);
+ return *this;
+ }
+
+ inline IOStream& operator << (const int16_t& v)
+ { writeIntegerMode(v); return *this; }
+ inline IOStream& operator << (const uint16_t& v)
+ { writeIntegerMode(v); return *this; }
+
+ inline IOStream& operator << (const int32_t& v)
+ { writeIntegerMode(v); return *this; }
+ inline IOStream& operator << (const uint32_t& v)
+ { writeIntegerMode(v); return *this; }
+
+%% if options["with_long_long"]
+ inline IOStream& operator << (const int64_t& v)
+ { writeIntegerMode(v); return *this; }
+ inline IOStream& operator << (const uint64_t& v)
+ { writeIntegerMode(v); return *this; }
+
+%% if family in ["darwin"]
+ // For OSX 'int64_t' is of type 'int'. Therefore there is no
+ // function here for the default type 'long int'. As 'long int' has the same
+ // width as 'int64_t' we just use a typedef here.
+ inline IOStream& operator << (const long int& v)
+ { writeIntegerMode(static_cast(v)); return *this; }
+ inline IOStream& operator << (const long unsigned int& v)
+ { writeIntegerMode(static_cast(v)); return *this; }
+%% endif
+%% endif
+
+%% if core.startswith("cortex-m")
+ // For ARM 'int32_t' is of type 'long'. Therefore there is no
+ // function here for the default type 'int'. As 'int' has the same
+ // width as 'int32_t' we just use a typedef here.
+ inline IOStream& operator << (const int& v)
+ { writeIntegerMode(static_cast(v)); return *this; }
+ inline IOStream& operator << (const unsigned int& v)
+ { writeIntegerMode(static_cast(v)); return *this; }
+%% endif
+
+%% if options["with_float"]
+ inline IOStream&
+ operator << (const float& v)
+ { writeFloat(v); return *this; }
+
+ inline IOStream&
+ operator << (const double& v)
+ { writeDouble(v); return *this; }
+%% endif
+
+ inline IOStream&
+ operator << (const char* s)
+ { device->write(s); return *this; }
+
+ /// write the hex value of a pointer
+ inline IOStream&
+ operator << (const void* p)
+ { writePointer(p); return *this; }
+
+ /// Write the hex value of any function pointer
+ template
+ IOStream&
+ operator << (Ret(*pointer)(Args...))
+ { writePointer(reinterpret_cast(&pointer)); return *this; }
+
+ inline IOStream&
+ operator << (IOStream& (*format)(IOStream&))
+ { return format(*this); }
+
+%% if options["with_printf"]
+ // printf -----------------------------------------------------------------
+ IOStream&
+ printf(const char* fmt, ...) __attribute__((format(printf, 2, 3)));
+
+ IOStream&
+ vprintf(const char *fmt, va_list vlist) __attribute__((format(printf, 2, 0)));
+%% endif
+
+
+protected:
+ template< typename T >
+ void
+ writeIntegerMode(const T v)
+ {
+ constexpr size_t t_bits = sizeof(T)*8;
+ if (mode == Mode::Ascii) {
+ writeInteger(v);
+ } else if (mode == Mode::Binary) {
+ for (uint8_t ii=t_bits-8; ii < t_bits; ii -= 8)
+ writeBin(static_cast>(v) >> ii);
+ } else {
+ for (uint8_t ii=t_bits-8; ii < t_bits; ii -= 8)
+ writeHex(static_cast>(v) >> ii);
+ }
+ }
+
+ void writeInteger(int16_t value);
+ void writeInteger(uint16_t value);
+ void writeInteger(int32_t value);
+ void writeInteger(uint32_t value);
+%% if options["with_long_long"]
+ void writeInteger(int64_t value);
+ void writeInteger(uint64_t value);
+%% endif
+
+%% if options["with_float"]
+ inline void writeFloat(float value)
+ { writeDouble(static_cast(value)); }
+ void writeDouble(const double& value);
+%% endif
+
+ void writePointer(const void* value);
+ void writeHex(uint8_t value);
+ void writeBin(uint8_t value);
+
+private:
+ enum class
+ Mode
+ {
+ Ascii,
+ Hexadecimal,
+ Binary
+ };
+
+ IOStream(const IOStream&) = delete;
+ IOStream& operator =(const IOStream&) = delete;
+
+private:
+ IODevice* const device;
+ Mode mode = Mode::Ascii;
+};
+
+/// @ingroup modm_io
+/// @{
+
+/// Flushes the output stream.
+/// This manipulator simply calls the stream's flush() member function.
+inline IOStream&
+flush(IOStream& ios)
+{ return ios.flush(); }
+
+//// Write a newline and flush the stream.
+inline IOStream&
+endl(IOStream& ios)
+{ return flush(ios.write('\n')); }
+
+/// set the output mode to binary style
+inline IOStream&
+bin(IOStream& ios)
+{ return ios.bin(); }
+
+/// set the output mode to hexadecimal style
+inline IOStream&
+hex(IOStream& ios)
+{ return ios.hex(); }
+
+/// set the output mode to ASCII style
+inline IOStream&
+ascii(IOStream& ios)
+{ return ios.ascii(); }
+
+/// Set the foreground colour on ANSI terminals.
+IOStream&
+black(IOStream& ios);
+
+IOStream&
+red(IOStream& ios);
+
+IOStream&
+green(IOStream& ios);
+
+IOStream&
+yellow(IOStream& ios);
+
+IOStream&
+blue(IOStream& ios);
+
+IOStream&
+magenta(IOStream& ios);
+
+IOStream&
+cyan(IOStream& ios);
+
+IOStream&
+white(IOStream& ios);
+/// @}
+
+} // namespace modm
+
+#endif // MODM_IOSTREAM_HPP
diff --git a/src/modm/io/iostream_float.cpp b/src/modm/io/iostream_float.cpp
deleted file mode 100644
index 40e5efa4af..0000000000
--- a/src/modm/io/iostream_float.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2009-2010, Martin Rosekeit
- * Copyright (c) 2009-2012, Fabian Greif
- * Copyright (c) 2012, Georgi Grinshpun
- * Copyright (c) 2012, 2014, 2017, Niklas Hauser
- * Copyright (c) 2013, Kevin Läufer
- * Copyright (c) 2016, Tarik TIRE
- * Copyright (c) 2018, Raphael Lehmann
- *
- * This file is part of the modm project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-// ----------------------------------------------------------------------------
-
-#include // snprintf()
-#include
-#include
-
-#include
-
-#include "iostream.hpp"
-
-void
-modm::IOStream::writeFloat(const float& value)
-{
- // hard coded for -2.22507e-308
- char str[13 + 1]; // +1 for '\0'
-
- if(!std::isfinite(value)) {
- char *ptr = &str[0];
- if(std::isinf(value)) {
- if (value < 0) {
- *ptr++ = '-';
- }
- *ptr++ = 'i';
- *ptr++ = 'n';
- *ptr++ = 'f';
- *ptr++ = '\0'; // End of string
- this->device->write(str);
- return;
- }
- else {
- *ptr++ = 'n';
- *ptr++ = 'a';
- *ptr++ = 'n';
- *ptr++ = '\0'; // End of string
- this->device->write(str);
- return;
- }
- }
-
-#if defined(MODM_CPU_AVR)
- dtostre(value, str, 5, 0);
- this->device->write(str);
-#elif defined(MODM_CPU_CORTEX_M4) || defined(MODM_CPU_CORTEX_M3) || defined(MODM_CPU_CORTEX_M0) || defined(MODM_OS_WIN32)
- float v;
- char *ptr = &str[0];
-
- if (value < 0) {
- v = -value;
- *ptr++ = '-';
- }
- else {
- v = value;
- }
-
- int32_t ep = 0;
- if (v != 0)
- {
- while (v < 1.f) {
- v *= 10;
- ep -= 1;
- }
-
- while (v > 10) {
- v *= 0.1f;
- ep += 1;
- }
- }
-
- for (uint32_t i = 0; i < 6; ++i)
- {
- int8_t num = static_cast(v);
- *ptr++ = (num + '0');
-
- if (i == 0) {
- *ptr++ = '.';
- }
-
- // next digit
- v = (v - num) * 10;
- }
-
- *ptr++ = 'e';
- if (ep < 0) {
- ep = -ep;
- *ptr++ = '-';
- }
- else {
- *ptr++ = '+';
- }
- if (ep < 10) {
- *ptr++ = '0';
- }
- *ptr++ = '\0'; // End of string
- this->device->write(str);
-
- this->writeInteger(ep);
-#else
- snprintf(str, sizeof(str), "%.5e", (double) value);
- this->device->write(str);
-#endif
-}
-
-// ----------------------------------------------------------------------------
-#if !defined(MODM_CPU_AVR)
-void
-modm::IOStream::writeDouble(const double& value)
-{
-#if defined(MODM_CPU_CORTEX_M4) || defined(MODM_CPU_CORTEX_M3) || defined(MODM_CPU_CORTEX_M0) || defined(MODM_OS_WIN32)
- // TODO do this better
- writeFloat(static_cast(value));
-#else
- // hard coded for 2.22507e-308
- char str[13 + 1]; // +1 for '\0'
- snprintf(str, sizeof(str), "%.5e", value);
- this->device->write(str);
-#endif
-}
-#endif
diff --git a/src/modm/io/iostream_printf.cpp b/src/modm/io/iostream_printf.cpp
deleted file mode 100644
index 5b8b2350a2..0000000000
--- a/src/modm/io/iostream_printf.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (c) 2011-2012, 2017, Fabian Greif
- * Copyright (c) 2012, 2014, 2017, Niklas Hauser
- * Copyright (c) 2014, 2016, Sascha Schade
- * Copyright (c) 2016, Kevin Läufer
- * Copyright (c) 2017, Marten Junga
- * Copyright (c) 2017-2018, Raphael Lehmann
- *
- * This file is part of the modm project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-// ----------------------------------------------------------------------------
-
-#include
-#include // snprintf()
-#include
-#include // modm::pow
-
-#include "iostream.hpp"
-
-modm::IOStream&
-modm::IOStream::printf(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
-
- this->vprintf(fmt, ap);
-
- va_end(ap);
- return *this;
-}
-
-modm::IOStream&
-modm::IOStream::vprintf(const char *fmt, va_list ap)
-{
- unsigned char c;
-
- // for all chars in format (fmt)
- while ((c = *fmt++) != 0)
- {
- bool isSigned = false;
- bool isLong = false;
- bool isLongLong = false;
- bool isFloat = false;
- bool isNegative = false;
-
- if (c != '%')
- {
- this->device->write(c);
- continue;
- }
- c = *fmt++;
-
- size_t width = 0;
- size_t width_frac = 0;
- char fill = ' ';
- if (c == '0')
- {
- fill = c;
- c = *fmt++;
- }
- if (c >= '0' && c <= '9')
- {
- width = c - '0';
- c = *fmt++;
- }
-
- if (c == '.') {
- c = *fmt++;
-
- if (c >= '0' && c <= '9') {
- width_frac = c - '0';
- }
- c = *fmt++;
- }
-
- if (c == 'l')
- {
- isLong = true;
- c = *fmt++;
- }
- if (c == 'l')
- {
- isLongLong = true;
- c = *fmt++;
- }
-
- uint_fast8_t base = 10;
- char *ptr;
- switch (c)
- {
- case 'c':
- c = va_arg(ap, int); // char promoted to int
- MODM_FALLTHROUGH;
- default:
- this->device->write(c);
- continue;
-
- case 's':
- ptr = (char *) va_arg(ap, char *);
- while ((c = *ptr++))
- {
- this->device->write(c);
- }
- continue;
-
- case 'f':
- isFloat = true;
- break;
-
- case 'd':
- isSigned = true;
- MODM_FALLTHROUGH;
-
- case 'u':
- base = 10;
- break;
-
- case 'p':
- this->device->write('0');
- this->device->write('x');
- fill = '0';
- width = (MODM_SIZEOF_POINTER * 2);
- isLong = (MODM_SIZEOF_POINTER == 4);
- isLongLong = (MODM_SIZEOF_POINTER == 8);
- MODM_FALLTHROUGH;
- case 'x':
- base = 16;
- break;
-
- case 'b':
- base = 2;
- break;
- }
-
-
- // Number output
- if (isFloat)
- {
- // va_arg(ap, float) not allowed
- float float_value = va_arg(ap, double);
-
- if(!std::isfinite(float_value)) {
- if(std::isinf(float_value)) {
- if (float_value < 0) {
- this->device->write('-');
- }
- this->device->write('i');
- this->device->write('n');
- this->device->write('f');
- return *this;
- }
- else {
- this->device->write('n');
- this->device->write('a');
- this->device->write('n');
- return *this;
- }
- }
-
- if (float_value < 0)
- {
- float_value = -float_value; // make it positive
- isNegative = true;
- }
-
- // Rounding
- float_value += 0.5 / modm::pow(10, width_frac);
-
- // 1) Print integer part
- int width_integer = width - width_frac - 1;
- if (width_integer < 0) {
- width_integer = 0;
- }
-
- writeUnsignedInteger((unsigned int)float_value, base, width_integer, fill, isNegative);
-
- // 2) Decimal dot
- this->device->write('.');
-
- // 3) Fractional part
- float_value = float_value - ((int) float_value);
- float_value *= modm::pow(10, width_frac);
-
- // Alternative: Smaller code size but probably less precise
- // for (uint_fast8_t ii = 0; ii < width_frac; ++ii) {
- // float_value = float_value * (10.0);
- // }
-
- // Print fractional part
- writeUnsignedInteger((unsigned int)float_value, base, width_frac, '0', false);
- }
-#if not defined(MODM_CPU_AVR)
- else if (isLongLong)
- {
- long long signedValue = va_arg(ap, long long);
- if (isSigned)
- {
- if (signedValue < 0)
- {
- isNegative = true;
- signedValue = -signedValue; // make it positive
- }
- }
- writeUnsignedLongLong((unsigned long long) signedValue, base, width, fill, isNegative);
- }
-#endif
- else
- {
- unsigned long unsignedValue;
-
- {
- long signedValue = 0;
-
- if (isLongLong) {
- signedValue = va_arg(ap, long long);
- }
- else if (isLong) {
- signedValue = va_arg(ap, long);
- }
- else {
- signedValue = va_arg(ap, int);
- }
-
- if (isSigned)
- {
- if (signedValue < 0)
- {
- isNegative = true;
- signedValue = -signedValue; // make it positive
- }
- }
- unsignedValue = (unsigned long) signedValue;
- }
-
- writeUnsignedInteger(unsignedValue, base, width, fill, isNegative);
- }
- }
-
- return *this;
-}
-
-void
-modm::IOStream::writeUnsignedInteger(
- unsigned long unsignedValue, uint_fast8_t base,
- size_t width, char fill, bool isNegative)
-{
- char scratch[26];
-
- char *ptr = scratch + sizeof(scratch);
- *--ptr = 0;
- do
- {
- char ch = (unsignedValue % base) + '0';
-
- if (ch > '9') {
- ch += 'A' - '9' - 1;
- }
-
- *--ptr = ch;
- unsignedValue /= base;
-
- if (width) {
- --width;
- }
- } while (unsignedValue);
-
- // Insert minus sign if needed
- if (isNegative)
- {
- *--ptr = '-';
- if (width) {
- --width;
- }
- }
-
- // insert padding chars
- while (width--) {
- *--ptr = fill;
- }
-
- // output result
- char ch;
- while ((ch = *ptr++)) {
- this->device->write(ch);
- }
-}
-
-#if not defined(MODM_CPU_AVR)
-void
-modm::IOStream::writeUnsignedLongLong(
- unsigned long long unsignedValue, uint_fast8_t base,
- size_t width, char fill, bool isNegative)
-{
- char scratch[26];
-
- char *ptr = scratch + sizeof(scratch);
- *--ptr = 0;
- do
- {
- char ch = (unsignedValue % base) + '0';
-
- if (ch > '9') {
- ch += 'A' - '9' - 1;
- }
-
- *--ptr = ch;
- unsignedValue /= base;
-
- if (width) {
- --width;
- }
- } while (unsignedValue);
-
- // Insert minus sign if needed
- if (isNegative)
- {
- *--ptr = '-';
- if (width) {
- --width;
- }
- }
-
- // insert padding chars
- while (width--) {
- *--ptr = fill;
- }
-
- // output result
- char ch;
- while ((ch = *ptr++)) {
- this->device->write(ch);
- }
-}
-#endif
diff --git a/src/modm/io/iostream_printf.cpp.in b/src/modm/io/iostream_printf.cpp.in
new file mode 100644
index 0000000000..74e0737a1c
--- /dev/null
+++ b/src/modm/io/iostream_printf.cpp.in
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2019, Niklas Hauser
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#include
+#include
+#include
+#include
+
+#include "iostream.hpp"
+
+extern "C"
+{
+ // configure printf implementation
+%% if not options["with_long_long"]
+ #define PRINTF_DISABLE_SUPPORT_LONG_LONG
+%% endif
+%% if not options["with_float"]
+ #define PRINTF_DISABLE_SUPPORT_FLOAT
+%% endif
+%% if not options["with_ptrdiff"]
+ #define PRINTF_DISABLE_SUPPORT_PTRDIFF_T
+%% endif
+ #define PRINTF_DEFAULT_FLOAT_PRECISION 5U
+
+ // include source from modm/ext/printf
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdouble-promotion"
+ #include "printf/printf.source"
+ #pragma GCC diagnostic pop
+ void _putchar(char) {};
+
+%% if core.startswith("avr") and options["with_float"]
+ // the double arithmetric in these functions does not work on AVRs
+ static size_t _etoa(out_fct_type, [[maybe_unused]] char* buffer, size_t idx, size_t,
+ [[maybe_unused]] double value, unsigned int, unsigned int, unsigned int)
+ {
+ *reinterpret_cast(buffer) << value;
+ return idx;
+ }
+ static size_t _ftoa(out_fct_type, [[maybe_unused]] char* buffer, size_t idx, size_t,
+ [[maybe_unused]] double value, unsigned int, unsigned int, unsigned int)
+ {
+ *reinterpret_cast(buffer) << value;
+ return idx;
+ }
+%% endif
+}
+
+namespace
+{
+void out_char(char character, void* buffer, size_t, size_t)
+{
+ if (character)
+ reinterpret_cast(buffer)->write(character);
+}
+}
+
+namespace modm
+{
+
+%% if options["with_printf"]
+IOStream&
+IOStream::printf(const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ vprintf(fmt, va);
+ va_end(va);
+ return *this;
+}
+
+IOStream&
+IOStream::vprintf(const char *fmt, va_list ap)
+{
+ _vsnprintf(out_char, (char*)this, -1, fmt, ap);
+ return *this;
+}
+%% endif
+
+void
+IOStream::writeInteger(int16_t value)
+{
+%% if core.startswith("avr") and not options["with_printf"]
+ // hard coded for -32768
+ char str[7 + 1]; // +1 for '\0'
+ itoa(value, str, 10);
+ device->write(str);
+%% else
+ _ntoa_long(out_char, (char*)this,
+ 0, -1,
+ uint16_t(value < 0 ? -value : value),
+ value < 0,
+ 10, 0, 0,
+ FLAGS_SHORT);
+%% endif
+}
+
+void
+IOStream::writeInteger(uint16_t value)
+{
+%% if core.startswith("avr") and not options["with_printf"]
+ // hard coded for 32768
+ char str[6 + 1]; // +1 for '\0'
+ utoa(value, str, 10);
+ device->write(str);
+%% else
+ _ntoa_long(out_char, (char*)this,
+ 0, -1,
+ value,
+ false,
+ 10, 0, 0,
+ FLAGS_SHORT);
+%% endif
+}
+
+void
+IOStream::writeInteger(int32_t value)
+{
+%% if core.startswith("avr") and not options["with_printf"]
+ // hard coded for -2147483648
+ char str[11 + 1]; // +1 for '\0'
+ ltoa(value, str, 10);
+ device->write(str);
+%% else
+ _ntoa_long(out_char, (char*)this,
+ 0, -1,
+ uint32_t(value < 0 ? -value : value),
+ value < 0,
+ 10, 0, 0,
+ FLAGS_LONG);
+%% endif
+}
+
+void
+IOStream::writeInteger(uint32_t value)
+{
+%% if core.startswith("avr") and not options["with_printf"]
+ // hard coded for 4294967295
+ char str[10 + 1]; // +1 for '\0'
+ ultoa(value, str, 10);
+ device->write(str);
+%% else
+ _ntoa_long(out_char, (char*)this,
+ 0, -1,
+ value,
+ false,
+ 10, 0, 0,
+ FLAGS_LONG);
+%% endif
+}
+
+%% if options["with_long_long"]
+void
+IOStream::writeInteger(int64_t value)
+{
+ _ntoa_long_long(out_char, (char*)this,
+ 0, -1,
+ uint64_t(value < 0 ? -value : value),
+ value < 0,
+ 10, 0, 0,
+ FLAGS_LONG_LONG);
+}
+
+void
+IOStream::writeInteger(uint64_t value)
+{
+ _ntoa_long_long(out_char, (char*)this,
+ 0, -1,
+ value,
+ false,
+ 10, 0, 0,
+ FLAGS_LONG_LONG);
+}
+%% endif
+
+%% if options["with_float"]
+void
+IOStream::writeDouble(const double& value)
+{
+%% if core.startswith("avr")
+ if(!std::isfinite(value)) {
+ if(std::isinf(value)) {
+ if (value < 0) device->write('-');
+ *this << IFSS("inf");
+ }
+ else {
+ *this << IFSS("nan");
+ }
+ }
+ else {
+ // hard coded for -2.22507e-308
+ char str[13 + 1]; // +1 for '\0'
+ dtostre(value, str, 5, 0);
+ device->write(str);
+ }
+%% else
+ _etoa(out_char, (char*)this,
+ 0, -1,
+ value,
+ 0, 0, 0);
+%% endif
+}
+%% endif
+
+} // namespace modm
diff --git a/src/modm/io/module.lb b/src/modm/io/module.lb
index e8e794b22c..7df616b9a1 100644
--- a/src/modm/io/module.lb
+++ b/src/modm/io/module.lb
@@ -19,11 +19,44 @@ def prepare(module, options):
module.depends(
":architecture:accessor",
":math:utils")
+
+ is_avr = options[":target"].identifier.platform in ["avr"]
+ module.add_option(
+ BooleanOption(name="with_long_long",
+ description="Support for 64-bit integer formatting",
+ default=not is_avr))
+ module.add_option(
+ BooleanOption(name="with_float",
+ description="Support for floating point formatting",
+ default=not is_avr))
+ module.add_option(
+ BooleanOption(name="with_ptrdiff",
+ description="Support for pointer difference formatting",
+ default=not is_avr))
+ module.add_option(
+ BooleanOption(name="with_printf",
+ description="Support for printf-style formatting",
+ default=not is_avr))
+
return True
def build(env):
env.outbasepath = "modm/src/modm/io"
- env.copy(".", ignore=env.ignore_files("io.hpp"))
+ env.copy(".", ignore=env.ignore_files("io.hpp", "iostream_printf.cpp.in", "iostream.hpp.in"))
+ env.substitutions = {
+ "family": env[":target"].identifier.family,
+ "core": env[":target"].get_driver("core")["type"],
+ }
+ env.template("iostream_printf.cpp.in")
+ env.template("iostream.hpp.in")
+
env.outbasepath = "modm/src/modm"
env.copy("io.hpp")
+ env.outbasepath = "modm/ext/printf"
+ # Copy custom printf header
+ env.copy(repopath("ext/mpaland/printf.h"), "printf.h")
+ # Copy source file but without .c suffix so it doesn't get indexed for compilation.
+ env.copy(repopath("ext/mpaland/printf/printf.c"), "printf.source")
+ env.collect(":build:path.include", "modm/ext")
+
diff --git a/src/modm/platform/core/avr/flash_reader.hpp b/src/modm/platform/core/avr/flash_reader.hpp
index 9a06c8ca33..ae2658ea1d 100644
--- a/src/modm/platform/core/avr/flash_reader.hpp
+++ b/src/modm/platform/core/avr/flash_reader.hpp
@@ -24,7 +24,7 @@
#define FLASH_STORAGE_STRING(s) extern const char s[] PROGMEM; const char s[]
#define EXTERN_FLASH_STORAGE_STRING(s) extern const char s[] PROGMEM
-#define INLINE_FLASH_STORAGE_STRING(s) PSTR(s)
+#define IFSS(s) (modm::accessor::Flash(PSTR(s)))
namespace modm
{
diff --git a/src/modm/platform/core/cortex/flash_reader.hpp b/src/modm/platform/core/cortex/flash_reader.hpp
index 968c777316..08a89e1575 100644
--- a/src/modm/platform/core/cortex/flash_reader.hpp
+++ b/src/modm/platform/core/cortex/flash_reader.hpp
@@ -29,8 +29,7 @@
#define FLASH_STORAGE_STRING(s) extern const char s[]; const char s[]
#define EXTERN_FLASH_STORAGE_STRING(s) extern const char s[]
-#define INLINE_FLASH_STORAGE_STRING(s) ((const char *)(s))
-#define PSTR(s) ((const char *)(s))
+#define IFSS(s) ((const char *)(s))
namespace modm
{
diff --git a/test/config/al-avreb-can.xml b/test/config/al-avreb-can.xml
index 479c6c58f9..0e78cbe0f6 100644
--- a/test/config/al-avreb-can.xml
+++ b/test/config/al-avreb-can.xml
@@ -5,6 +5,9 @@
+
+
+
diff --git a/test/config/arduino-nano.xml b/test/config/arduino-nano.xml
index 94f6a65114..0a614b2c6a 100644
--- a/test/config/arduino-nano.xml
+++ b/test/config/arduino-nano.xml
@@ -4,6 +4,9 @@
+
+
+
diff --git a/test/config/arduino-uno.xml b/test/config/arduino-uno.xml
index 0f17db7fef..6bd5c8186c 100644
--- a/test/config/arduino-uno.xml
+++ b/test/config/arduino-uno.xml
@@ -4,6 +4,9 @@
+
+
+
diff --git a/test/modm/io/io_stream_test.cpp b/test/modm/io/io_stream_test.cpp
index 0d3015b62a..f7353bd6e0 100644
--- a/test/modm/io/io_stream_test.cpp
+++ b/test/modm/io/io_stream_test.cpp
@@ -20,18 +20,7 @@
#include // MODM_ARRAY_SIZE
#include // snprintf
#include // memset
-
-#if not defined(MODM_CPU_AVR)
#include
-#else
-#include
-namespace std {
-template struct numeric_limits {
- static constexpr T quiet_NaN() { return NAN; }
- static constexpr T infinity() { return INFINITY; }
-};
-}
-#endif
// ----------------------------------------------------------------------------
// simple IODevice which stores all data in a memory buffer
@@ -108,14 +97,12 @@ IoStreamTest::testString()
TEST_ASSERT_EQUALS(device.bytesWritten, 6U);
}
-FLASH_STORAGE_STRING(flashString) = "abc";
-
void
IoStreamTest::testFlashString()
{
char string[] = "abc";
- (*stream) << modm::accessor::asFlash(flashString);
+ (*stream) << IFSS("abc");
TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 3);
TEST_ASSERT_EQUALS(device.bytesWritten, 3U);
@@ -252,27 +239,23 @@ IoStreamTest::testStreamInt32_3()
void
IoStreamTest::testStreamUint64()
{
-#ifndef __AVR__
char string[] = "12345678901234";
(*stream) << static_cast(12345678901234ULL);
TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 14);
TEST_ASSERT_EQUALS(device.bytesWritten, 14U);
-#endif
}
void
IoStreamTest::testStreamInt64()
{
-#ifndef __AVR__
char string[] = "-12345678901234";
(*stream) << static_cast(-12345678901234LL);
TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 15);
TEST_ASSERT_EQUALS(device.bytesWritten, 15U);
-#endif
}
// ----------------------------------------------------------------------------
@@ -342,6 +325,72 @@ IoStreamTest::testFloat6()
TEST_ASSERT_EQUALS(device.bytesWritten, 3U);
}
+void
+IoStreamTest::testFloatPrintf()
+{
+ char string[] = "1.23000e+00";
+
+ stream->printf("%e", double(1.23));
+
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 11);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 11U);
+}
+
+void
+IoStreamTest::testFloatPrintf2()
+{
+ char string[] = "4.57000e+02";
+
+ stream->printf("%e", double(457.0));
+
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 11);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 11U);
+}
+
+void
+IoStreamTest::testFloatPrintf3()
+{
+ char string[] = "-5.12314e+07";
+
+ stream->printf("%e", double(-51231400.0));
+
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 12);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 12U);
+}
+
+void
+IoStreamTest::testFloatPrintf4()
+{
+ char string[] = "-7.23400e-04";
+
+ stream->printf("%e", double(-0.0007234));
+
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 12);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 12U);
+}
+
+void
+IoStreamTest::testFloatPrintf5()
+{
+ char string[] = "nan";
+
+ stream->printf("%e", std::numeric_limits::quiet_NaN());
+
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 3);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 3U);
+}
+
+void
+IoStreamTest::testFloatPrintf6()
+{
+ char string[] = "inf";
+
+ stream->printf("%e", std::numeric_limits::infinity());
+
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 3);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 3U);
+}
+
void
IoStreamTest::testBool1()
{
@@ -385,14 +434,14 @@ IoStreamTest::testHex1()
void
IoStreamTest::testHex2()
{
- char string[] = "48616C6C6F04";
+ char string[] = "48616C6C6F00";
char s[] = "Hallo";
+ (*stream) << modm::hex;
+ for (char c : s) (*stream) << c;
- (*stream) << modm::hex << s;
-
- TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 10);
- TEST_ASSERT_EQUALS(device.bytesWritten, 10U);
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 12);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 12U);
}
void
@@ -454,14 +503,14 @@ IoStreamTest::testBin1()
void
IoStreamTest::testBin2()
{
- char string[] = "0100100001100001011011000110110001101111";
+ char string[] = "010010000110000101101100011011000110111100000000";
char s[] = "Hallo";
+ (*stream) << modm::bin;
+ for (char c : s) (*stream) << c;
- (*stream) << modm::bin << s;
-
- TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 40);
- TEST_ASSERT_EQUALS(device.bytesWritten, 40U);
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 48);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 48U);
}
void
@@ -493,7 +542,7 @@ IoStreamTest::testBin4()
void
IoStreamTest::testBin5()
{
- char string[] = "0000000100000000";
+ char string[] = "10";
bool boo = true;
@@ -502,8 +551,8 @@ IoStreamTest::testBin5()
boo = false;
(*stream) << modm::bin << boo;
- TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 16);
- TEST_ASSERT_EQUALS(device.bytesWritten, 16U);
+ TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, 2);
+ TEST_ASSERT_EQUALS(device.bytesWritten, 2U);
}
void
@@ -565,10 +614,9 @@ IoStreamTest::testPrintf2()
void
IoStreamTest::testPrintf3()
{
-#if not defined(MODM_CPU_AVR)
// Test for 64 bit uints and ints on printf
unsigned long long unsignedlonglong = 0xFEDCBA9876543210;
- (*stream).printf("%llx", unsignedlonglong);
+ (*stream).printf("%llX", unsignedlonglong);
TEST_ASSERT_EQUALS_ARRAY("FEDCBA9876543210", device.buffer, 16);
(*stream).flush();
@@ -576,7 +624,6 @@ IoStreamTest::testPrintf3()
(*stream).printf("%lld", longlong);
TEST_ASSERT_EQUALS_ARRAY("-9223372036854775806", device.buffer, 20);
(*stream).flush();
-#endif
}
int myFunc1(void) { return -1; };
@@ -615,7 +662,7 @@ IoStreamTest::testPointer()
const size_t bytesWritten = 18;
#endif
- (*stream).printf("%p", p);
+ (*stream).printf("0x%p", p);
TEST_ASSERT_EQUALS_ARRAY(string, device.buffer, bytesWritten);
TEST_ASSERT_EQUALS(device.bytesWritten, bytesWritten);
diff --git a/test/modm/io/io_stream_test.hpp b/test/modm/io/io_stream_test.hpp
index 09e4f7460b..65cdd7d17a 100644
--- a/test/modm/io/io_stream_test.hpp
+++ b/test/modm/io/io_stream_test.hpp
@@ -95,6 +95,25 @@ class IoStreamTest : public unittest::TestSuite
void
testFloat6();
+ // float via printf
+ void
+ testFloatPrintf();
+
+ void
+ testFloatPrintf2();
+
+ void
+ testFloatPrintf3();
+
+ void
+ testFloatPrintf4();
+
+ void
+ testFloatPrintf5();
+
+ void
+ testFloatPrintf6();
+
// bool
void
testBool1();