Arduino string comparison not working when using String str_out = String((char*)buf); - c++

I am successfully receiving data over RF on a second Arduino. However I am trying to compare the incoming string so that I can call a method when there is a match. The "if" block is never executed. I am just trying to compare the strings that are incoming. It's printing the correct values to the serial monitor but the block is never executed. Maybe because this is using a pointer to a string (don't shoot me)? I am not that familiar with C or C++. I have tried several of the string comparison methods in the Arduino docs but no joy? Any reccomendations?
void loop()
{
// Set buffer to size of expected message
uint8_t buf[7];
uint8_t buflen = sizeof(buf);
// Check if received packet is correct size
if (rf_driver.recv(buf, &buflen))
{
// Message received with valid checksum
Serial.print("Message Received: ");
String str_out = String((char*)buf);
Serial.println(str_out); /
if (str_out == "plasma1") { // this is never executed wtf!!!
plasmaSequenceOne();
} else if (str_out == "plasma2") {
plasmaSequenceTwo();
} else if (str_out == "plasma3") {
plasmaSequenceThree();
} else if (str_out == "plasma4") {
plasmaSequenceFour();
}
}
}

Making Alex' self-response easier readable, and avoiding unnecessary String objects:
uint8_t buf[8];
uint8_t buflen = sizeof(buf)-1; // leave space for terminating 0
if (rf_driver.recv(buf, &buflen)) {
buf[buflen] = 0;
char* str_out = (char*)buf;
Serial.println (str_out);
if (strcmp(str_out, "plasma1")==0) plasmaSequenceOne();
...
}
This worked, thanks to #Remy Lebeau.

Related

Incoming values to serial port are sometime corrupted or missing

