Capturing serial input in string/char array - c++

I have a software serial link between an Arduino Uno and a TC35 GSM Module to send and receive SMS messages. Sending SMS'/calls is not a problem as it is a matter of sending the appropriate AT command to the GSM module. However I wish to use the AT+CMGR=1 command (which checks the first SMS stored on the SIM card) to check if there is any messages and store the message as a char array so that I can then check if the SMS contains the word 'on' or 'off' to activate a LED.
The AT+CMGR=1 command should return the following:
AT+CMGR=1
+CMGR: "REC READ","+3538xxxxxxxx",,"13/03/23,14:29:37+00"
Set
OK
But in the method below when I print 'data' it just returns:
Message contains:
AT
Any pointers would be much appreciated.
void checkMessage() {
gsmSerial.println("AT+CMGR=1"); //Reads the first SMS
for (x=0;x < 255;x++){
data[x]='\0';
}
x=0;
do{
while(gsmSerial.available()==0);
data[x]=gsmSerial.read();
x++;
if(data[x-1]==0x0D&&data[x-2]=='"'){
x=0;
}
}while(!(data[x-1]=='K'&&data[x-2]=='O'));
data[x-3]='\0'; //finish the string before the OK
Serial.println("\r\nMessage contains: \r");
Serial.println(data); //shows the message
delay(1000);
}

I don't understand your intent of doing this:
if(data[x-1]==0x0D&&data[x-2]=='"'){
x=0;
}
It appears you're discarding your data and reading new data whenever you hit a line containing a trailing quote and newline. So the response to the command of interest is being discarded. I haven't tested it, but I think it would work if you deleted those three lines.
I should also mention that [x-1] and [x-2] are referencing memory prior to the data buffer. That's a very bad practice that can and will cause undefined behavior. You should only check the index minus some value when the result of that computation will be a positive value. A negative array index will access memory prior to the start of the array.

Related

Weird output for RGB

I am trying to manage some LED strips with my mobile device using bluetooth + Adafruit NeoPixel. I almost had the sketch finished but I have found the numbers for RGB are not appearing as I expected and I cannot find what I am doing wrong.
Imagine that from my mobile I have sent the following RGB code "0,19,255", when I check the console I see the following result:
As you can see the first two lines are ok, but the third one we can see 2550. The 0 should no be there and I cannot figure it out the problem.
So I decided isolate the code and try to keep the minimum to identify the root cause and this is the code:
#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
SoftwareSerial BT (10, 11);
#define PIN 2
#define NUMPIXELS 144
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRBW + NEO_KHZ800);
int red = "";
void setup() {
Serial.begin(9600);
Serial.println("Ready");
BT.begin(38400);
pixels.begin();
pixels.show();
pixels.setBrightness(20);
}
void loop() {
while (BT.available()>0){
red = BT.parseInt();
Serial.println(red);
}
}
You describe that for the shown output you sent via mobile "0,19,255".
Yet in the shown output that obviously is only the second part of a longer sequence of numbers sent, which starts with "0,21".
Assuming that what you send is always of the format you have described, i.e. three numbers, separated by two ",", the shown output is most likely the result of you sending first "0,21,255" and then another triplet "0,19,255".
These two messages together would end up in an input buffer "0,21,2550,19,255".
Now I have to do some speculation. Most parsers, when told to look for numbers within the buffer, will look for digits followed by non-digits. They would end up yielding "0,21,2550".
Without knowing details of the parsers working it is hard to say how to fix your problem.
I would however definitly experiment with sending triplets which end in a non-digit.
For example:
"0,21,255,"
or
"0,21,255 "
or
"0,21,255;"
If none of them work you might need to explicitly expect the non-digit, i.e. between triplets of numbers read a character and either ignore it or compare it to " ,", " " or ";" for additional self-checking features.
(Writing this I rely on user zdf not intending to make an answer, because while I did spot the "2550" as "255""0", zdf spotted the only two "," inside the question body in sample input, which I missed. I will of course adapt my answer to one created by zdf, to not use their contribution without their consent.)

in c++ program after pressing enter , "cin" will feed all Variables

