I'd like to know if there is a standard way to communicate with the serial device that is efficient. Should I be using a standard library? If so, which one?
Right now I'm fiddling around getting an LED to light up at a given amount based on number input. (Arduino code below). Just practice stuff.
See my overly simple and inefficient test:
#include <iostream>
#include <stdio.h>
using namespace std;
int
main()
{
FILE *file;
//Opening device file
int getnum;
while (true)
{
file = fopen("/dev/ttyACM5", "w");
cout << ">>" << endl;
cin >> getnum;
fprintf(file, "%d", getnum); //Writing to the file
fclose(file);
}
}
The while loop is cute, but hardly efficient if allowed to run without waiting for the user. I suspect the redundant fopen fclose use is stupid.
The microcontroller is going to be sensing states of a device and sending signals to the computer. The computer will do the "crunching" of all of these values, and sending messages back to alter the arduino's behavior. Basically the heavy thinking is being delegated to the computer, besides requiring human keyboard input.
Of course this is all for fun, but as you can see I need to "learn the rules" of serial interaction in C++! Any help or guidance greatly appreciated.
The arduino code:
char incomingByte = 0; // for incoming serial data
int led = 11;
int bright;
void
setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void
loop()
{
// send data only when you receive data:
if (Serial.available() > 0)
{
// read the incoming byte:
incomingByte = Serial.read();
switch (incomingByte)
{
case '1':
bright = 10;
break;
case '2':
bright = 50;
break;
case '3':
bright = 255;
break;
default:
bright = 0;
break;
}
analogWrite(led, bright);
Serial.println(incomingByte);
}
}
I wonder why nobody answered this question for so long. Why are you saying this is an inefficient way? It isn't creating a physical file in the filesystem if you're referring to that. This is actually the right way to do it, just don't open and close the file descriptor inside the loop. If you want Serial.read to read a single value send '\n', fprint (file, "%d\n", value).
Related
Whilst I am having better results using fgets, I am really puzzled by why the following code would always give the same value (from the second read onwards).
The following is a minimal temperature reader. It seems to read correctly the first time but outputs the same value forever, despite the system temperature changes.
To do a comparison, current, effective temperature can be monitored with the command watch cat /sys/class/thermal/thermal_zone0/temp
Here's the code (compile with g++ filename.cpp ):
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
bool shouldStop = false;
void sigHandler(int signo) {
if(signo == SIGTERM) {
shouldStop = true;
}
else if(signo == SIGINT) {
printf("Bye bye");
shouldStop = true;
}
}
void temperatureReadLoop() {
FILE *fp;
fp = fopen("/sys/class/thermal/thermal_zone0/temp", "r");
int temperature;
while(!shouldStop) {
fscanf(fp, "%d", &temperature);
printf("\ntemperature read : %d", temperature);
// //rewind(fp);
fseek(fp, 0, SEEK_SET);
sleep(1);
}
fclose(fp);
printf("\nquit\n");
}
int main() {
signal(SIGTERM, sigHandler);
signal(SIGINT, sigHandler); // STOP WITH [CTRL + C]
temperatureReadLoop();
}
Running the above results in an infinite
temperature read : 44000
temperature read : 44000
temperature read : 44000
temperature read : 44000
temperature read : 44000
...despite the temperature is changing.
I tried resetting the file seek position in different ways but I had no luck.
It's almost like fscanf has its own hidden buffer that it's not reset.
It's worth noting that if the temperature changes between the first and the second read, the change gets through and the temperature value is correctly updated but this happens only if, by luck, the temperature changes between first and second read; it remains the same for the rest of the run time.
What am I missing?
You should call fflush() before your fseek().
Fseek will correctly handle updates from within your program but it does not know about external changes.
What I'm trying to do is to send a message to each child and than see which one prints it out first. I've tried using one pipe so my code looks like this:
int main()
{
int pfd[2];
if(pipe(pfd)<0){
perror("pfd error");
exit(1);
}
int n=5;
for(int i=1;i<=n;i++){
pid_t pid=fork();
if(pid<0){
perror("fork error\n");
exit(1);
}
if(pid==0){
close(pfd[1]);
char ms[256];
int h;
read(pfd[0],&h,sizeof(int));
read(pfd[0],ms,h*sizeof(char));
cout<<i<<"_"<<ms<<endl;
close(pfd[0]);
exit(0);
}
if(pid>0){
close(pfd[0]);
}
}
int j=1;
char uzenet[256];
strcpy(uzenet,"start");
int ho=strlen(uzenet);
while(j<=n){
if(write(pfd[1],&ho,sizeof(int))==-1){
perror("write error");
exit(1);
}
if(write(pfd[1],uzenet,ho*sizeof(char))==-1){
perror("write error");
exit(1);
}
j++;
}
close(pfd[1]);
while(wait(NULL)>0){};
exit(0);
}
And it prints out this:
2_
1_start
4_
3_
5_
But what I want is this:
2_start
1_start
4_start
3_start
5_start
You can't with only one pipe!
Data read from a pipe is consumed, that means that once something is read from a pipe it will never be available, it disappears from the pipe (think about water and pipe, drinking consumes the water).
If you share the reading part of a pipe in between different processes, then they will be concurrent. That means that you can't have any guaranty on who will read some data. The system is able to choose any reader he wants among all readers that request reading at some point. In the worst case, one process would read everything. In general, you will have a kind of random choice. It is not random, but almost impossible to control (and surely a bad idea to try). At least don't think about replicate N times the message on the writing part, and hope that the N readers will be able to read one copy each.
pipes cannot be used to broadcast something. If you want it, implement your own broadcasting system.
---ADD---
Also don't forget that pipe data have no semantic, there is no concept of messages inside, if you need it you'll have to implement some protocol to simulate it. I mean that you can't flood the pipe with liters and drink drops, or the converse...
I use Qt 5.4 on Ubuntu Gnome 14.04 LTS to reads a string line from serial port. Everything was OK, but when I re-installed Ubuntu Gnome 14.04 and Qt 5.4, my code of serial port does not work well. When the Arduino send "0" the code of Qt reads it like this "�" and the other numbers that sends over serial the Qt reads it as a letters and symbols. I think the problem with unicode of my Qt. The unicode of my ubuntu is en.US.UTF-8 and the QT unicode is setted to "system". Please help me :(
This is my code that read the data from serial port:
QByteArray input;
if (serial->canReadLine()) //chect if data line is ready
input.clear();
input = serial->readLine(); //read data line from sreial port
ui->label->setText(input);
qDebug ()<<input<<endl;
this code of Arduino it is working fine with CuteCom and Arduino serial monitor
const int analogInPin = A0;
unsigned int sensorValue = 0; // value read from the pot
void setup() {
Serial.begin(19200);
}
void loop() {
Serial.print("\n");
Serial.print("#");
for (int i=0; i < 5; i++) {
// read the analog in value:
sensorValue = analogRead(analogInPin);
Serial.print(sensorValue);
Serial.print("#");
};
sensorValue = analogRead(analogInPin);
Serial.print(sensorValue);
Serial.print("# \n");
}
Sorry for my English
If the parity or data/stop bit parameters are different you can still write and read, but you get "funny" output similar to the one you showed us above, and this is not a problem of the unicode setting (especially not with '0', which is a character of the ASCII set).
Try setting the same port parameters explicitly on both ends just before starting the communication.
There are several problems:
You didn't post enough code to know the context of how you use it. I'm assuming that you handle the data in a method attached to the readyRead signal.
You are only reading one line, where you should be reading lines until no more are available. The readyRead signal can be emitted with any number of bytes available for reading: these may make up no complete lines, or several complete lines! If you don't keep on reading lines until no more are available, you'll be severely lagging behind incoming data.
You are using implicit QByteArray to QString conversions. These are a bad code smell. Be explicit about it.
You have fairly verbose code. You don't need to clear a QByteArray before setting its value. You also should declare it at the point of use. Better yet, use type inference that C++11 brought.
Thus:
class MyWindow : public QDialog {
QSerialPort m_port;
void onData() {
while (m_port->canReadLine())
auto input = QString::fromLatin1(m_port->readLine());
ui->label->setText(input);
qDebug() << input;
}
}
...
public:
MyWindow(QWidget * parent = 0) : QDialog(parent) {
...
connect(&m_port, &QIODevice::readyRead, this, &MyWindow::onData);
}
};
I am trying to write a c++ program for my linux machine that can interact with some instrumentation that responds to simple ascii commands. The problem I'm running into, I would think, would be a fairly common request but my searches of various forums came up with nothing quite the same.
My problem is this: When I connect to the instrument, due to some communication issues, it often pukes up a bunch of data of varying length that I don't want. The data the machine prints has line endings with '\r'. I have been trying to write a simple loop what will keep reading and ignoring data until the machine is quiet for two seconds, then carry on to perform some data requests once the storm is over.
When searching forums, I found gobs and gobs of threads about cin.ignore, cin.sync, getline and cin.getline. These all seemed quite useful but when I attempted to implement them in a way that should be simple, they never behaved quite as I expected them to.
I apologize in advance if this is a duplicate post as I would have thought I wasn't the first person to want to throw away garbage input but I have found no such post.
The code I have been trying a few different arrangements of looks something like this:
sleep(2);
cin.clear();
while ( cin.peek() != char_traits<char>::eof()) {
//cin.sync();
//cin.ignore(numeric_limits<streamsize>::max(),char_traits<char>::eof());
cin.clear();
char tmp[1];
while ( cin.getline(tmp,80,'\r') ) {}
cin.clear();
sleep(2);
}
I understand from my searches that doing some sort of while(!cin.eof()) is bad practice but tried it anyway for grins as well as while(getline(cin,str,'\r')) and while(cin.ignore()). I am at a loss here as there is clearly something I'm missing.
Thoughts?
EDIT: --final code--
Alright! This did it! Thanks for point me to termios #MatsPetersson! I wound up stealing quite a lot of your code, but I'm glad I had the opportunity to figure out what was going on. This website helped me make sense of the tcassert manual page: http://en.wikibooks.org/wiki/Serial_Programming/termios
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <limits>
#include <termios.h>
#include <errno.h>
#include <cassert>
using namespace std;
const int STDIN_HANDLE=fileno(stdin);
int main()
{
string str;
//Configuring terminal behavior
termios tios, original;
assert( tcgetattr(STDIN_HANDLE, &tios)==0 );
original = tios;
tios.c_lflag &= ~ICANON; // Don't read a whole line at a time.
tios.c_cc[VTIME] = 20; // 0.5 second timeout.
tios.c_cc[VMIN] = 0; // Read single character at a time.
assert( tcsetattr(STDIN_HANDLE, TCSAFLUSH, &tios)==0 );
const int size=999; //numeric_limits<streamsize>::max() turns out to be too big.
char tmp[size];
int res;
cerr << "---------------STDIN_HANDLE=" << STDIN_HANDLE << endl;
cerr << "---------------enter loop" << endl;
while ( res=read(STDIN_HANDLE, tmp, sizeof(tmp)) ) {
cerr << "----read: " << tmp << endl;
}
cerr << "--------------exit loop" << endl;
cout << "END";
assert( tcsetattr(STDIN_HANDLE, TCSANOW, &original)==0 );
return 0;
}
That wasn't as bad as I began to fear it would be! Works perfectly! Obviously all the cerr << -- lines are not necessary. As well as some of the #include's but I'll use them in the full program so I left them in for my own purposes.
Well... It mostly works anyway. It works fine so long as I don't redirect the stdio for the program to a tcp-ip address using socat. Then it gives me a "Not a Typewriter" error which is what I guess happens when it attempts to control something that isn't a tty. That sounds like a different question though, so I'll have to leave it here and start again I guess.
Thanks folks!
Here's a quick sample of how to do console input (and can easily be adapted to do input from another input source, such as a serial port).
Note that it's hard to "type fast enough" for this to read more than one character at a time, but if you copy'n'paste, it will indeed read 256 characters at once, so assuming your machine that you are connecting to is indeed feeding out a large amount of stuff, it should work just fine to read large-ish chunks - I tested it by marking a region in one window, and middle-button-clicking in the window running this code.
I have added SOME comments, but for FULL details, you need to do man tcsetattr - there are a whole lot of settings that may or may not help you. This is configured to read data of "any" kind, and exit if you hit escape (it also exits if you hit an arrow-key or similar, because those translate to an ESC-something sequence, and thus will trigger the "exit" functionality. It's a good idea to not crash out of, or set up some handler to restore the terminal behaviour, as if you do accidentally exit before you've restored to original setting, the console will act a tad weird.
#include <termios.h>
#include <unistd.h>
#include <cassert>
#include <iostream>
const int STDIN_HANDLE = 0;
int main()
{
termios tios, original;
int status;
status = tcgetattr(STDIN_HANDLE, &tios);
assert(status >= 0);
original = tios;
// Set some input flags
tios.c_iflag &= ~IXOFF; // Turn off XON/XOFF...
tios.c_iflag &= ~INLCR; // Don't translate NL to CR.
// Set some output flags
// tios.c_oflag = ... // not needed, I think.
// Local modes flags.
tios.c_lflag &= ~ISIG; // Don't signal on CTRL-C, CTRL-Z, etc.
tios.c_lflag &= ~ICANON; // Don't read a whole line at a time.
tios.c_lflag &= ~(ECHO | ECHOE | ECHOK); // Don't show the input.
// Set some other parameters
tios.c_cc[VTIME] = 5; // 0.5 second timeout.
tios.c_cc[VMIN] = 0; // Read single character at a time.
status = tcsetattr(STDIN_HANDLE, TCSANOW, &tios);
assert(status >= 0);
char buffer[256];
int tocount = 0;
for(;;)
{
int count = read(STDIN_HANDLE, buffer, sizeof(buffer));
if (count < 0)
{
std::cout << "Error..." << std::endl;
break;
}
if (count == 0)
{
// No input for VTIME * 0.1s.
tocount++;
if (tocount > 5)
{
std::cout << "Hmmm. No input for a bit..." << std::endl;
tocount = 0;
}
}
else
{
tocount = 0;
if (buffer[0]== 27) // Escape
{
break;
}
for(int i = 0; i < count; i++)
{
std::cout << std::hex << (unsigned)buffer[i] << " ";
if (!(i % 16))
{
std::cout << std::endl;
}
}
std::cout << std::endl;
}
}
status = tcsetattr(STDIN_HANDLE, TCSANOW, &original);
return 0;
}
If your instrumentation offers a stream interface, and assuming that it would wait before returning whenever no input is available, I'd suggest to simply use :
cin.ignore(numeric_limits<streamsize>::max(),'\r'); // ignore everything until '\r'
Another alternative could be to use poll, which provides a mechanism for multiplexing (and waiting for) input/output over a set of file descriptors. This has the advantage of letting you read several instrumentation devices if you'd need.
I'm working on creating a maze game, where two players connect (one acts as host, the other the player). In this, I'm sending XML data as a string using the send() function. (I'm also using a pre-made Socket class, keeping in mind this is for non-profit activities, meaning it doesn't break the copyright.) Keep in mind the client & server are running on Windows 7 using the WinSock2.h package.
The problem I'm encountering is fairly straightforward. I first send the Maze XML file, this reads properly and is able to save the maze in a series of tiles. After this, another XML file is sent, updating the position of the player (and enemy) of the other user's game. However, when I attempt to READ this line, it starts reading from the beginning of the buffer, and it seems as if the buffer isn't being cleared because it starts reading the Maze XML file again.
Is there a way to clear the buffer that recv() uses? I can't think of any other reason why the Maze XML is being read twice, when it isn't being sent twice.
Below is the code that receives the XML, character by character. This is the server's code, the client code just reverses the order of sending/receiving the data. Not sure if that's necessary or relevant.
[code]
while (1) { char r;
switch(recv(s_, &r, 1, 0)) {
case 0: // not connected anymore;
// ... but last line sent
// might not end in \n,
// so return ret anyway.
return ret;
case -1:
return "";
// if (errno == EAGAIN) {
// return ret;
// } else {
// // not connected anymore
// return "";
// }
}
ret += r;
if (r == '<') {
counter = 0;
check = "";
}
check += r;
if (counter == 6 && check.compare(ender) == 0)
{
return ret;
}
//if (r == '\n') return ret;
counter++;
}
[/code]
And this is the code that sends/receives the different XML files.
[code]
Socket* s=in.Accept();
cout << "Accepted a Call from a Client." << endl;
// Here is where we receive the first (Maze) XML File, and
// send our maze as XML
string mazeS = s->ReceiveLineMaze();
TiXmlDocument testDoc;
testDoc.Parse(mazeS.c_str(), 0, TIXML_ENCODING_UTF8);
testDoc.SaveFile("ServerTestDoc.xml");
//testDoc.SaveFile("testXMLFromString.xml");
Tile** theirMaze = readXML(testDoc);
TiXmlDocument theMaze = maze->mazeToXML();
//theMaze.SaveFile("ClientTestWrite.XML");
TiXmlPrinter printer;
theMaze.Accept(&printer);
string toSend = printer.CStr();
cout << toSend << endl;
s->SendLine(toSend);
//RENDER STUFF IN THIS LOOP
bool inOurMaze = false;
while(boolValues->running) {
// This next line is where I want to receive the update on position
// but instead it reads the Maze XML file again, the one I read up
// above
string posReceive = s->ReceiveLineUpdate();
TiXmlDocument theirPos;
theirPos.Parse(posReceive.c_str(), 0, TIXML_ENCODING_UTF8);
... This is where I process the update XML ...
TiXmlDocument updatePos = maze->updatePositionXML();
TiXmlPrinter printerPos;
updatePos.Accept(&printerPos);
string posSend = printer.CStr();
s->SendLine(posSend);
[/code]
Any help is appreciated. If it isn't clear up top, let me summarize.
I first swap an XML file that details the Maze itself. This works fine. Then I attempt to swap the update XML files, that update the player/enemy positions for the other user. But when I attempt to use recv(...), it starts to read the Maze file again, NOT the update file. It's...perplexing.
Oh, and here's the send code (very simple):
[code]
s += '\n';
send(s_,s.c_str(),s.length(),0);
[/code]
where s_ is the socket and s.c_str is the string that needs to be sent (in this case the different XML files).
As #Martin points out, the issue is definitely with the code. Few things to check, looks like the data is read into the buffer "ret" and that's under your control. Is that getting flushed / cleared each time (the code does not make that clear). If this is fine, check the client code to ensure that the data is sent correctly.
Best option is to debug thru your send and receive functions in the IDE, you should be able to spot whats wrong.