Arduino servo code resetting to positon 0 - c++

(excuse my english)
Hi. I'm a beginner at coding who started trying things in Arduino and c++ (because of Arduino). Recently I just learned that you could write to the Arduino board via the serial monitor, and thus via your PC through your COM port, so I tried to find a way of controlling a servo motors rotation from cmd via Arduino's serial monitor. I copied code that was given as an example in the Arduino website and via someone from youtube and got a piece of code that worked, sort of.
Because you see this code works as in it writes to the serial monitor via a c++ program on windows (any ide), but when I send a command, it runs correctly, then it runs once again but setting the input to 0 degrees thus moving the servo head to 0 degrees. I "fixed" it temporarily by preventing the servo from rotating if the input is 0 but it runs everything else in the sketch.
(I've included the code below but it's really long and I don't exactly know how to include big pieces of code (apologies if I included stuff wrong) while still including the minimum reproducible example. I'll happily change it if told to)
The main code:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <string>
#include "SerialPort.h"
char output[MAX_DATA_LENGTH];
char incomingData[MAX_DATA_LENGTH];
using namespace std;
char temp[] = "\\\\.\\COM4";
char* port = temp;
float Scalar = 0.8888;
int main() {
SerialPort arduino(port);
if (arduino.isConnected()) {
cout << "Connection established" << endl << endl;
}
else {
cout << "Error in port name" << endl << endl;
}
while (arduino.isConnected()) {
while (true) {
cout << "Enter your command (degrees 0 to 180 in integers): " << endl;
string data;
cin >> data;
if (data == "exit")
return 0;
/*if (stoi(data) != 90) {
data = to_string(
round((stof(data) - 90) * Scalar + 90)
);
}*/
//cout << data << endl;
char* charArray = new char[data.size() + 2];
copy(data.begin(), data.end(), charArray);
charArray[data.size()] = '\n';
charArray[data.size() + 1] = '\0';
cout << "char array: " << charArray << endl;
arduino.writeSerialPort(charArray, MAX_DATA_LENGTH);
arduino.readSerialPort(output, MAX_DATA_LENGTH);
cout << ">> " << output << endl;
cout << "----------\n" << endl;
delete[] charArray;
}
}
return 0;
}
The .ino sketch file:
#include <Servo.h>
Servo servo1;
int LED = 13;
int servoPos = 90; //to store servo's position
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(LED, OUTPUT);
servo1.attach(11);
servo1.write(servoPos);
}
void loop() {
// put your main code here, to run repeatedly:
delay(15);
if(Serial.available() > 0) {
String info;
String return_text;
info = Serial.readStringUntil('\n');
return_text = "info variable string is: " + info;
Serial.println(return_text);
if(info.toInt() < servoPos && info.toInt() != 0) {
for( 0; servoPos > info.toInt(); servoPos-=1) {
servo1.write(servoPos);
delay(5);
}
}
else if(info.toInt() > servoPos) {
for( 0; servoPos < info.toInt(); servoPos+=1) {
servo1.write(servoPos);
delay(5);
}
}
digitalWrite(LED, HIGH);
delay(20);
digitalWrite(LED, LOW);
//Serial.println("");
//Serial.print("Servo position: ");
//Serial.println(servoPos);
}
}
The header:
#ifndef SERIALPORT_H
#define SERIALPORT_H
#define ARDUINO_WAIT_TIME 2000
#define MAX_DATA_LENGTH 255
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class SerialPort
{
private:
HANDLE handler;
bool connected;
COMSTAT status;
DWORD errors;
public:
SerialPort(char* portName);
~SerialPort();
int readSerialPort(char* buffer, unsigned int buf_size);
bool writeSerialPort(char* buffer, unsigned int buf_size);
bool isConnected();
};
#endif // SERIALPORT_H
And the cpp file containing the functions:
#include "SerialPort.h"
SerialPort::SerialPort(char* portName)
{
this->connected = false;
this->handler = CreateFileA(static_cast<LPCSTR>(portName),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (this->handler == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else {
DCB dcbSerialParameters = { 0 };
if (!GetCommState(this->handler, &dcbSerialParameters)) {
printf("failed to get current serial parameters");
}
else {
dcbSerialParameters.BaudRate = CBR_9600;
dcbSerialParameters.ByteSize = 8;
dcbSerialParameters.StopBits = ONESTOPBIT;
dcbSerialParameters.Parity = NOPARITY;
dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(handler, &dcbSerialParameters))
{
printf("ALERT: could not set Serial port parameters\n");
}
else {
this->connected = true;
PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
SerialPort::~SerialPort()
{
if (this->connected) {
this->connected = false;
CloseHandle(this->handler);
}
}
int SerialPort::readSerialPort(char* buffer, unsigned int buf_size)
{
DWORD bytesRead;
unsigned int toRead = 0;
ClearCommError(this->handler, &this->errors, &this->status);
if (this->status.cbInQue > 0) {
if (this->status.cbInQue > buf_size) {
toRead = buf_size;
}
else toRead = this->status.cbInQue;
}
if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;
return 0;
}
bool SerialPort::writeSerialPort(char* buffer, unsigned int buf_size)
{
DWORD bytesSend;
if (!WriteFile(this->handler, (void*)buffer, buf_size, &bytesSend, 0)) {
ClearCommError(this->handler, &this->errors, &this->status);
return false;
}
else return true;
}
bool SerialPort::isConnected()
{
return this->connected;
}
What happens:
So when I run it, first the servo rotates to 90 degrees, then when I give it an integer input the Arduino runs the servo to the desired input, powers on and off the LED, and whilst this happens the cpp main code prints what I've sent to the Arduino (or at least the visible stuff without \n and \0 e.t.c) and what the serial monitor wrote and goes back to asking me to send an input. The problem is the Arduino code runs again and moves the servo to 0 degrees and lights on and off the LED, just like before without my request.
I went and prevented the servo from moving if data == 0, but the rest of the .ino sketch still runs, so I suspect it maybe have something to do with the char that the cpp file sends to the monitor..? But I'm too smooth brained to figure it out, thus asking for any advice. The console shows the output but doesn't show anything during the second time the arduino loop happens.
If I write something in the console whilst the second (undesired) iteration happens then the arduino doesn't respond to my input, and it also messes up output from the serial monitor during the next runs by either not showing text or completely messing up the text and/or displaying weird gibberish like "³ô¦ò»]½R↨ùýº§»⌂2{²à_Ú◄/4ý¾ı" and more.
(If anything needs to be added, removed or changed because of either misconduct, etiquette or e.t.c then as I said I'll be more than happy to)
thanks in advance.

Take a look here: Serial monitoring tool
It's a tool that simplify serial monitoring. You can view/plot data, send commands, store parameters and bind data with 3D view.
There are files for generic C code and the files (cpp) for Arduino are here Arduino files

Apologies for not updating. I found the solution. It was just that I asked the function from the code online to send a char array of 255 characters when I provided it with the length of whatever I sent. Since the function/header was tasked to send 255 characters it somehow made up random data which the arduino serial COM reader read as 0. I just fixed it by telling the function how much data to send by changing MAX_DATA_LENGTH in arduino.writeSerialPort(charArray, MAX_DATA_LENGTH); to just the number of characters in the string to send.

Related

Windows API to Arduino Serial write works once but sends corrupted data when the same message is rewritten

I am using a third party WinAPI-based Serial library (SerialPort) in a C++ program to command a LED strip (iLED and pixel color), but it turns out it only seems to work for one command - if I send the same command a second time, the color of that pixel takes another random colour and for some reason the first LED turns on too with a random colour.
Here is a link to a video of what happens when the simplified code below is run, i.e. when pixel 3, 5 and 7 are commanded over and over to be red, green, and blue respectively.
https://drive.google.com/file/d/1RRAshnhPz96YGJtmETy3vuGi25QjxqJz/view?usp=drivesdk
I suspected the Serial.read() weren't synchronised so I added a start byte but it didn't seem to work either, that's what the code below does.
What is happening ?
SerialPort.h (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#ifndef SERIALPORT_H
#define SERIALPORT_H
#define ARDUINO_WAIT_TIME 2000
#define MAX_DATA_LENGTH 255
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class SerialPort
{
private:
HANDLE handler;
bool connected;
COMSTAT status;
DWORD errors;
public:
SerialPort(char const *portName, unsigned long baudrate);
~SerialPort();
int readSerialPort(char *buffer, unsigned int buf_size);
bool writeSerialPort(char *buffer, unsigned int buf_size);
bool isConnected();
};
#endif // SERIALPORT_H
SerialPort.cpp (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#include "serialport.h"
SerialPort::SerialPort(char const *portName, unsigned long baudrate)
{
this->connected = false;
this->handler = CreateFileA(static_cast<LPCSTR>(portName),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (this->handler == INVALID_HANDLE_VALUE){
if (GetLastError() == ERROR_FILE_NOT_FOUND){
printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else {
DCB dcbSerialParameters = {0};
if (!GetCommState(this->handler, &dcbSerialParameters)) {
printf("failed to get current serial parameters");
}
else {
dcbSerialParameters.BaudRate = baudrate;
dcbSerialParameters.ByteSize = 8;
dcbSerialParameters.StopBits = ONESTOPBIT;
dcbSerialParameters.Parity = NOPARITY;
dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(handler, &dcbSerialParameters))
{
printf("ALERT: could not set Serial port parameters\n");
}
else {
this->connected = true;
PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
SerialPort::~SerialPort()
{
if (this->connected){
this->connected = false;
CloseHandle(this->handler);
}
}
int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesRead;
unsigned int toRead;
ClearCommError(this->handler, &this->errors, &this->status);
if (this->status.cbInQue > 0){
if (this->status.cbInQue > buf_size){
toRead = buf_size;
}
else toRead = this->status.cbInQue;
}
if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;
return 0;
}
bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesSend;
if (!WriteFile(this->handler, (void*) buffer, buf_size, &bytesSend, 0)){
ClearCommError(this->handler, &this->errors, &this->status);
return false;
}
else return true;
}
bool SerialPort::isConnected()
{
return this->connected;
}
main.cpp
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM3", 115200);
while(1) {
unsigned char buffer[] = {255,3, 254, 0, 0};
serial.writeSerialPort((char*)buffer, 4);
unsigned char buffer2[] = {255,5, 0, 254, 0};
serial.writeSerialPort((char*)buffer2, 4);
unsigned char buffer3[] = {255,7, 0, 0, 254};
serial.writeSerialPort((char*)buffer3, 4);
}
return 0;
}
Arduino firmware
#include <FastLED.h>
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
CRGB leds[N_LEDS] = {0};
void setup() {
FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, N_LEDS); //I don't know why the colours are BRG on this strip
FastLED.show();
Serial.begin(BAUDRATE);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
if(buf[0] < N_LEDS) { //Valid ID
leds[buf[0]] = CRGB(buf[1],buf[2],buf[3]); //Update LED state in internal representation
FastLED.show(); //Refresh LEDs based on internal representation
}
}
}
Note that the LED strip seems to work properly on its own, since I successfully tested moving at constant speed a single pixel.
The LED strip itself is the easiest debug route I have since I didn't manage to make readSerialPort() work yet and the COM port is hogged by the program so I can't get a handle on it (can we sniff that somehow?).
I test serial.writeSerialPort on Windows 10 desktop with Arduino Uno. It works for me.
The following is the code I used:
On windows:
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM4", 115200);
while (1) {
unsigned char buffer[] = { 255,3, 254, 0, 0 };
serial.writeSerialPort((char*)buffer, 5);
unsigned char buffer2[] = { 255,5, 0, 254, 0 };
serial.writeSerialPort((char*)buffer2, 5);
unsigned char buffer3[] = { 255,7, 0, 0, 254 };
serial.writeSerialPort((char*)buffer3, 5);
}
return 0;
}
On Arduino:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
void setup() {
Serial.begin(BAUDRATE);
mySerial.begin(BAUDRATE);
mySerial.println("Start reading.");
delay(5000);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
mySerial.print(buf[i]);
mySerial.print(",");
}
mySerial.print("\r\n");
//Serial.write("Read complete!");
}
}
I print the received data on Arduino:
I notice that the printed data messed up when the Windows sends fast as you did in the while(1) without delay. So try adding a delay between two writes to see if it works.
Add also note the problem as #paddy pointed out.
I didn't manage to make readSerialPort() work yet
Set unsigned int toRead = buf_size; in SerialPort.cpp works for me. Use the following code to read:
unsigned char readBuffer[20] = {};
serial.readSerialPort((char*)readBuffer, 20);
printf((char*)readBuffer);
printf("\n");
Read from Arduino result:

Weird characters in COM Serial Port echo of HELLO WORLD

I have code that sends HELLO WORLD:$ from my PC to COM6 to a TIVAC board. I have confirmed through IAR that the board receives the right message. Note that $ is the terminating character.
I have it set up on the TIVAC board to echo the same message through UART and have confirmed manually through Putty that the echo is correct. However when using this following program which sends the same message and listens for the echo I get weird characters in the echo as shown in this image:
It might be an error in the encoding but how do I fix that?
#include <string>
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <iostream>
#include <winbase.h>
#include <tchar.h>
HANDLE GetSerialPort(char *);
void delay();
int main(void)
{
//
COMMTIMEOUTS timeouts;
HANDLE h1;
char h1_buffer[] = {"HELLO WORLD:$"};
char h2_buffer[24];
DWORD byteswritten, bytesread;
char c1[] = {"COM6"};
char c2[] = {"COM6"};
h1 = GetSerialPort(c1);
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
WriteFile(h1, h1_buffer, strlen(h1_buffer), &byteswritten, NULL);
do
{
bool exit = FALSE;
ReadFile(h1, h2_buffer, strlen(h2_buffer) + 1, &bytesread, NULL);
if(bytesread)
{
h2_buffer[strlen(h2_buffer)] = '\0';
std::string mystring(h2_buffer);
std::cout << "String is : " << mystring << "\n" ;
printf("GOT IT %d\n", strlen(h2_buffer));
ReadFile(h1, h2_buffer, strlen(h2_buffer) + 1, &bytesread, NULL);
printf("%s\n", h2_buffer);
printf("GOT IT %d\n", strlen(h2_buffer));
}
else
{
char stop;
printf("Nothing read\n");
printf("Do you want to exit? ");
scanf(" %c", stop);
if(stop == 'N' || stop == 'n')
{
exit = TRUE;
}
}
}while(1);
printf("EXIT ");
CloseHandle(h1);
}
HANDLE GetSerialPort(char *p)
{
HANDLE hSerial;
hSerial = CreateFile(p,GENERIC_READ | GENERIC_WRITE, 0,0,OPEN_EXISTING,0, 0);
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
dcbSerialParams.BaudRate=CBR_115200;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
dcbSerialParams.fParity = 0;
dcbSerialParams.ByteSize=DATABITS_8;
dcbSerialParams.fDtrControl = 0;
dcbSerialParams.fRtsControl = 0;
return hSerial;
}
void delay ()
{
int i = 1000000000;
printf("In delay\n");
while(i>0)
{
i--;
}
}
Many problems in this code.
Calling strlen() on uninitialised memory will give undefined behaviour.
You don't check for a partial write on the WriteFile() call.
Don't check the return value on ReadFile()
Call strlen() on the data received from ReadFile() instead of using bytesread.
Etc.
You should not be using strlen() on data you get from somewhere else like this -- you should be checking your data and paying attention to the byte counts from your I/O calls.

how can I display/save the value of what return an AT command

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.

C++ Arduino serial connection timing out

Originally, I used AutoHotkey to communicate with the Arduino, but I found that after a few hours of not sending anything to the Arduino (the Arduino sent a 'heartbeat' every ten seconds), the connection would freeze or fail.
Now I'm trying to control an Arduino via its serial connection from a C++ program with the RS-232 library.
But I'm getting the same problem. The program pings the Arduino every twenty seconds, and the Arduino is then supposed to report with a small string of information. After a few hours, the connection dies, and my C++ program just sits there pinging with no response. The Arduino has a watchdog, and I can verify that it is still working when the connection isn't, so I believe that my problem lies in some sort of inherent timeout with serial... Except that the connection is actively being used..
I'd appreciate any help figuring out what I need to do in order to keep the serial connection alive, the computer has to be able to send data to the Arduino 24/7.
I'm compiling on Code::Blocks, and running the program on Windows 7.
I'm not very familiar with C++ or C, so if you find other stupid stuff I'm doing in the program, please let me know.
main.cpp
/**************************************************
File: main.cpp
Purpose: Simple demo that receives characters from
the serial port and print them on the
screen.
**************************************************/
#include <stdlib.h>
#include <iostream>
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
#include "rs232.h"
using namespace std;
int main()
{
int debug = 0;
int i = 0, n,
cport_nr = 5, /* /dev/ttyS5 (COM6 on Windows) */
bdrate = 9600; /* 9600 baud */
unsigned char buf[4096];
if(OpenComport(cport_nr, bdrate))
{
cout << "Can not open comport\n";
return(0);
}
while(1)
{
if (debug)
{
printf("Entering While(1) loop. \n");
}
n = PollComport(cport_nr, buf, 4095);
if(n > 0)
{
buf[n] = 0; /* always put a "null" at the end of a string! */
/* for(i=0; i < n; i++)
{
if(buf[i] < 32) // replace unreadable control-codes by dots
{
buf[i] = '.';
}
} */
//printf("\n\n\nreceived %i bytes: %s\n\n", n, (char *)buf);
cout << endl << endl << endl << (char *)buf;
}
if (SendByte(cport_nr, 83))
{
printf("\n\nSending data didn't work. \n\n");
}
else
{
cout << "\nSent [S]\n";
}
i = 0;
#ifdef _WIN32
Sleep(10000); /* It's ugly to use a sleeptimer, in a real program, change
the while-loop into a (interrupt) timerroutine. */
#else
usleep(10000000); /* Sleep for 100 milliSeconds */
#endif
}
return(0);
}
Arduino file
//
// SuiteLock v.2.1a
// By: Chris Bero (bigbero#gmail.com)
// Last Updated: 11.4.2012
//
#include <Servo.h>
#include <avr/wdt.h>
// Pin Constants:
const int servoPin = 9;
const int doorbtn = 3;
// Not sure if I'm still going to use these...
const int ledGND = 4;
const int ledVCC = 5;
const int servDelay = 600; // The delay allowing for the servo to complete an action.
//Variables:
int doorState = 0; // The value returned by the door button (0 or 1).
int servState = 90; // The position of the servo in degrees (0 through 180).
unsigned long prevMillis = 0;
unsigned long progCycles = 0;
int serialByte = 0;
int lastSerial = 0;
int smallBlink = 0;
bool dostatus = false; // Determine whether to send sys status.
Servo serv;
// Set up the environment.
void setup()
{
wdt_enable(WDTO_4S);
pinMode(doorbtn, INPUT);
pinMode(ledGND, OUTPUT);
pinMode(ledVCC, OUTPUT);
pinMode(servoPin, OUTPUT);
digitalWrite(ledGND, LOW);
serv.attach(servoPin);
Serial.begin(9600);
prevMillis = millis();
}
////////////////////////////////////////////////
// Statuser - Sends system status to Serial
/////////////////////////////////////////////
int statuser ()
{
wdt_reset();
Serial.println("[Start]"); //Start Of Transmission
delay(15);
unsigned long currentMillis = millis();
refresh();
Serial.print("\tTime Alive: ");
int hr = ((currentMillis/1000)/3600);
int mn = (((currentMillis/1000)-(hr*3600))/60);
int sc = ((currentMillis/1000)-(hr*3600)-(mn*60));
Serial.print(hr);
Serial.print(":");
Serial.print(mn);
Serial.print(":");
Serial.println(sc);
Serial.print("\tNum of Program Cycles: ");
Serial.println(progCycles);
Serial.print("\tAvg Cycles per Second: ");
int cps = (progCycles/(currentMillis/1000));
Serial.println(cps);
Serial.print("\tDoorState: ");
Serial.println(doorState);
Serial.print("\tServo Position: ");
Serial.println(servState);
Serial.print("\tLast Serial Byte: ");
Serial.println(lastSerial);
delay(15);
Serial.println("[End]"); //End Of Transmission
return(0);
}
////////////////////////
// Lock the door.
/////////////////////
int locker()
{
wdt_reset();
// Check the button states.
refresh();
// Make sure the door is closed.
do
{
wdt_reset();
delay(500);
refresh();
} while(doorState == LOW);
// Turn on the locking LED during the servo movement.
digitalWrite(ledVCC, HIGH);
wdt_reset();
// Tell the servo to turn to 20 degrees.
serv.write(20);
// Give the servo time to complete the turn.
delay(servDelay);
wdt_reset();
// Turn the servo opp direction to reset.
serv.write(90);
// Wait for the servo to reach it's reset point.
delay(servDelay);
// Turn off the cool little LED.
digitalWrite(ledVCC, LOW);
// Call parents for 11pm checkup and tell them everything's A-OK.
return(0);
}
/////////////////////////
// Unlock the door.
//////////////////////
int unlocker ()
{
wdt_reset();
// Check the pin states.
refresh();
// Turn on the status LED.
digitalWrite(ledVCC, HIGH);
wdt_reset();
// Turn servo to 170 degrees to unlock the door.
serv.write(170);
// Wait for servo motion to complete.
delay(servDelay);
wdt_reset();
// Reset the servo to 90 degrees.
serv.write(90);
// Wait for reset motion to complete.
delay(servDelay);
// Turn off LED.
digitalWrite(ledVCC, LOW);
return(0);
}
///////////////////////////////
// Refresh button states.
/////////////////////////////
void refresh ()
{
wdt_reset();
doorState = digitalRead(doorbtn);
servState = serv.read();
}
///////////////////////
// Main function.
////////////////////
void loop()
{
wdt_reset();
// Blink the LED every so many turn overs of the function.
if (smallBlink == 5)
{
smallBlink = 0;
digitalWrite(ledVCC, HIGH);
delay(300);
digitalWrite(ledVCC, LOW);
}
// Status.
if(dostatus == true)
{
unsigned long currentMillis = millis();
if ((currentMillis - prevMillis) > 4000)
{
prevMillis = currentMillis;
statuser();
}
}
// Refresh button states.
refresh();
// Is the door closed and not locked? *Gasp*
if ((doorState == LOW))
{
// Fix it.
while (doorState == LOW)
{
wdt_reset();
delay(500);
refresh();
}
locker();
}
// Check for available communications.
if (Serial.available() > 0)
{
// Reset the serialByte, done for debugging.
serialByte = 0;
wdt_reset();
// Read the serialByte.
serialByte = Serial.read();
lastSerial = serialByte;
}
// Act on the byte data.
if (serialByte == 'U')
{
// Let someone in.
unlocker();
// Wait for the door to change states.
delay(1000);
}
if (serialByte == 'L')
{
locker();
delay(1000);
}
if (serialByte == 'S')
{
statuser();
delay(200);
}
// Clean serialByte for debugging.
serialByte = 0;
// Count through program cycles.
progCycles++;
smallBlink++;
}
I adjusted the C++ program to open the comport, send 'S', then close the comport and wait. Then I had it loop the procedure, so that it would keep opening and closing the port. My hope was that this would keep the connection from reaching the several hour mark and timing out or whatever. Instead, the program looped successfully for an hour, and then suddenly failed to open the COM port... This is totally blowing me away, and I have no idea what to do about it..
If CrazyCasta is right, and it's just my Arduino's connection to the laptop that's buggy, is there a way to reset the connection without having to restart the computer first?
As CrazyCasta said, it was a hardware problem. I was able to fix the issue by removing a 9 ft (2.7 m) USB extension cord between my Arduino and computer.
As of this morning the connection has been alive for ten hours, which is seven hours longer than previous tests. I hope it's safe to say this is fixed.

Using select without listen()ing, possible?

I am building a client that:
Should be able to recieve information from both the server and the standart input
Should be able to recieve information from the server without asking, for example when another client sends a message.
To do so I tried using select to monitor both possible inputs.
What happens is that when a keyboard input is monitored I send a message to the client and I expect one back, so there's no problem. But when the server sends an unexpected message nothing happens, and I don't know why. Is using select() the proper way to do so? Is it even possible to use select() without listen()ing?
Here's my code (compileable):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#define MAX_CLIENT_NAME 30
#define MAX_TWIT_SIZE 140
#define NUM_OF_ARG 4
#define ERROR -1
#define GREAT_SUCCESS 0
#define OK "OK"
#define EXIT "EXIT"
using std::string;
using std::cerr;
using std::endl;
using std::cout;
string clientName;
int srverfd, numbytes, status, maxSock ;
fd_set inputFdSet; /* Socket file descriptors we want to wake
up for, using select() */
int establishConnection(char * serverAddress,char * port){
if ((srverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return ERROR;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
inet_aton(serverAddress, &server.sin_addr);
server.sin_port = htons(atoi(port));
memset(&(server.sin_zero), '\0', 8);
if (connect(srverfd,(const struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("connect");
close(srverfd);
return ERROR;
}
maxSock = srverfd;
return GREAT_SUCCESS;
}
const char * getUserTweet(){
string temp;
getline(std::cin,temp);
return temp.c_str();
}
void sendMessage(string message){
if ((numbytes = send(srverfd, message.c_str(), message.length(), 0)) == -1) {
perror("sendMessage");
close(srverfd);
}
cout<<"Message sent: "<< message << endl;
return;
}
const char * getMessage(){
char buf[MAX_TWIT_SIZE];
memset(buf,'\0',MAX_TWIT_SIZE);
if ((numbytes = recv(srverfd, buf, 140, 0)) == -1) {
perror("getMessage");
close(srverfd);
}
string temp = buf;
return temp.c_str();
}
void build_select_list() {
FD_ZERO(&inputFdSet);
FD_SET(srverfd,&inputFdSet);
FD_SET(STDIN_FILENO,&inputFdSet);
if (STDIN_FILENO > maxSock)
maxSock = STDIN_FILENO;
return;
}
void readSocket(fd_set tempfd) {
const char * tweet, * inMessage;
if (FD_ISSET(srverfd,&tempfd)) {
inMessage = getMessage();
cout << inMessage << endl;
}
if (FD_ISSET(STDIN_FILENO,&tempfd)) {
tweet = getUserTweet();
sendMessage(tweet);
inMessage = getMessage();
if (strcmp(inMessage,OK) != 0) {
cout << inMessage << endl;
}
if (strcmp(inMessage,EXIT) == 0) {
return;
}
}
return;
}
int main (int argc, char *argv[] ){
int value;
bool clientON = false;
if(establishConnection(argv[2],argv[3])){
cerr << "usage: failed to make connection" << endl << "exiting..." << endl;
exit(EXIT_FAILURE);
}
cout << "Connected successfully" << endl;
sendMessage("CONNECT "+clientName); //Connect
if(strcmp(getMessage(),OK) == 0){
clientON = true;
}
while(clientON){
build_select_list();
value = select(maxSock, &inputFdSet, NULL, NULL, NULL);
if (value < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
continue;
}
else {
readSocket(inputFdSet);
}
}
sendMessage("DISCONNECT");
if(strcmp(getMessage(),OK) == 0){
// do nothing
}
close(srverfd);
return 0;
}
Your select call is invalid. The first parameter must be the highest file descriptor in any of the sets, plus one.
As you have it, an event on srverfd will not "wake up" the select call (unless STDIN_FILENO was somehow less than srverfd, in which case stdin events wouldn't unlock select - but that won't happen in practice).
There are quite a few other problems with your code. (It doesn't really look like C++.)
getUserTweet is unreliable (undefined behavior - temp is destroyed as soon as the function returns, so the char* you return has disappeared by the time its caller will try to use it). Same for getMessage. To remedy that, use std::string everywhere, and only extract the char* when you call into C library functions).
readSocket needlessly copies the FD set (can be expensive).
You should really get rid of all those globals - build one or two classes to encapsulate that state and the networking functions, or something like that.