-2

I am trying to extract a few integers from a string on Arduino. I am using a Bluefruit Bluetooth module that I have linked to my mobile phone.

An application on my phone sends a string of data to the Arduino via the Bluefruit's TX/RX.

I succesfully receive the data from the application, and I can see it in my serial monitor on my computer. The strings are in this format: x:xxx,xxx,xxx with the first number being 1 to 6, and the other numbers being three 0-255.

So for example: 1:171,54,201

The string also includes a carriage return, since the next string always starts on a new line.

Can anyone help me extract these integers and set them to variables?

cbuchart
  • 10,847
  • 9
  • 53
  • 93

2 Answers2

1

You can use the C sscanf() function:

#include <stdio.h>

char line[] = "1:171,54,201"; // read a line from Bluetooth
int num1, num2, num3, num4;

if (sscanf(line, "%d:%d,%d,%d", &num1, &num2, &num3, &num4) == 4)
{
    // use numbers as needed
}

Or the C++ wrapper, std::sscanf():

#include <cstdio>

char line[] = "1:171,54,201"; // read a line from Bluetooth
int num1, num2, num3, num4;

if (std::sscanf(line, "%d:%d,%d,%d", &num1, &num2, &num3, &num4) == 4)
{
    // use numbers as needed
}

If you have an STL available (which apparently Arduino does not), you could use the STL std::istringstream class instead:

#include <string>
#include <sstream>

std::string line = "1:171,54,201"; // read a line from Bluetooth
int num1, num2, num3, num4;

std::istringstream iss(line);
char ignore;

if (iss >> num1 >> ignore >> num2 >> ignore >> num3 >> ignore >> num4)
{
    // use numbers as needed
}

Alternatively:

#include <string>
#include <sstream>

bool readInt(std::istream &in, char delim, int &value)
{
    std::string temp;
    if (!std::getline(in, temp, delim)) return false;
    return (std::istringstream(temp) >> value);
}

std::string line = "1:171,54,201"; // read a line from Bluetooth
int num1, num2, num3, num4;

std::istringstream iss(line);

if (readInt(iss, ':', num1) && readInt(iss, ',', num2) && readInt(iss, ',', num3) && readInt(iss, '\n', num4))
{
    // use numbers as needed
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • This seems like a good solution. I'm trying it right now, but I have the issue that it says that string is not a part of std. Also I can't include I am updating Arduino IDE to see if that resolves the issue. – Luca van der knaap Mar 21 '17 at 21:46
  • @Lucavanderknaap Arduino "C++" is not real "C++" it's more like a restricted subset/dialect. The STL is not available on Arduino by the vendors, there are however small, restricted implementations for microcontrollers out there. –  Mar 21 '17 at 21:51
  • @RemyLebeau I have added .h to string and now it includes it, but I still have the error that "string is not a member of std" – Luca van der knaap Mar 21 '17 at 21:55
  • @user2176127 So do you mean that it is not possible to use the solutions Remy suggested because the methods are simply not avaible for arduino? – Luca van der knaap Mar 21 '17 at 21:55
  • @Lucavanderknaap `` and `` are two different things. But yes, if the STL is not available then you can ignore most of my answer. `sscanf()` comes from C, not C++, so try that. – Remy Lebeau Mar 21 '17 at 21:58
  • @RemyLebeau Well, how do I include it then. It says: fatal error: string: No such file or directory – Luca van der knaap Mar 21 '17 at 21:59
  • @Lucavanderknaap: `std::string` and `` are part of the STL. If there is no STL on Arduino, they you can't use them. Sounds like you will have to resort to old C-style `char[]` string handling. – Remy Lebeau Mar 21 '17 at 22:00
  • @RemyLebeau I looked it up and there indeed is no STL on arduino. Thanks anyway ;) – Luca van der knaap Mar 21 '17 at 22:03
0

With a quick google search of a similar problem, I discovered an example of how to convert a string IP address into numbers with the following code:

std::string ip ="192.168.1.54";
std::stringstream s(ip);
int a,b,c,d; //to store the 4 ints
char ch; //to temporarily store the '.'
s >> a >> ch >> b >> ch >> c >> ch >> d;

However, since your problem is "slightly" different, you could do the following:

std::string givenExample = "1:171,54,201"

//Since it is known that the value will be 1-6, just take
//the ASCII value minus 30 hex (or '0') to get the actual value.
int firstNumber = ((int)givenExample.at(0) - 0x30); //or minus '0'

givenExample.erase(0, 2); //Remove "1:" from the string

std::stringstream s(givenExample);
int secondNumber, thirdNumber, fourthNumber;
char ch;
s >> secondNumber >> ch >> thirdNumber >> ch >> fourthNumber;

However, if you compare the first example to the second, the ip string is in almost the same format as your example: 4 ints separated by chars. So both will work, depending on which one makes more sense to you.

As far as how you are going to be reading that data in (Dealing with the carriage return), that depends on your interface to the serial data stream received from Arduino.

Community
  • 1
  • 1
Trevor
  • 366
  • 2
  • 11
  • `int firstNumber = (int)givenExample.at(0);` will make firstNumber contain 49 is the 1st char is '1'. Extract number `48` from it (or '0') – Fureeish Mar 21 '17 at 21:46
  • Good call, thank you! I've updated my answer. – Trevor Mar 21 '17 at 21:48
  • Unfortunately there is no STL on arduino so I can't use this. Thanks anyway – Luca van der knaap Mar 21 '17 at 22:04
  • @Trevor: "*However, since your problem is "slightly" different*" - how so? The IP example extracts 4 `.`-delimited numbers. The OP wants to extract 4 delimited numbers, just with different delimiters. So your whole `firstNumber` example is a bit overkill when the IP example with work the same with those different delimiters. – Remy Lebeau Mar 21 '17 at 22:04