Serial read, collate, write AT commands - c++

This is most probably a software question, not sure where to post this (Arduino sub? electronics sub?).
I have an Arduino Mega, that is connected to :
an RFID card read via SPI,
a wifi chip (esp8266-12f) via Serial1.
The wifi chip currently acts as a web Server as I intend to send commands to it via the internet. I also want that wifi chip to act as a Client, that is to say : when the RFID reads a card, I want the Arduino Mega to forward the RFID's card id to the wifi chip via Serial1 so that the wifi chip can send an http request to a dedicated server that would save it into sql database.
This is how I coded it on the wifi chip so far :
// esp as a Server
// [...]
// esp as a Client
timeout = millis() + (10 * 1000UL); // 10s
String input;
while (Serial.available() >= 0 && millis() < timeout) {
input += Serial.readStringUntil('\r');
int pos = input.indexOf("AT+TEST");
if (pos >= 0) {
Serial.println(F("AT+TEST"));
// collate, aka confirm to Arduino Mega we understood the command and we are processing it
// todo: process the command, aka parse the command, send an http request, etc
Serial.println(F("\r\nOK"));
} else {
Serial.println(F("\r\nNOPE"));
}
}
As you might have guessed, the chip is printing "AT+TEST" over and over again (until it times out, then loops infinite NOPE), as it is trying to process the command over and over, but I just want it to say "ok Arduino Mega, I understood you want me to execute AT+TEST"
What would be an elegant way to make it so that the wifi chip "ignores" the stuff it itself prints to it's own serial? It should only execute commands coming from the Arduino Mega.
This is something the factory default firmware does very well : when I send "AT", it echoes back "AT\r\n\r\nOK" only once.
I found this but I cannot understand how they implemented the idea (irrelevant code everywhere) : https://github.com/JiriBilek/ESP_ATMod/blob/d6ad63f71ef3189518ef4740f16a9d697c3e843a/ESP_ATMod/ESP_ATMod.ino#L581
Looking for guidance on a solid way to achieve this as there are lots of datas coming in and out to that serial of the wifi chip.

It looped because of the Line Feed. Not only that, it also needed a 1ms delay somehow.
Sorry for the poor explanation of my issue.
The following works as I expected :
// esp as a client
String input;
timeout = millis() + (5 * 1000UL); // 5s
while (Serial.available() && millis() < timeout) {
input = Serial.readStringUntil('\r'); // up to CR
delay(1); Serial.read(); // discard LF
// collate
Serial.println(input);
// AT+TEST
if (input.indexOf("AT+TEST") >= 0) {
Serial.println(F("\r\nOK"));
// todo : verbose for debug
}
// AT+GET=https://arduino.example.tld/api/arduino.php?token=123&key1=val1
else if (input.indexOf("AT+GET") >= 0) {
Serial.println(F("\r\nOK"));
// todo : regex + http get req
} else {
Serial.println(F("\r\nERROR"));
}
}

Related

How to properly write a Win32 application using boost::asio to communicate over serial connection

