I am trying to read Serial data on Arduino Mega 2560 using built in String object but its not printing the Serial data when used inside a FreeRTOS task like following code
void TaskSerialIn(void *pvParameters)
{
String json;
for(;;) {
while(Serial.available()) {
json = Serial.readStringUntil('\n');
Serial.println(json); // this code not printing anything
}
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
It doesn't work even if I declare the String as global variable.
Whereas the following code works when character array is used to store the bytes
char serialJson[65];
void TaskSerialIn(void *pvParameters)
{
char * jsonStr;
int i = 0;
for(;;) {
i = 0;
while(Serial.available()) {
char inChar = (char) Serial.read();
serialJson[i++] = inChar;
if(inChar == '\n') {
serialJson[i] = '\0';
Serial.print(serialJson);
}
}
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
Any help would be appreciated on how could I use String to read the Serial data.
Related
A server in java, sends from a Server socket a byte array, this byte array contains text (utf-8) with the next format:
first 4 bytes: an int with the number of bytes of the text
next n
bytes: each byte represents a char.
So i am using "WiFiClient" from the "ESP8266WiFi.h" library (it should be the same as "WiFi.h" library), WifiClient has a method to receive a byte using the read() method, the problem is that i am unable to read correctly the int (first four bytes) or transform the bytes into int value. So i will be very gratefull if you help me with that:
Java (Server) simplified code:
String respuestaServer="RESPUESTAS DEL SERVER";
DataOutputStream out=new DataOutputStream(sock.getOutputStream());
out.writeInt(respuestaServer.getBytes(StandardCharsets.UTF_8).length);
out.write(respuestaServer.getBytes(StandardCharsets.UTF_8));
out.flush();
Arduino (Client) code to receive and interpret the byte array (the objective of this code is transform the bytes into a String):
String recibirInfo() {
//TRYING TO READ FIRST FOUR BYTES
byte bytesSizeMsj[4];
for (int i = 0; i < sizeof(bytesSizeMsj); i++) {
bytesSizeMsj[i] = client.read();
Serial.print("BYTE: "+bytesSizeMsj[i]);
}
//TRYING TO TRANSFORM THE FOUR BYTES INTO AN INT
int sizeMsj = int((unsigned char)(bytesSizeMsj[0]) |
(unsigned char)(bytesSizeMsj[1]) |
(unsigned char)(bytesSizeMsj[2])|
(unsigned char)(bytesSizeMsj[3]));
Serial.println(sizeMsj);
char charArray[sizeMsj];
//TRYING TO READ THE REST OF THE MESSAGE
for (int i = 0; i < sizeof(charArray); i++) {
charArray[i] = client.read();
}
//TRYING TO TRANSFORM THE BYTE ARRAY INTO A STRING
String msj=charArray;
return msj;
}
I fix it, i had problems with the way I read from the socket, the way I transform the 4 bytes into an Int datatype and with the way I transoform the bytes into a String, I figure out why i was not receiving all the bytes when trying to read from the socket, the reason was that when I call the method "client.read()" the server was not fast enought to send the information so it did not read anything, so I did a loop and with help of the method "client.available()" I checked that there was a byte ready to be read, so the loop ends when the first 4 bytes were read. Then I transform the 4 bytes readed into an Int, read the rest of the bytes in a similar way than before, and I tranformed the bytes into a String.
Here is my functional code:
String recibirInfo(bool* error) {
String msj = "";
byte bytesSizeMsj[4];
for (int i = 0; i < sizeof(bytesSizeMsj); i++) {
if (client.connected()) {
if (client.available()) {
bytesSizeMsj[i] = client.read();
} else {
delay(10);
i--;
}
} else {
*error = true;
return "";
}
}
//TRANSFORMAR LOS 4 BYTES A INT
int sizeMsj = 0;
sizeMsj = ((int)bytesSizeMsj[3]) | sizeMsj;
sizeMsj = ((int)bytesSizeMsj[2]) << 8 | sizeMsj;
sizeMsj = ((int)bytesSizeMsj[1]) << 16 | sizeMsj;
sizeMsj = ((int)bytesSizeMsj[0]) << 24 | sizeMsj;
char charArray[sizeMsj];
//LEER EL TEXTO
for (int i = 0; i < sizeof(charArray); i++) {
if (client.connected()) {
if (client.available()) {
charArray[i] = client.read();
} else {
delay(250);
i--;
}
} else {
*error = true;
return "";
}
}
//TRANSFORMAR BYTES A STRING
msj = charArrayToString(charArray, sizeMsj);
Serial.print("RECIBIDO: ");
Serial.println(msj);
return msj;
}
String charArrayToString(char arrChar[], int tam) {
String s = "";
for (int i = 0; i < tam; i++) {
s = s + arrChar[i];
}
return s;
}
It's kinda of hard to trouble shoot like this do you actually receive data ? Can you show the output you get ? Maybe you aren't even connected.
Also what i've done in the past is convert every int or "letter" into a char. Since i usually send a message of known lenght with a starting char i read every byte of my message and convert it to a char and then add it to my received message string. I dont know if this helps... Basically i do the conversion on the arrival of the byte.
Before someone flags this as duplicate I have found these two links and neither totally apply although I have implemented at least a little of both.
Buffer gets overwritten
Arduino reading json from EEPROM / converting uint8_t to char
My problem is this. I am trying to read and write a JSON string to an Arduinos EEPROM using ArduinoJson library (https://github.com/bblanchon/ArduinoJson). In the below code I generate a JsonObject from a hard coded JSON string (this works). I then write it to EEPROM (this works). It then gets read back from EEPROM (this works) but when I try and parse the second string using ArduinoJSON i get a parse failure.
For the purpose of testing I also clear the EEPROM each time just in case although eventually this will be removed.
The code compiles with no errors. I am hoping that someone more knowledgable in C++ than myself will spot something really obvious. I am compiling this onto a NodeMCU (esp8266).
#include <ArduinoJson.h>
#include <EEPROM.h>
StaticJsonBuffer<400> jsonBuffer;
JsonObject *jsonObject;
JsonObject *config;
String dummyJson = "{\"name\":\"RGB LED 1\",\"io\":[\"pwm1\",\"pwm2\",\"pwm3\"],\"io_type\":\"output\",\"device\":\"pwm_output\",\"uuid\":\"5a81f424aaf8d1e951ae78d270668337\",\"ip\":\"255.255.255.255\"}";
void setup()
{
Serial.begin(9600);
while (!Serial)
{
continue;
}
EEPROM.begin(512);
Serial.println("\n\n");
clearEEPROM();
createDummyJsonObject();
writeJsonToEEPROM();
readJsonFromEEPROM();
}
void createDummyJsonObject()
{
jsonObject = &jsonBuffer.parseObject(dummyJson);
if (!jsonObject->success())
{
Serial.println("jsonBuffer.parseObject() failed");
return;
}
else
{
Serial.println("JSON object generated from dummy string");
jsonObject->prettyPrintTo(Serial);
Serial.println("\n\n");
}
}
void loop()
{
// not used
}
void clearEEPROM()
{
for (int i = 0; i < 512 + 1; i++)
{
EEPROM.write(i, 0);
}
EEPROM.commit();
}
void writeJsonToEEPROM()
{
String jsonStr;
jsonObject->printTo(jsonStr);
for (int i = 0; i < jsonStr.length(); ++i)
{
EEPROM.write(i, jsonStr[i]);
}
EEPROM.write(jsonStr.length(), byte(0));
EEPROM.commit();
}
void readJsonFromEEPROM()
{
String jsonStr;
for (int i = 0; i < 512; ++i)
{
char c = char(EEPROM.read(i));
if (c != 0)
{
jsonStr += c;
delay(1);
}
else
{
break;
}
}
Serial.println(jsonStr);
char charBuf[jsonStr.length()];
jsonStr.toCharArray(charBuf, jsonStr.length());
config = &jsonBuffer.parseObject(charBuf);
if (!config->success())
{
Serial.println("jsonObject.parseObject() failed ");
return;
}
else
{
// Never reaches this point!
Serial.println("\nJSON object generated from EEPROM data");
config->prettyPrintTo(Serial);
Serial.println("\n\n");
}
}
The size allocated for charBuf should be jsonStr.length() + 1 because you need space for a string terminator. Therefore you should also add something like charBuf[jsonStr.length()] = '\0'; to provide that string terminator:
int const jsonStringLengh = jsonStr.length();
char charBuf[jsonStringLengh + 1];
jsonStr.toCharArray(charBuf, jsonStringLengh);
charBuf[jsonStringLengh] = '\0';
Ok so this solved it. All I had to do was create a new StaticJsonBuffer for the second string parse. For anyone who is having a similar issue here's the working code.
#include <ArduinoJson.h>
#include <EEPROM.h>
StaticJsonBuffer<512> jsonBuffer;
JsonObject *jsonObject;
JsonObject *config;
String dummyJson = "{\"name\":\"RGB LED 1\",\"io\":[\"pwm1\",\"pwm2\",\"pwm3\"],\"io_type\":\"output\",\"device\":\"pwm_output\",\"uuid\":\"5a81f424aaf8d1e951ae78d270668337\",\"ip\":\"255.255.255.255\"}";
void setup()
{
Serial.begin(9600);
while (!Serial)
{
continue;
}
EEPROM.begin(512);
clearEEPROM();
createDummyJsonObject();
writeJsonToEEPROM();
readJsonFromEEPROM();
}
void createDummyJsonObject()
{
jsonObject = &jsonBuffer.parseObject(dummyJson);
if (!jsonObject->success())
{
Serial.println("jsonBuffer.parseObject() failed");
return;
}
else
{
Serial.println("JSON object generated from dummy string");
}
}
void loop()
{
// not used
}
void clearEEPROM()
{
for (int i = 0; i < 512 + 1; i++)
{
EEPROM.write(i, 0);
}
EEPROM.commit();
}
void writeJsonToEEPROM()
{
String jsonStr;
jsonObject->printTo(jsonStr);
for (int i = 0; i < jsonStr.length(); ++i)
{
EEPROM.write(i, jsonStr[i]);
}
EEPROM.write(jsonStr.length(), byte(0));
EEPROM.commit();
}
void readJsonFromEEPROM()
{
String jsonStr;
for (int i = 0; i < 512; ++i)
{
char c = char(EEPROM.read(i));
if (c != 0)
{
jsonStr += c;
delay(1);
}
else
{
break;
}
}
StaticJsonBuffer<512> jsonBuffer2;
config = &jsonBuffer2.parseObject(jsonStr);
if (!config->success())
{
Serial.println("jsonObject.parseObject() failed ");
return;
}
else
{
Serial.println("\nJSON object generated from EEPROM data");
config->prettyPrintTo(Serial);
Serial.println("\n\n");
}
}
Good day all!
I am working on a project with Arduino UNO and a SIM908.
I am trying to understand the AT command.
When I enter
Serial.print("AT")
Serial.println("AT+CGPSSTATUS?");
Serial retuen a value and I would like to save that value into a buffer
char buffer[size]
I do not want to have other string than the return value of an AT command.
I also red that document
SIM908 AT Command Manual_V1.01
At the page 13, you can read (NB. < CR>< LF> : I added a space after the first <, other there are not display)
The "AT" or "at" prefix must be set at the beginning of each Command
line. To terminate a Command line enter < CR>. Commands are usually
followed by a response that includes. "< CR>< LF>< CR>< LF>"
Throughout this document, only the responses are presented, < CR>< LF>
are omitted intentionally
Then, I am asking how I can "extract" the response between < CR>< LF> and < CR>< LF>
Looking at this exemple (let me know if I am wrong), how can I detect the < CR>< LF>
void setup()
{
char buffer[200];
Serial.println("AT+CGPSSTATUS?");
}
void loop()
{
if (Serial.available())
{
// HERE I SHOULD CHECK IF CR ANF LF
Serial.write(Serial.read());
// AND SAVE IT IN buffer. IS'T NOT?
}
}
}
Do you see what I means?
How could you help me to store in a buffer, only the return value of an AT command?
Many thank for your help
It's very interresting what you show me. Here is how I adapt my code
I adapted my code and by the way I created a file for testing Serail while we send a AT command.
The concern function are loop() and read_AT_string(). (I renamed the read_String to read_AT_string().
Here my code and I explain, after the issue, regardin your proposal
#include <SoftwareSerial.h>
int baud_rate = 9600;
int pin_gsm = 3;
int pin_gps = 4;
int pin_power = 5;
//int pin_dtr = 6;
boolean debug = true;
boolean raedy_to_go = false;
// Reading String
#define BUFFERSIZE 200
char buffer[BUFFERSIZE];
char inChar;
int index;
void setup()
{
Serial.begin(baud_rate);
delay(5000); // Wait for 5sec after begin
if(debug)
{
Serial.println(F("\n****************************"));
Serial.println(F("STARTING SYSTEM Read AT stream"));
Serial.println(F("******************************"));
}
pinMode(pin_gsm,OUTPUT); // Set the pins
pinMode(pin_gps,OUTPUT);
pinMode(pin_power,OUTPUT);
powerUpSim908:
if(powerUpSim908())
{
delay(1000);
if(gps_power()){
gsm_enable();
raedy_to_go = true;
if(debug)
{
Serial.println(F("\n****************************"));
Serial.println(F("READY TO GO\n"));
Serial.println(F("****************************\n"));
}
}
else
{
raedy_to_go = false;
if(debug)
{
Serial.println(F("\nNOT READY TO GO.\nGPS could not be power\nRestart the module\nor/and check the battery level.\n"));
}
goto powerUpSim908;
}
}
else
{
raedy_to_go = false;
if(debug)
{
Serial.println(F("\nNOT READY TO GO.\nCheck the battery level.\n"));
}
};
}
void loop()
{
/*
if (Serial.available())
{
Serial.print("Character received: ");
Serial.write(Serial.read());
Serial.println("");
}
*/
if(raedy_to_go)
{
read_AT_string("AT",5000);
delay(10000);
}
}
char read_AT_string(char* command, int timeout)
{
unsigned long previous;
previous = millis();
Serial.println(F("\nDISPLAY BUFFER:"));
index=0;
Serial.println(command);
do
{
if(Serial.available() > 0) // Don't read unless
// there you know there is data
{
Serial.println("1");
if (Serial.peek() == 13) // check if CR (without reading)
{
Serial.println("13");
if(Serial.available() > 0)
{
Serial.read(); // read and ignore
if (Serial.peek()==10) // then check if LF (without reading)
{
Serial.println("10");
if(index < Serial.readBytesUntil(13, buffer, BUFFERSIZE-1)) // One less than the size of the buffer array
{
Serial.println("b");
inChar = Serial.read(); // Read a character
buffer[index] = inChar; // Store it
index++; // Increment where to write next
buffer[index] = '\0'; // Null terminate the string
}
}
}
}
}
}while(((millis() - previous) < timeout));
Serial.println(buffer);
buffer[0]='\0';
Serial.println(F("END DISPLAY BUFFER"));
}
/* FUNCTION */
boolean powerUpSim908(void)
{
if(debug)
{
Serial.println(F("Powering up SIM908"));
}
boolean turnedON = false;
//uint8_t answer=0;
int cont;
for (cont=0; cont<3; cont++)
{
digitalWrite(pin_power,HIGH);
delay(1500);
digitalWrite(pin_power,LOW);
Serial.println(F("Checking if the module is up"));
if(sendATcommand("AT", "OK", 5000))
{
cont = 4; // Leave the loop
turnedON = true;
}
else
{
turnedON = false;
if(debug)
{
Serial.println(F("\nTrying agin to turn on SIM908"));
}
};
}
if(turnedON)
{
if(debug)
{
Serial.println(F("Module is tunrned up\n"));
}
}
else
{
if(debug)
{
Serial.println(F("Module is NOT tunrned ON\n"));
}
}
return turnedON;
}
boolean sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout)
{
uint8_t x=0;
bool answer=false;
//åchar response[100];
//buffer[0]='\0';
unsigned long previous;
//memset(response, '\0', 100); // Initialice the string
//Serial.println(response);
delay(100);
while( Serial.available() > 0) Serial.read(); // Clean the input buffer
if (ATcommand[0] != '\0')
{
Serial.println(ATcommand); // Send the AT command
}
x = 0;
previous = millis();
index=0;
do
{
if(Serial.available() > 0)
// there you know there is data
{
if(index < BUFFERSIZE-1) // One less than the size of the array // Same as buffer size
{
inChar = Serial.read(); // Read a character
buffer[index] = inChar; // Store it
index++; // Increment where to write next
//Serial.println(index);
buffer[index] = '\0'; // Null terminate the string
}
}
}while(((millis() - previous) < timeout));
if(strstr(buffer,"NORMAL POWER DOWN") != NULL)
{
answer = false;
}
else if (strstr(buffer, expected_answer) != NULL) // check if the desired answer (OK) is in the response of the module
{
/*
Serial.println(F("### BUFFER"));
Serial.println(buffer);
Serial.println(F("### END BUFFER"));
*/
answer = true;
}
else
{
answer = false;
}
if(debug)
{
if(answer)
{
//Serial.println(F("Expected answer : OK!\n"));
}
else
{
//Serial.println(F("Expected answer : KO!\n"));
};
}
return answer;
}
void gps_enable(void)
{
if(debug)
{
Serial.println(F("\nEnabling GPS ..."));
}
digitalWrite(pin_gps,LOW); //Enable GPS mode
digitalWrite(pin_gsm,HIGH); //Disable GSM mode
delay(2000);
}
void gsm_enable(void)
{
if(debug)
{
Serial.println(F("\nEnabling GSM ..."));
}
digitalWrite(pin_gsm,LOW); //Enable GSM mode
digitalWrite(pin_gps,HIGH); //Disable GPS mode
delay(2000);
}
/* UTILISTIES */
/* GPS */
boolean gps_power(void) //turn on GPS power supply
{
/*
Serial.println("AT");
delay(2000);
*/
boolean gpspwr = false;
boolean gpsrst = false;
if(sendATcommand("AT+CGPSPWR=1","OK",2000))
{
gpspwr = true;
if(debug)
{
Serial.println("turn on GPS power supply => OK");
}
}
else
{
if(debug)
{
Serial.println("turn on GPS power supply => KO");
}
};
//delay(1000);
if(sendATcommand("AT+CGPSRST=1","OK",2000))
{
gpsrst = true;
if(debug)
{
Serial.println("reset GPS in autonomy mode => OK");
}
}
else
{
if(debug)
{
Serial.println("reset GPS in autonomy mode => KO");
}
}; //reset GPS in autonomy mode
delay(1000);
if(gpspwr && gpsrst)
{
return true;
}else
{
return false;
}
}
At the read_AT_string, the first if(Serial.peek()==13) always return false.
1 is printed, but '13' is not, then I supposed
if(Serial.peek()==13)
return false
Here is what is printed within 5 sec
AT DISPLAY BUFFER:
1
1
1
1
1
1
1
1
1
[...] // It prints 1 until now
1
END DISPLAY BUFFER
Here a piece of code to detect and remove CR+LF (Attention: if A CR is read but it's not followed by a LF, it is removed as well):
if (Serial.peek()==13) { // check if CR (without reading)
Serial.read(); // read and ignore
if (Serial.peek()==10) // then check if LF (without reading)
Serial.read();
}
To read the rest of the response from Serial you could use:
buffer[Serial.readBytesUntil(13, buffer, 199)]=0; // readbytes returns the number of bytes read
You then have to discard the ending CRLF (same as above).
Edit
There are several issues with the code that you've posted in a separate answer.
When you powerUpSim908() you have to be aware that the gsm module may send unrequested data (see documentation, chapter 1.4):
Note: A HEX string such as "00 49 49 49 49 FF FF FF FF" will be sent
out through serial port at the baud rate of 115200 immediately after
SIM908 is powered on. The string shall be ignored since it is used for
synchronization with PC tool. Only enter AT Command through serial
port after SIM908 is powered on and Unsolicited Result Code "RDY" is
received from serial port.
This means that before you send anything, you have to discard this data by reading it. I guess this is why you don't get CRLF when reading the response: you first get the HEX string or "RDY".
Then readBytesUntil() reads as many bytes as available (maxi 199 in my example above), stores them in the buffer. It stops reading when it encounters the byte 13 (i.e.CR). There is no need to loop on an index. The function returns the number of chars that could be read, and it doesn't put an ending 0 at the end of the buffer (i.e. no valid C string). If you want to use the function in another way than what I proposed, you must store the length returned, because you have no other way to find it out later on.
for the previous code, the serial monitor will get the message is hexadecimal like"08000AE23BDB",but in Processing those data just show as "NaN".I think maybe only string can be got for processing? but" String buffer(buffer[count])" seems can`t work,how can I convert it?
following is the code of arduino:
#include <SoftwareSerial.h>
SoftwareSerial SoftSerial(2, 3);
unsigned char buffer[64]; // buffer array for data recieve over serial port
int count=0; // counter for buffer array
void setup()
{
SoftSerial.begin(9600); // the SoftSerial baud rate
Serial.begin(9600); // the Serial port of Arduino baud rate.
}
void loop()
{
if (SoftSerial.available()) // if date is comming from softwareserial port ==> data is comming from SoftSerial shield
{
while(SoftSerial.available()) // reading data into char array
{
buffer[count++]=SoftSerial.read(); // writing data into array
if(count == 64)break;
}
Serial.write(buffer,count); // if no data transmission ends, write buffer to hardware serial port
clearBufferArray(); // call clearBufferArray function to clear the storaged data from the array
count = 0; // set counter of while loop to zero
}
if (Serial.available()) // if data is available on hardwareserial port ==> data is comming from PC or notebook
{
SoftSerial.write(Serial.read()); // write it to the SoftSerial shield
}
}
void clearBufferArray() // function to clear buffer array
{
for (int i=0; i<count;i++){
{
buffer[i]=NULL;
}
} // clear all index of array with command NULL
}
and this is the getting massage part of Processing:
void serialEvent(Serial myPort) {
String inString = myPort.readStringUntil('\n');
if (inString != null) {
inString = trim(inString);
float[] data = float(split(inString, ","));
if (data.length >=1)
{
direction1 = data[0];
}
println("data");
println(data[0]);
}
}
Maybe this?
String inString = "08000AE23BDB ";
if (inString != null) {
inString = trim(inString);
String[] data = split(inString, ",");
if (data.length >=1)
{
//direction1 = data[0];
}
println(unhex(data[0]));
}
I am trying to read a serial data into a string with is capable of being compared against another string. I am using if (inputString.equals("test")) to test the boolean value but it is always returning as false as THEY ARE EQUAL is never displayed when test is typed in the serial monitor (which does echo back what ever I sent to the arduino). Any ideas? Is concating the string this way adding extra, non-displayed, bytes to the string?
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
void setup() {
// initialize serial:
Serial.begin(9600);
}
void loop() {
// print the string when a newline arrives:
if (stringComplete) {
if (inputString.equals("test")) {
Serial.print("THEY ARE EQUAL");
}
Serial.print(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
}
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
stringComplete = true;
}
}
Thanks!
You need to allow enough time for the serial data to be read. Add a delay
char inChar = (char)Serial.read();
// add it to the inputString:
delay(100);
inputString += inChar;