0

I learned about StringStream today at work.

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string.h>

using namespace std;

char* getSql() {
    float outdoorTempInC = 15;
    int outoorHumidity = 23;
    float indorTempinC = 20;
    int humidity = 22;
    int val = 400; // soil sensor reading
    int avgVal = 38; // avaerage of 10 values of soils sensor
    char statusMsg[50] = {"Hello World"} ;
    std::stringstream sqlQuery;
    sqlQuery  << "INSERT INTO arduinoSensorData.sensorLog (out_temperature,  " 
        << "out_humidity,  drwngRoom_temperature, drwngRoom_humidity, "
        << "pot1_soilMoisture, pot1_avg_SoilMoisture, wateringPot1) VALUES ('" 
        << outdoorTempInC << "', '" << outoorHumidity << "', '" << indorTempinC
        << "', '" << humidity << "', '" << val << "', '" << avgVal << "', '"
        << statusMsg << "');";

    char *mychar = new char[sqlQuery.str().length() + 1];
    strcpy(mychar, sqlQuery.str().c_str());
    return mychar;
}

string getSqlStream() {
    float outdoorTempInC = 15;
    int outoorHumidity = 23;
    float indorTempinC = 20;
    int humidity = 22;
    int val = 400; // soil sensor reading
    int avgVal = 38; // avaerage of 10 values of soils sensor
    char statusMsg[50] = {"Hello World"} ;
    std::stringstream sqlQuery;
    sqlQuery  << "INSERT INTO arduinoSensorData.sensorLog (out_temperature,  " 
        << "out_humidity,  drwngRoom_temperature, drwngRoom_humidity, "
        << "pot1_soilMoisture, pot1_avg_SoilMoisture, wateringPot1) VALUES ('" 
        << outdoorTempInC << "', '" << outoorHumidity << "', '" << indorTempinC
        << "', '" << humidity << "', '" << val << "', '" << avgVal << "', '"
        << statusMsg << "');";
    return sqlQuery.str();
}

int main() {
    string sql = getSqlStream();
    cout << getSql() << "\n";
    cout << sql.c_str() << "\n";
    return  0;
}

I was very happy until I discovered I cannot use StringStream in Arduino, so I dug in the internet and came across with this.

So if I try to use the above linked gist StringSteam like I have used in my example code, I am getting this error:

error: no match for 'operator<<' (operand types are 'StringStream' and 'const char [60]')
     sqlQuery  << "INSERT INTO arduinoSensorData.sensorLog (out_temperature,  " 
               ^
webServer_Displaying_everything_v01:24: error: 'outdoorTempInC' was not declared in this scope
         << outdoorTempInC << "', '" << outoorHumidity << "', '" << indorTempinC
            ^
webServer_Displaying_everything_v01:24: error: 'outoorHumidity' was not declared in this scope
         << outdoorTempInC << "', '" << outoorHumidity << "', '" << indorTempinC
                                        ^
webServer_Displaying_everything_v01:24: error: 'indorTempinC' was not declared in this scope
         << outdoorTempInC << "', '" << outoorHumidity << "', '" << indorTempinC
                                                                    ^
webServer_Displaying_everything_v01:25: error: 'humidity' was not declared in this scope
         << "', '" << humidity << "', '" << val << "', '" << avgVal << "', '"
                      ^
webServer_Displaying_everything_v01:25: error: 'val' was not declared in this scope
         << "', '" << humidity << "', '" << val << "', '" << avgVal << "', '"
                                            ^
webServer_Displaying_everything_v01:25: error: 'avgVal' was not declared in this scope
         << "', '" << humidity << "', '" << val << "', '" << avgVal << "', '"
                                                             ^
webServer_Displaying_everything_v01:28: error: 'class StringStream' has no member named 'str'
     char *mychar = new char[sqlQuery.str().length() + 1];
                                      ^
webServer_Displaying_everything_v01:29: error: 'class StringStream' has no member named 'str'
     strcpy(mychar, sqlQuery.str().c_str());