I'm developing a Windows application that has to communicate (both input and output) with an Arduino through its serial port. I'm using boost::asio for portability reasons and I want to keep using it. What happens is that the first time I run my application it works perfectly, but if I run it a second time, no data comes from the Arduino anymore and the application stucks on the read operation. The only way to recover is to unplug and replug the Arduino USB cable from the computer.
This behavior is Windows-specific. The same code works perfectly on Linux.
The compiler is Visual Studio 2017 Community Edition.
Here is an example code to reproduce the issue:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>
int main() {
boost::asio::serial_port port(ioctx, "COM3"); // "/dev/ttyACM0" on Linux
port.set_option(boost::asio::serial_port::baud_rate(9600));
port.set_option(boost::asio::serial_port::character_size(8));
port.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
port.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
port.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
char c = 'e';
auto const s = boost::asio::write(port, boost::asio::buffer(&c, 1));
std::cout << "sent " << s << " bytes" << std::endl;
boost::asio::streambuf response;
boost::asio::read_until(port, response, "\r\n");
std::istream response_stream(&response);
std::string line;
std::getline(response_stream, line);
std::cout << line << std::endl;
port.close(); // last-ditch effort to get it working
}
Here is an Arduino sketch (got from the Arduino website):
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Is there a way to restore the correct state of the connection? Am I missing something?
After having learned a couple of things, here is the solution:
Arduino uses its USB communication for both burning the sketch and performing data transmission back and forth the PC. The boot sequence foresees that for 2 seconds (for new Arduino versions and standard boot loader) the communication towards the boot loader is active. After that time, the sketch is executed.
Windows API allows to set all connection parameters at once via the SetCommState function and to retrieve them in a similar fashion with the GetCommState one. That is the method the set_option function uses to set the parameters, but it happens that calling GetCommState-SetCommState multiple times in a row slows down the process a lot (maybe by resetting the Arduino multiple times).
I ended writing the following function:
#include <Windows.h>
#include <chrono>
void init_arduino(boost::asio::serial_port& port, std::chrono::milliseconds const& sleep = 2000)
{
DCB dcbSerialParams = { 0 };
GetCommState(port.native_handle(), &dcbSerialParams);
// this is the optimal way to set the whole serial port configuration
// just in one shot.
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
//Setting the DTR to Control_Enable ensures that the Arduino is properly
//reset upon establishing a connection
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
SetCommState(port.native_handle(), &dcbSerialParams);
PurgeComm(port.native_handle(), PURGE_RXCLEAR | PURGE_TXCLEAR);
// Wait for Arduino to boot the sketch
Sleep(sleep.count());
}
and using it to replace the port.set_option( lines in the question example.
I also set the flow control to DTR_CONTROL_ENABLE instead of the original none in order to reset the Arduino upon connection.
USB serial adaptors can have device driver bugs and hardware problems. The fact that you have to unplug and plug the device to get it working again is indicative of a device driver bug.
Look for an updated driver. It will probably a Prolific or FTDI chipset, make sure you get the driver from the chip maker. See Prolific or FTDI
If it is a flow control related hardware problem you can wire together the DTR, DSR and CD pins, and wire together the RTS and CTS pins on the RS-232 connector on the USB adaptor. I have seen USB adaptors where this is necessary, despite setting no flow control in software.

Send a signed integer as a byte via serial in c++ and Arduino read it

I could send a String via serial, but Arduino reads String very slow. Therefore, I use reading byte in Arduino, but the problem is I don't know how to send a number (<256) as a byte via Serial Port in C++.
If you open up the Arduino IDE, under the menu, look at:
File > Examples > 08.Strings > CharacterAnalysis
Here I think you'll find something very close what you're looking for. To sum up, it opens a Serial connection (USB) and reads input from the computer. (You'll need to make sure you match the baud rate and use the "send" button.) It's up to you do program the Arduino as you'd like. In the example's case, it simply sends feedback back to the the Serial Monitor. Run it for yourself and see what happens :)
A [MCVE] snippet from the example:
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// send an intro:
Serial.println("send any byte and I'll tell you everything I can about it");
Serial.println();
}
void loop() {
// get any incoming bytes:
if (Serial.available() > 0) {
int thisChar = Serial.read();
// say what was sent:
Serial.print("You sent me: \'");
Serial.write(thisChar);
}

python arduino usb communication

I'm trying to move data from Python to Arduino nano, but I can't see anything on the console on the Arduino side, but when
I tried to move data from Arduino to python, it worked very well.
Follow my codes below:
arduino code
void setup() {
Serial.begin(9600);
}
void loop() {
if(Serial.available() > 0) {
char data = Serial.read();
char str[2];
str[0] = data;
str[1] = '\0'
Serial.print(str);
}
}
python code
import serial, time
arduino = serial.Serial('COM3', 9600, timeout=.1)
time.sleep(1) # give the connection a second to settle
arduino.write("Hello from Python!")
while True:
data = arduino.readline()
if data:
print data.rstrip('\n') # strip out the new lines
The Arduino is using print, the Python is using readLINE.. Readline reads until it finds a '\n' the arduino is never sending a '\n'.'
Replace \0 in the sketch with \n and it should work.
It's always useful to test using the serial monitor and seeing what happens, if this doesn't work then please try sending some data using the serial monitor and let us know the results.
The problem may be that you have set too little time after connecting to the COM port.
try this
time.sleep(5) # give the connection 5 seconds to establish

C++ Serial Communication Issue

I am trying to make a Console C++ program that will be able to communicate through the serial port with my Arduino microcontroller, however I am having a problem with the ReadFile() function:
This is the ReadFile() function code from my C++ Console Program:
if(ReadFile(myPortHandle, &szBuf, 1, &dwIncommingReadSize, NULL) != 0)
{
cout<<"FOUND IT!"<<endl;
Sleep(100);
}
else
{
cout<<".";
Sleep(100);
}
The ReadFile function is consistently returning the "False" value, meaning it is not finding anything in the serial port. On the other side of the serial port, I have my Arduino Hooked up with the following code:
int switchPin = 4; // Switch connected to pin 4
void setup() {
pinMode(switchPin, INPUT); // Set pin 0 as an input
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop() {
if (digitalRead(switchPin) == HIGH) { // If switch is ON,
Serial.write(1); // send 1 to Processing
} else { // If the switch is not ON,
Serial.write(0); // send 0 to Processing
}
delay(100); // Wait 100 milliseconds
}
And every time I press a push button, I would send a "1" value to the serial port, and a "0" every time I don't press a push button. Basically, I got the Arduino code from a tutorial I watched on how to do serial communication with the program Processing (which worked perfectly), though I am unable to do the same with a simple Console Application I made with C++ because for some reason the ReadFile() function isn't finding any information in the serial port.
Anyone happen to know why?
P.S.: The complete code in the C++ Console Program can be found here:
https://stackoverflow.com/questions/27844956/c-console-program-serial-communication-arduino
The ReadFile function is consistently returning the "False" value, meaning it is not finding anything
No, that is not what it means. A FALSE return value indicates that it failed. That is never normal, you must implement error reporting code so you can diagnose the reason. And end the program since there is little reason to continue running. Unless you setup the serial port to intentionally fail by setting a read timeout.
Use GetLastError() to obtain the underlying Windows error code.
You look to use MS Windows so try to catch the arduino output using portmon first, then you can debug your C++ code.

How do I read the output of an AT command in Arduino?

How do I capture the output from an AT command on an Arduino?
I'm using the Arduino Uno R3 with a GSM shield. I have all the AT commands (they can be seen here ) and I can enter them just fine if I use the terminal and get output. However how can I capture the resulting output via code? The code below shows what I've tried but it does not work. In particular where I attempt to get the analog input and then print out the result.
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7, 8);
void setup()
{
char sensorValue[32] ="";
Serial.begin(9600);
mySerial.begin(9600);
Serial.println("\r");
//Wait for a second while the modem sends an "OK"
delay(1000);
//Because we want to send the SMS in text mode
Serial.println("AT+CMGF=1\r");
delay(1000);
mySerial.println("AT+CADC?"); //Query the analog input for data
Serial.println(Serial.available());
Serial.println(Serial.read()); //Print out result???
//Start accepting the text for the message
//to be sent to the number specified.
//Replace this number with the target mobile number.
Serial.println("AT+CMGS=\"+MSISDN\"\r");
delay(1000);
Serial.println("!"); //The text for the message
delay(1000);
Serial.write(26); //Equivalent to sending Ctrl+Z
}
void loop()
{
/*
if (mySerial.available())
Serial.write(mySerial.read());
if (Serial.available())
mySerial.write(Serial.read());
*/
}
I get the outputs:
AT+CMGF=1
AT+CADC? 21 13
or
AT+CMGF=1
AT+CADC? 18 65
Regardless of changes in my analog source
Take a look at the documentation of the SoftwareSerial read function here.
When you read from the GSM device serial interface, you cannot take for granted that there are bytes to be read on the buffer.
It's very likely that mySerial.read() returns -1 (no bytes available), as Arduino runs that code before the GSM device can provide something on the serial port.
You should use the available function (documentation here) to test the serial interface for incoming bytes. You could use it with a timeout to avoid infinite waiting.
The best thing you could try is to write a separate class to handle serial operations (read, write, timeouts, delays, etc).
Also, I wrote a GPRS driver for Arduino once.
I had a problem with the power supply that required me to install an extra capacitor on the GPRS device and use a power supply with more than 2A of output current.