I have a program that takes two numbers and shows them on the screen.
However, when I hit "enter" after I input the first number, my program shows the answers before letting me input the second number.
Why does this happen?
int main()
{
int n1;
float n2;
cin>>n1;
cin>>n2;
cout<<"int n:"<<n1<<endl<<"float n:"<<n2;
return 0;
}
I wanna input 0.25 and 35 but when I write 0.25 and hit enter suddenly shows the answer "int: n:0 float n:0.25" it doesn't let me write second num. my os is Win10 and this program compiled with DevCpp
It works when both variables are ints.
There is no difference between cin>>n1; cin>>n2; and cin >> n1 >>n2. Enter key only serves as signal to sychronize input buffer and stream buffer. cin doesn't input per line, it parses buffer when there is available volume of data. If parse incomplete, it waits. If parse can't be done, it stops and state bit changes. To continue parsing you have either ignore or clear part or whole buffer content.
Something wrong was entered in first line, causing cin to go into bad() state. Edge case might happen if you're running program through a remote terminal, some incorrect character could slip in, e.g. ^M generated by new line from Windows would break cin stream on Linux. That's also case if you input from a file which was saved on different platform. On Windows line ends consist of two characters, #10 and #13. On linux steams expect only #13 as a new line and buffer flush signal, #10 is an unexpected character.
Edit (after OP gave information about input data):
"0.25" would be parsed as "0" and ".25", that expected and documented stream behavior. Parsing for n1 had stopped as soon as stream encountered character which doesn't fit int pattern, which could be space, end of line, alphabetic or punctuation. Period considered a punctuation in this case
Then it tries to get a float from stream input and buffer contains ".25". It's a legal float notation and it gets assigned to n2.
When you have both "int", you cannot get second value at all with same input, it always will be 0, because cin locks up in bad state, i.e. method its istream::good() returns false. You have to check state of stream after reading variables. Any further formatted reading that wouldn't be able to parse .25 wouldn't advance stream past that point.
If you want to read from stream exclusively line by line, you have to use istream::getline() method to get the string. There is also method get which can acquire content of stream and ignore which allows to discard part of stream.

Arduino c++ First letter of string missing

I'm receiving a string from one serial port and repeating to a second serial port. The following code works, but the first letter (number 4 in this case) of the string is missing.
while(Serial1.available()){
MyString = Serial1.readString();
}
client.print(MyString);
The end result is "192A4BF,0,3.999023" when it should be "4192A4BF,0,3.999023"
You're reading from Serial1 in a loop, overwriting all strings that you receive except for the last one. What likely happens is that you first read — and discard — 4 and then read — and print — the rest.
Moving the print into the loop should fix this:
while(Serial1.available()){
MyString = Serial1.readString();
client.print(MyString);
}

C++ serial communication in Linux

I am trying to send data from my BeagleBone black board to Arduino Uno. The baud rate I have selected is 300. I am using the serialib library which is located here: http://serialib.free.fr/html/classserialib.html#ac8988727fef8e5d86c9eced17876f609 you can scroll all the way to the bottom to view the two files (serialib.h and serialib.cpp), however I have posted the main snippets here too. I read some reviews saying that this library is not reliable however I would first want to check my code before really suspecting anything else.
This is the program I have written in C++ on my BeagleBone:
#include <iostream>
#include "serialib.h"
#ifdef __linux__
#define DEVICE_PORT "/dev/ttyO1"
#endif
using namespace std;
int main()
{
serialib LS; //the main class to access
int Ret;
Ret= LS.Open(DEVICE_PORT,300);
if (Ret!=1)
{
cout<<"cant open port\n";
return 0;
}
else{cout<<"port now open \n";}
string xval="650X450Y";
for(int i=0;i<500;i++)//send xval 500 times
{
for(int j=0;j<xval.length();j++)//send each character separately
{
Ret=LS.WriteChar(xval[j]);
LS.Close();
LS.Open(DEVICE_PORT,300);
}
if (Ret!=1){cout<<"cannot write\n";}
else{cout<<"done writing\n";}
}
LS.Close();
cout<<"Transmission complete\n";
}
My code on the Arduino Uno is as follows:
#include <SoftwareSerial.h>
SoftwareSerial uart(10,11);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); //baud rate for Serial communication
uart.begin(300);
}
char x;
String data="";
void loop()
{
if(uart.available()>0)//check if data is coming in
{
while(uart.available())
{
x=uart.read();//read the incoming byte
data+=x;//append the string with incoming bytes
}
if(x=='Y')//received all the bits
{
Serial.println(data); //display received information
}
}
}
C++ - I am first opening up my UART port on the BeagleBone and sending the string "650X450Y" character by character which is repeated 500 times to see if my communication system is robust or not. As you can see that within the 'for' loop I am closing and opening this port after sending every character because without this, it sends quite a lot of wrong data and if this 'for' loop is very big then the writing process even stops (not sure why it behaves like that) thus after closing and opening this port every time, I have managed to reduce the errors significantly but there are still a few errors:
I sent this string 500 times but one sample I received on the Uno was "660X450Y", wrong value.
About 2-3 times out of 500, I am receiving "650X450Y650X450Y650X450Y" i.e. repetitions, this is definitely not the string length then how come it can send this data?.
The rest of the strings I received on the Uno are perfect.
On the Uno as you can see that I am reading in character by character and appending it to my string named data and printing out this data as soon as the byte 'Y' is detected which denotes the end of the string. I previously used the WriteString() function in my C++ code however that gave a number of errors, The code I have provided is the closest I have come so far in the last few days to make this system 100% reliable and robust after lots of debugging, however I'm really not sure why the system is still not 100%.
I saw the source code of both the files in the library and observed the WriteChar(char Byte) function which is defined at line 210 in serialib.cpp (link already provided above) and I see that this is the function transmitting the characters:
if (write(fd,&Byte,1)!=1) // Write the char
return -1; // Error while writting
return 1; // Write operation successfull
I don't see anything wrong with this function then why can't I receive the data with 100% accuracy, Is there anything wrong in both my source codes or either one?, should I opt for a different serial library?, in case I opt for other libraries and I still don't get my results then I think I may have to transmit this info in a wireless manner for e.g using bluetooth modules. If anyone has any suggestions/improvements regarding this problem then do let me know :), till then I'll try other methods to achieve a 100% accuracy.
The easiest just to check if quickly can be done in the linux terminal and no library is used for that.
Set the baudrate to 300 for the UART1 (stty -F /dev/ttyO1 raw & stty -F /dev/ttyO1 300)
You can sent data to the UART1 simply by writing(or reading) to the device file for the UART1 which is in your case /dev/ttyO1
Writing: echo "650X450Y" > /dev/ttyO1
Reading: cat /dev/ttyO1
If you want to do this in C Code you can use the open/read/write/close syscall functions.