I have written simple bluetooth transmitter and receiver on two arduino nano v3 boards. Bluetooth modules are HM-10 connected into hardware serial ports. It works, but on receiver side I often receive corrupted values and many values are missing. Where is a problem:
I am beginner in arduino. If it is possible a need to explain deeply. Thanks.
Transmitter code:
const long waitingInterval = 20000;
unsigned long lastSend = micros();
void setup()
{
Serial.begin(19200);
Serial.println("Started");
}
bool delay() {
if(micros() >= lastSend + waitingInterval) {
lastSend = micros();
return true;
}
return false;
}
void loop()
{
if(delay()) {
String mil = String(millis());
String sendingText = mil + ";" + mil + ";" + mil + ".";
Serial.println(sendingText);
}
}
Output of transmitter serial monitor interface:
10548;10548;10548.
10568;10568;10568.
10589;10589;10589.
10609;10609;10609.
10629;10629;10629.
10649;10649;10649.
10670;10670;10670.
10690;10690;10690.
10711;10711;10711.
10730;10730;10730.
10750;10750;10750.
10771;10771;10771.
10791;10791;10791.
10812;10812;10812.
10831;10831;10831.
10852;10852;10852.
10872;10872;10872.
10893;10893;10893.
10913;10913;10913.
10933;10933;10933.
10953;10953;10953.
10974;10974;10974.
10994;10994;10994.
11014;11014;11014.
11034;11034;11034.
11055;11055;11055.
11075;11075;11075.
11096;11096;11096.
11115;11115;11115.
Receiver code:
void setup() {
Serial.begin(19200);
Serial.println("Started");
}
void loop() {
if(Serial.available()) {
String incomingData = String();
char incomingChar = Serial.read();
if(incomingChar == '.') {
incomingData = bufferString;
Serial.print(bufferString);
bufferString = String();
} else {
bufferString += String(incomingChar);
return;
}
}
Output of receiver serial monitor interface:
10548;10548;10548
10568;10568;10568
10589;10589;10589
10609;10609;10609
10629;10629;10629
106410771
10791;10791;10791
10812;10812;10812
10831;10831;10831
10852;10852;10852
10872;10872;10872
10893;10893;11034;11034;11034
11055;11055;11055
11075;11075;11075
11096;11096;11096
11115;11115;11115
One problem is simply calling Serial.available() simply returns the number of bytes available to be read in the buffer; it could be exactly the number of bytes you need, it could be less, or more. Because of this, you might read extra data, too little, or too much data. More so, in higher level transmission protocols sometimes after a device receives data it will send an ACK(acknowledgement) back to the sender, saying it is ready for more data.
Edit** It should also be noted that the comment talking about mutex's isn't correct. Mutexes are typically used to synchronize code across multiple threads of execution on the same device. The key is that they are a shared resource across the thread's heap space. This is NOT the case when using two different arduino devices; thus, even if you could use them, it would be useless.
For your code, I would suggest the following edits to the transmitter:
#define MIN_TIMEOUT 3
void recieveAck(){
bool validAck = false;
uint8_t timeout_cnt = 0x00;
while(timeout_cnt < MIN_TIMEOUT){
//Wait for receiving device to respond with two bytes then send next
char incomingBytes[2];
Serial.readBytes(incomingBytes, 0x02);
if(incomingBytes[0] == 0xBB && incomingBytes[1] == 0xCC)
break;
timeout_cnt++;
}
}
void loop()
{
if(delay()) {
String mil = String(millis());
String sendingText = mil + ";" + mil + ";" + mil + ".";
Serial.println(sendingText);
recieveAck();
}
}
And to the receiver:
#define NEXT_INC_SIZE 2 //Expects one byte at a time
void sendAck(){
char outData[2];
outData[0] = 0xBB;
outData[1] = 0xCC;
Serial.write(outData, 2); //Write the ack data
}
void loop() {
if(Serial.available() >= NEXT_INC_SIZE){
char incomingBytes[2];
Serial.readByte(incomingBytes, NEXT_INC_SIZE); //Read exactly how many bytes you need
//Do stuff with the data here....
sendAck();
}
}

How to store JSON Array in arduino program?

I was working on IOT project for which I needed JSON parsing in NodeMCU.
I saw this sample code for arduino for parsing JSON with the help of ArduinoJson library which worked well and I was able to get and parse the data from url(say url_1) successfully. Now I want to store this data in an array so that when I get data from the other ur2(say url_2) I can compare them with each other and trigger an event repective to the result.
Data in url_1 and url_2 is of form,
["1","1","1","1","0","0","0","0"]
and assume that url_1 had same values as specified.
What I did was I declared an array Data[] in which I stored the parsed JSON values so that I could use them later on in if else statements in the code.
As you can see that the data I am retrieving in url have 1's and 0's only, so what I want to do is that "If get 1 do this", "else do that", which you can see in the code. But the problem is that once I end the connection to the url the Data[] array gives only garbage values which I checked by printing them on serial monitor as shown in the code.
What I believe is that "const char* Data[20];" stores the position of JSON data and when I end the connection, the data at those position is also lost that's why I'm getting the garbage values. Now, I could be wrong since I'm new to this stuff. That's why I wanted to know how to solve this problem which is that if what I said was right, then how could I store the parsed json data in an array so that it is not lost even if the connection to the url has been ended.
(I'm new to this platform so If I did something wrong and wish that you guys can guide me for the future and I also apologize for my broken english).
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
const char* Data[20];
const char* ssid = "SSID";
const char* password = "Password";
//Connecting to WiFi
void setup() {
WiFi.mode(WIFI_OFF);
delay(1000);
WiFi.mode(WIFI_STA);// Hides the viewing of ESP as wifi Hotspot
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting...");
}
Serial.println("Connected to WiFi Successfully");
}
void loop()
{
if(WiFi.status()== WL_CONNECTED)
{
HTTPClient http;
//Starting connection to url_1
http.begin("url_1");
int httpCode = http.GET();
if(httpCode > 0)
{
String data = http.getString();
const size_t bufferSize = JSON_ARRAY_SIZE(8) + 20;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonArray& root = jsonBuffer.parseArray(data);
for(int i=0;i<8;i++){
Data[i] = root[i];
Serial.println("Printing whole Data");
Serial.println(Data[i]);
}
}
http.end();//ending the connetion
for(int i=0;i<8;i++)
{
if(strcmp(Data[i],"1")==0){
Serial.print("if satement, Data = ");
Serial.println(Data[i]);
}
else
{
Serial.print("else satement, Data = ");
Serial.println(Data[i]);
}
}
}
}
Data[] contains pointers to dynamically allocated strings. When you leave the code block with the JSON parser, its destructor is called and therefore the allocated memory can and has been overwritten by something else.
I would suggest to use instead
bool Data[...];
...
// true for "1", false for "0"
Data[i] = strcmp(root[i], "1") == 0;
...
EDIT if you need to store more "complicated" data, e.g. actual strings, you will need to make a copy of the string pointed to by root[i].

parsing complete messages from serial port

I am trying to read complete messages from my GPS via serial port.
The message I am looking for starts with:
0xB5 0x62 0x02 0x13
So I read from the serial port like so
while (running !=0)
{
int n = read (fd, input_buffer, sizeof input_buffer);
for (int i=0; i<BUFFER_SIZE; i++)
{
if (input_buffer[i]==0xB5 && input_buffer[i+1]== 0x62 && input_buffer[i+2]== 0x02 && input_buffer[i+3]== 0x13 && i<(BUFFER_SIZE-1) )
{
// process the message.
}
}
The problem I am having is that I need to get a complete message. Half of a message could be in the buffer one iteration. And the other half could come into the message the next iteration.
Somebody suggested that free the buffer up from the complete message. And then I move the rest of data in the buffer to the beginning of the buffer.
How do I do that or any other way that make sure I get every complete selected message that comes in?
edit//
I want a particular class and ID. But I can also read in the length
To minimize the overhead of making many read() syscalls of small byte counts, use an intermediate buffer in your code.
The read()s should be in blocking mode to avoid a return code of zero bytes.
#define BLEN 1024
unsigned char rbuf[BLEN];
unsigned char *rp = &rbuf[BLEN];
int bufcnt = 0;
static unsigned char getbyte(void)
{
if ((rp - rbuf) >= bufcnt) {
/* buffer needs refill */
bufcnt = read(fd, rbuf, BLEN);
if (bufcnt <= 0) {
/* report error, then abort */
}
rp = rbuf;
}
return *rp++;
}
For proper termios initialization code for the serial terminal, see this answer. You should increase the VMIN parameter to something closer to the BLEN value.
Now you can conveniently access the received data a byte at a time with minimal performance penalty.
#define MLEN 1024 /* choose appropriate value for message protocol */
unsigned char mesg[MLEN];
while (1) {
while (getbyte() != 0xB5)
/* hunt for 1st sync */ ;
retry_sync:
if ((sync = getbyte()) != 0x62) {
if (sync == 0xB5)
goto retry_sync;
else
continue; /* restart sync hunt */
}
class = getbyte();
id = getbyte();
length = getbyte();
length += getbyte() << 8;
if (length > MLEN) {
/* report error, then restart sync hunt */
continue;
}
for (i = 0; i < length; i++) {
mesg[i] = getbyte();
/* accumulate checksum */
}
chka = getbyte();
chkb = getbyte();
if ( /* valid checksum */ )
break; /* verified message */
/* report error, and restart sync hunt */
}
/* process the message */
switch (class) {
case 0x02:
if (id == 0x13) {
...
...
You can break the read into three parts. Find the start of a message. Then get the LENGTH. Then read the rest of the message.
// Should probably clear these in case data left over from a previous read
input_buffer[0] = input_buffer[1] = 0;
// First make sure first char is 0xB5
do {
n = read(fd, input_buffer, 1);
} while (0xB5 != input_buffer[0]);
// Check for 2nd sync char
n = read(fd, &input_buffer[1], 1);
if (input_buffer[1] != 0x62) {
// Error
return;
}
// Read up to LENGTH
n = read(fd, &input_buffer[2], 4);
// Parse length
//int length = *((int *)&input_buffer[4]);
// Since I don't know what size an int is on your system, this way is better
int length = input_buffer[4] | (input_buffer[5] << 8);
// Read rest of message
n = read(fd, &input_buffer[6], length);
// input_buffer should now have a complete message
You should add error checking...

Reading on serial port returns what i just wrote

I just started a project where i'm struggling since days now about serial ports. I wrote a static library that can handle all the serial routine and give an interface with "readLine()" and "writeLine()" functions.
Everything works flawlessly on the write and read (which are threaded by the way) except if the slave does not anwser after he gets the data, then, the data is sent back to me, and i read it.
I open my fd with O_NDELAY and configure my read system call as Non blocking with fcntl.
here are the two threaded loops that work perfectly beside that.
void *Serial_Port::readLoop(void *param)
{
Serial_Port *sp = static_cast<Serial_Port*>(param);
std::string *line = NULL;
char buffer[128];
while (1)
{
line = new std::string();
while ((line->find("\r\n")) == std::string::npos)
{
usleep(100);
bzero(buffer, 128);
pthread_mutex_lock(sp->getRLock());
if (read(sp->getDescriptor(), buffer, 127) > 0)
*line += buffer;
pthread_mutex_unlock(sp->getRLock());
}
pthread_mutex_lock(sp->getRLock());
sp->getRStack()->push(line->substr(0, line->find("\r\n")));
pthread_mutex_unlock(sp->getRLock());
delete (line);
}
return (param);
}
void *Serial_Port::writeLoop(void *param)
{
Serial_Port *sp = static_cast<Serial_Port*>(param);
std::string *line;
while (1)
{
line = NULL;
pthread_mutex_lock(sp->getWLock());
if (!sp->getWStack()->empty())
{
line = new std::string(sp->getWStack()->front());
sp->getWStack()->pop();
}
pthread_mutex_unlock(sp->getWLock());
if (line != NULL)
{
pthread_mutex_lock(sp->getWLock());
write(sp->getDescriptor(), line->c_str(), line->length());
// fsync(sp->getDescriptor());
pthread_mutex_unlock(sp->getWLock());
}
usleep(100);
}
return (param);
}
I tried to flush the file descriptor, but i can't manage to receive any data after doing that. How can I get rid of that duplicate, needless data?
Thanks.
After multiple tests and behavior analysis, I discovered it was the "Pulsar3" (the device i was using on serial) that kept giving me back what i sent as "Acknowledge". Nice to know!

Trouble with boolean value returning twice (Arduino)

I'm working with a project that involves a Arduino UNO card and JAVA. The Arduino UNO would be the client and JAVA the server.
The problem is that my verify function is returning 0 twice when it's false, why does it do that and if true it returns 1 and 0 which is weird.
I just want it to return once, and not false false like the example here:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0x50, 0x35 };
IPAddress arduino(192,168,0,12);
IPAddress server(192,168,0,15);
EthernetClient client;
String username[] = {"Admin","Skut","Arbek","Kubda"};
String password[] = {"12344","stra","124ssgra","!#ยค%"};
String readString;
void setup() {
Serial.begin(9600);
Ethernet.begin(mac,arduino);
Serial.println("Connecting...");
if (client.connect(server, 8888)){
Serial.println("Connected to Server");
}
else {
Serial.println("Connecting failed");
}
}
boolean verify(String firstText, String secondText){
for(int i = 0; i <= 3 ; i++){
if((username[i] == firstText ) && (password[i] == secondText)){
return true;
}
}
return false;
}
void clientRead() {
while (client.available()) {
//delay(10);
if (client.available() >0) {
char c = client.read();
readString += c;
}
}
}
void loop(){
if (client.available() > 0){
readString = "";
clientRead();
Serial.println(readString);
int n = readString.length();
int commaIndex = readString.indexOf(';');
int lastIndex = readString.lastIndexOf(n);
String firstText = readString.substring(0, commaIndex);
String secondText = readString.substring(commaIndex + 1 , lastIndex);
Serial.println(firstText);
Serial.println(secondText);
Serial.println(verify(firstText, secondText));
}
if (!client.connected()){
Serial.println("Server disconnected!");
client.stop();
client.flush();
while(true);
}
}
I've tried sending ( Admin;12344 ) to the arduino from the server and this is what I get:
Connecting...
Connected to Server
Admin;12344
Admin
12344
1
0
while (client.available())
is not reliable. It might terminate earlier than what you expect depending on the relative speed of the device. Most probably you are getting partial data on the first try and another batch on second one (probably only \n). Instead of relying on available, use a marker to end the data.
The problem lies with what is being sent. If you look at the hex values of your output you will notice 7 CRLF between the 1 and 0. One of those belongs to the println of 1. The next 6 is exactly the output of 3 println. What is being printed 3 times? One CRLF, thats all. Because of the way you do the substrings all three outputs:
Serial.println(readString);
Serial.println(firstText);
Serial.println(secondText);
will print the very same CRLF along with their respective CRLF of the println.
So your answer is that you are sending a CRLF at the end of the line which is sent to the Arduino. Consider Cem Kalyoncu's answer about how to properly handle the reading and also do not send a CRLF to the Arduino at the end of the authentication line and you will most probably be fine.
I also suggest you read up on why not to use String in arduino. It is a world of memory and space problems you bring forth if you keep on using it.
Instead of if((username[i] == firstText ) && (password[i] == secondText)), try to use if(( firstText.equals(username[i]) ) && ( secondText.equals(password[i]) ))
I think the == don't compare the value of strings.