C++ serial communication in Linux - c++

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

The easiest just to check if quickly can be done in the linux terminal and no library is used for that.
Set the baudrate to 300 for the UART1 (stty -F /dev/ttyO1 raw & stty -F /dev/ttyO1 300)
You can sent data to the UART1 simply by writing(or reading) to the device file for the UART1 which is in your case /dev/ttyO1
Writing: echo "650X450Y" > /dev/ttyO1
Reading: cat /dev/ttyO1
If you want to do this in C Code you can use the open/read/write/close syscall functions.

Related

Weird output for RGB

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

send CTRL-Z through C++ program

I am trying to write a simple C++ program that sends an SMS message out based on its input from the user. The simple C++ program fails to do the job:
#include<stdio.h>
#include <stdlib.h> /* system, NULL, EXIT_FAILURE */
#include<iostream>
#define CTRL(x) (#x[0]-'a'+1)
using namespace std;
int main()
{
char buffer[128];
sprintf(buffer, "/opt/modemcli AT+CMGC=\"+112345678\"\rTEST%c", CTRL(z));
printf (buffer);
system(buffer);
return 0;
}
modemcli is just a simple C++ program that writes messages to the USB port and reads the response.
modemcli is simple, here is a test:
/opt/modemcli AT
Received AT
OK
My guess is CMGC is not formed properly. The format is:
AT+CMGC="PHONE_NUMBER"<CR>SMS MESSAGE BODY.<Ctrl+z>
Can someone please help me figure this out?
First of all, I think you want to use the AT+CMGS command, not AT+CMGC. Check out the description of each command in 27.005 to see if you really want AT+CMGC. But before reading that document, read all of chapter 5 in V.250, that will teach you all the basics for AT command handling you need.
What you are attempting is impossible to do by using a generic command line program for sending AT command like modemcli or my atinout program. In order to run AT+CMGS on a modem, the program issuing it must have explicitly support for this specific AT command's behaviour.
This is because the need to wait for the "ready to receive" prompt from the modem before sending the payload. See the first part of this answer for details.
I have started working on a companion program to atinout specifically to handle AT+CMGS, but it is not done yet and do not hold your breath, the development is currently on hold.

Why does getchar work like a buffer instead of working as expected in real-time

This is my first question on stackoverflow. Pardon me if I haven't searched properly but I do not seem to find an explanation for this. Was just attempting an example from Bjourne Stroustroup's papers. Added my bits to see the array get re-sized as I type the text.
But it doesn't seem to work that way! getchar() simply waits till I am done with entering all the characters and then it will execute the loop. As per the logic, it doesn't actually go into the loop, get a character, perform its actions and then iterate. I am wondering if this is implementation specific, or intended to be like this?
I am on Ubuntu 14.04 LTS using Codeblocks with gcc 4.8.2. The source was in cpp files if that matters.
while(true)
{
int c = getchar();
if(c=='\n' || c==EOF)
{
text[i] = 0;
break;
}
text[i] = c;
if(i == maxsize-1)
{
maxsize = maxsize+maxsize;
text = (char*)realloc(text,maxsize);
if(text == 0) exit(1);
cout << "\n Increasing array size to " << maxsize << endl;
}
i++;
}
The output is as follows:
Array Size is now: 10
Please enter some text: this is some sample text. I would have liked to see the memory being realloced right here, but apparently that's not how it works!
Increasing array size to 20
Increasing array size to 40
Increasing array size to 80
Increasing array size to 160
You have entered: this is some sample text. I would have liked to see the memory being realloced right here, but apparently that's not how it works!
Array Size is now: 160
This has nothing to do with getchar directly. The "problem" is the underlying terminal, which will buffer your Input. The Input is sent to the program after you press enter. In Linux (dunno if there is a way in Windows) you can workaround this by calling
/bin/stty raw
in terminal or by calling
system ("/bin/stty raw");
in your program. This will cause getchar to immediately return the input character to you.
Dont forget to reset the tty behaviour by calling
/bin/stty cooked
when done!
Here is an example (for Linux):
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main() {
system ("/bin/stty raw");
char c = getchar();
system ("/bin/stty cooked");
return 0;
}
Also have a look at this SO Post: How to avoid press enter with any getchar()
Also, as suggested in the comments, have a look here: http://linux.die.net/man/3/termios especially on the command tcsetattr, which should work cross-platform.
Actually, tcsetattr does not apply to Windows (which is what is commonly referred to in this site as "cross-platform"). However, the question is tagged for Linux, so "cross-platform" is a moot point.
By default the standard input, output and error streams are set to
line-buffered (input)
block-buffered (output)
line-buffered (error)
You can change that using setbuf, but of course will not solve the problem (the answer calls for single-character input). POSIX terminal I/O (termios) lets you change via a system call any of the flags shown using stty. As a rule, you might call stty directly from a script, rarely from a C program.
Reading a single character is a frequently asked question, e.g.,
How can I read single characters from the terminal? (unix-faq)
How can I read a single character from the keyboard without waiting for the RETURN key? How can I stop characters from being echoed on the screen as they're typed? (comp.lang.c FAQ)
You could also use ncurses: the filter function is useful for programs that process a command-line (rather than a full-screen application). There is a sample program in ncurses-examples (filter.c) which does this.

Arduino substring doesn't work

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

Capturing serial input in string/char array

I have a software serial link between an Arduino Uno and a TC35 GSM Module to send and receive SMS messages. Sending SMS'/calls is not a problem as it is a matter of sending the appropriate AT command to the GSM module. However I wish to use the AT+CMGR=1 command (which checks the first SMS stored on the SIM card) to check if there is any messages and store the message as a char array so that I can then check if the SMS contains the word 'on' or 'off' to activate a LED.
The AT+CMGR=1 command should return the following:
AT+CMGR=1
+CMGR: "REC READ","+3538xxxxxxxx",,"13/03/23,14:29:37+00"
Set
OK
But in the method below when I print 'data' it just returns:
Message contains:
AT
Any pointers would be much appreciated.
void checkMessage() {
gsmSerial.println("AT+CMGR=1"); //Reads the first SMS
for (x=0;x < 255;x++){
data[x]='\0';
}
x=0;
do{
while(gsmSerial.available()==0);
data[x]=gsmSerial.read();
x++;
if(data[x-1]==0x0D&&data[x-2]=='"'){
x=0;
}
}while(!(data[x-1]=='K'&&data[x-2]=='O'));
data[x-3]='\0'; //finish the string before the OK
Serial.println("\r\nMessage contains: \r");
Serial.println(data); //shows the message
delay(1000);
}
I don't understand your intent of doing this:
if(data[x-1]==0x0D&&data[x-2]=='"'){
x=0;
}
It appears you're discarding your data and reading new data whenever you hit a line containing a trailing quote and newline. So the response to the command of interest is being discarded. I haven't tested it, but I think it would work if you deleted those three lines.
I should also mention that [x-1] and [x-2] are referencing memory prior to the data buffer. That's a very bad practice that can and will cause undefined behavior. You should only check the index minus some value when the result of that computation will be a positive value. A negative array index will access memory prior to the start of the array.