Arduino substring doesn't work

I have a static method that searches (and returns) into String msg the value between a TAG
this is the code function:
static String genericCutterMessage(String TAG, String msg){
Serial.print("a-----");
Serial.println(msg);
Serial.print("b-----");
Serial.println(TAG);
if(msg.indexOf(TAG) >= 0){
Serial.print("msg ");
Serial.println(msg);
int startTx = msg.indexOf(TAG)+3;
int endTx = msg.indexOf(TAG,startTx)-2;
Serial.print("startTx ");
Serial.println(startTx);
Serial.print("endTx ");
Serial.println(endTx);
String newMsg = msg.substring(startTx,endTx);
Serial.print("d-----");
Serial.println(newMsg);
Serial.println("END");
Serial.println(newMsg.length());
return newMsg;
} else {
Serial.println("d-----TAG NOT FOUND");
return "";
}
}
and this is output
a-----[HS][TS]5132[/TS][TO]5000[/TO][/HS]
b-----HS
msg [HS][TS]5132[/TS][TO]5000[/TO][/HS]
startTx 4
endTx 30
d-----
END
0
fake -_-'....go on! <-- print out of genericCutterMessage
in that case I want return the string between HS tag, so my expected output is
[TS]5132[/TS][TO]5000[/TO]
but I don't know why I receive a void string.
to understand how substring works I just followed tutorial on official Arduino site
http://www.arduino.cc/en/Tutorial/StringSubstring
I'm not an expert in C++ and Arduino but this looks like a flushing or buffering problem, isn't it?
Any idea?
Your code is correct, this should not happen. Which forces you to consider the unexpected ways that this could possibly fail. There is really only one candidate mishap I can think of, your Arduino is running out of RAM. It has very little, the Uno only has 2 kilobytes for example. It doesn't take a lot of string munching to fill that up.
This is not reported in a smooth way. All I can do is point you to the relevant company page. Quoting:
If you run out of SRAM, your program may fail in unexpected ways; it will appear to upload successfully, but not run, or run strangely. To check if this is happening, you can try commenting out or shortening the strings or other data structures in your sketch (without changing the code). If it then runs successfully, you're probably running out of SRAM. There are a few things you can do to address this problem:
If your sketch talks to a program running on a (desktop/laptop) computer, you can try shifting data or calculations to the computer, reducing the load on the Arduino.
If you have lookup tables or other large arrays, use the smallest data type necessary to store the values you need; for example, an int takes up two bytes, while a byte uses only one (but can store a smaller range of values).
If you don't need to modify the strings or data while your sketch is running, you can store them in flash (program) memory instead of SRAM; to do this, use the PROGMEM keyword.
That's not very helpful in your specific case, you'll have to look at the rest of the program for candidates. Or upgrade your hardware, StackExchange has a dedicated site for Arduino enthusiasts, surely the best place to get advice.