Or I am doing it completely the wrong way? It feels I still cannot use it the way I have done in the example. Please help.

  • This class is not a “stream” in the C++ sense, it's a Stream in the Arduino sense, i.e. it provides an interface similar to Serial. You can for instance print() and println() to it. – Edgar Bonet Jan 27 '17 at 19:31
  • @EdgarBonet so in that case how can I use sqlQuery method of storing to a variable in arduino without having to use print(), println or sprintf ? – Ciasto piekarz Jan 27 '17 at 19:50
  • The whole purpose if this StringStream is to let you print() and println() into it. – Edgar Bonet Jan 27 '17 at 20:29
  • 1
    The reference to StringStream is to "#include <sstream>" which is very much a stream in the C++ sense, not in the Arduino sense. The OP is looking to use std C++ in Arduino. The answer is to use the GNU tool chains used by (and installed with) the Arduino IDE, but without the ino preprocessor. There is no class StringStream. The class is ostringstream, and its purpose is to provide appendage methods via the << operator. Println is never used. The \n, \r\n, or preferably std::endl is used to terminate a line and sprintf may or may not be used underneath the ostringstream methods. – FauChristian Jan 30 '17 at 17:01
4

Direct Answer

Program in C++ and cross compile to the Arduino Yún. The Arduino Sketch language is a thin layer over C++, but the std:: namespace is not light weight to the degree it would need to be to fit the things you are appreciating from the standard C++ library into the memory footprint of a small embedded CPU board. See Arduino Yun C++ environment? Bridge + Cross-Compiler.

Serious Programming on Arduino

If you wish to open the door to C++ elegance on smaller embedded CPU boards like the simpler Arduinos, you will need to move beyond the Arduino sketch language. You may find it both fun and useful to learn how to cross compile and link using the GNU tool set that targets the Atmel CPU you have on your board.

This more professional approach is not for the faint at heart, but it is done all the time. We do it here in TranSeed Labs every day.

To get started, you don't need to download or install anything other than the Arduino software. The tool set that targets Atmel's AVR architecture (used by several Arduino boards) is in a sub-directory under the Arduino IDE's home directory. The tool set that targets Atmel's SAM Architecture for the Arduino Due is placed in a sub-directory of your home directory when you set up the IDE to upload sketches to the Due.

Returning to the Question in This C++ Context

Once you learn how to compile and link using g++ from the GNU tool chain1 and use the upload tools2 your program via the USB port, you can create a template class to get the elegance available in C++ like the operator overloading that you like.

The issue with trying to employ the C++ library with embedded targets is that the allocation system and other dependencies will probably exhaust much if not all of your program memory. The ostringstream class from the C++ library, with all its dependencies included, is not extremely lean.

An approach that consumes very little memory and does not require the CPU cycles of dynamic allocation is to create a C++ template that wraps a static array. Its buffer size can be one of the template parameters.

Then you can overload the << operator of the class using these examples as a guide. You get your elegance and drastically reduce your computing resource requirements.


[1] Both cross compiling and cross linking are done with g++ (gcc for the Aruino and Atmel C files in the library). For Arduino boards using the AVR based Atmel CPUs, use the AVR GNU Tool Chain. For the Due, which uses the SAM based Atmel CPUs, use the SAM5X GNU Tool Chain.

[2] The program bossac is used to upload to the Due. The program avrdude is used to upload to the Mega 2560.

  • well, I do not have Arduino Yun, but I was rather going to buy [Arduino Yun Shield][1], I'd assume it should not make difference , correct me if I am wrong please ! [1]: arduino.cc/en/Main/ArduinoYunShield – Ciasto piekarz Jan 29 '17 at 4:58
  • Yun board != Yun shield – Douglas Daseeco Jan 29 '17 at 9:42
  • 1
    Thanks Douglas, best answer I have accepted however just little bit more trouble I would appreciate if in your answer you can link up the text "cross compile" , "link using the GNU tool" and "set that targets the Atmel CPU" example on web. It will seed the process of learning. However I would refrain from directly jumping to higher step. – Ciasto piekarz Jan 29 '17 at 11:20
  • 1
    This answer is almost exactly the road we take here at the lab, and it works very well. Most of the serious embedded programmers use microemacs to develop. We tried using the std:: namespace in sketches for containers and strings, but the advantage to moving to g++ and a makefile became obvious in the first week of writing actual programs. The way outlined here has worked for three years now and triples our development speed. – FauChristian Jan 30 '17 at 16:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.