I'm using Qt's QSerialPort library to communicate with RS232. I connected ReadyRead signal to my readData() slot;
connect(comms,SIGNAL(readyRead()),this,SLOT(readData()));
When i send a string like "Hello World!" I can read all of data with comms.readAll() and comms.bytesAvailable() returns 12.
But when i send "Hello World!\n\r" it reads "Hello World!" and "\n\r" parts sepereatly and comms.bytesAvailable() returns 12 first, then 2.
And it's getting worse when i send hex bytes like (with no spaces)
0x0F 0x00 0x43 0x11 0x00 0x04 0x11 0x00 0x02 0x70
It reads values correctly but 1 or 2 bytes at a time. I tried waitForRead() but that doesn't help.
How can i read all incoming bytes at a time even it's not standart letter?
Try reading from the port while bytes are available:
if (f_port->bytesAvailable()) { // If there are bytes available
QByteArray f_data; // data container
f_data.clear();
if (f_port->open(QIODevice::ReadWrite)) { // Try to open the port
while(f_port->bytesAvailable()) { // Reading loop
f_data.append(f_port->readAll());
}
f_port->flush();
f_port->close();
}
qDebug() << f_data; // Check the result
}
Unfortunately you cannot be sure to have read all data.
You have to collect incoming data in some intermediate buffer and analyse it for commands complying to your protocol definition. That is, is must meet certain requirements like fixed length or particular starting byte (0x02 for instance) or ending byte (\r comes to mind) or a combination of those.
One way to do it is accumulating a buffer with the bytes you obtain.
Then verify if it's a correct command(that is up to you decide what is correct) and trigger the command you wanna do.
Also you should have a timer to remove trash from the buffer.
Let's see with an small pseudocode
static QByteArrray s_vBuffer;
readData()
{
s_vBuffer.append(....);
bool bValidCommand=VerifyCommand(s_vBuffer);
if(bValidCommand)
{
QByteArray vCommand=ExtractCommand(s_vBuffer);//also removing the part of the command
ExecuteCommand(vCommand);
}
else
{
//if timeout clear s_vBuffer
}
}
Other techniques involves checksums , CRC etc at the end of your command.etc
Related
I'm pretty new still to all this. So please excuse me if there is something obvious.
I have been struggling with the included datasheet for a magnetoscope. For some reason it seems like everything is working, but when I wave a magnet at it, I'm not really getting any response in the serial.
So here is some information.
#include <Wire.h>
void setup() {
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial communication at 9600bps
}
void loop() {
int reading = 0;
int Address = 30;
Wire.beginTransmission(Address);
Wire.write(byte(0x03));
Wire.write(byte(0x04));
Wire.endTransmission();
Wire.requestFrom(Address, 2);
delay(10);
if (2 <= Wire.available()) {
reading = Wire.read();
reading = reading << 8;
reading |= Wire.read();
Serial.println(int(reading));
}
delay(250); // wait a bit since people have to read the output :)
}
With this code, I receive a number.
-5637
-5637
-5637
-5637
-5637
But then if I remove the following line Wire.write(byte(0x03));, my output does not change. The value from the device is supposed to be expressed as two's complement.
So at first I thought I didn't know how to send multiple bytes to the device, but after some research I found that I was doing it right (I think).
Then if I only put Wire.write(byte(0x03)); I receive "0" as response. Reading the datasheet I see that response 0 means that the command is invalid.
I included the datasheet to this post. Can someone point me in the right dirrection? The IC I'm using is an LSM303DLHC and I'm using it from this "sheild".
Here is the datasheet.
The following picture is a picture of the communication of the bus.
I believe the following code does this, which is like Table 11 in the datasheet:
Wire.beginTransmission(Address); // START and write to device address 0x1E
Wire.write(byte(0x03)); // Set the register pointer to sub-address 0x03
Wire.write(byte(0x04)); // Write a value of 0x04 to sub-address 0x3
Wire.endTransmission(); // STOP.
Then I suspect the device's register pointer gets automatically incremented from register 0x03 to 0x04. And then the rest of your code maybe reads two bytes from sub-address 0x04 and 0x05.
You didn't express your intention for your code but I suspect the above is NOT what you intended. My guess is that you intend to read two bytes from device address 0x1E, sub-address 0x03 and sub-address 0x04. Is that right?
You should be doing an operation like what is described in Table 13.
Wire.beginTransmission(Address); // START and write to device address 0x1E
Wire.write(byte(0x03)); // Set the register pointer to sub-address 0x03
Wire.requestFrom(Address, 2); // REPEAT-START and read 2 bytes from sub-address 0x03 and 0x04
I'm using a measurement device which sends (binary) float values using a tcp socket with up to 70 kHz.
My goal is to read these values as fast as possible and use them in other parts of my program.
Till now I'm able to extract value by value using a QTcpSocket and QDataStream:
First I create the socket and connect the stream to it
mysock = new QTcpSocket(this);
mysock->connectToHost(ip, port);
QDataStream stream(mysock);
stream.setByteOrder(QDataStream::LittleEndian);
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
Then I read from the socket and write the stream data to my float value
while(true) //only for test purpose (dont stop reading)
if (mysock->waitForReadyRead())
{
while (mysock->bytesAvailable() >= 6)
{
QByteArray a = mysock->read(6); //each value sent is 6 bytes long
stream.skipRawData(2); //first 2 bytes don't belong to the number
float result;
stream >> result;
//qDebug()<<result;
}
}
When I measure the iteration frequency of the while(true) loop I'm able to achieve about 30 kHz.
Reading multiple values per read I can reach up to 70 Khz. (Not taking other calculations into account which might slow me down)
My questions are:
If I read multiple values at once, how do I extract these values from the QDataStream? I need a 6 bytes spacing with only 4 bytes containing the value.
Answer: In my case there is 2 bytes (trash) followed by a known number of values, for example 4 bytes for a float, 4 bytes for another float, 2 bytes for an uint16.
stream >> trashuint16 >> resultfloat1 >> resultfloat2 >> resultuint16
Expands 1: I can configure my device to send different values of different type (int, float) which need to be written to different variables.
Answer: Same.
Is there a more efficient way to read many values from a QTcpSocket?
Answer: Anwered in the comments.
Update (to answer some questions):
Max rate in Bytes: 70 kHz x 6 Byte (for one value) = 420 kB/s (Doesnt seem that much :))
Update 2
New Question: When i start a transaction (using stream.startTransaction) I would like to know whats inside that stream in binary code.
I dont understand how QDataStream::startTransaction works. How many bytes will be read? what happens with the data I dont extract using >>?
I've tried the following:
if (mysock->waitForReadyRead())
{
stream.startTransaction();
char *c = new char[40];
stream.readRawData(c, 40); //I want to know whats really inside
QByteArray a(c);
qDebug() << a <<stream.status();
if (!stream.commitTransaction())
break;
}
Doing this again and again, I'll sometimes get status = -1 (read too much) and sometimes not. How do I get the "size" of the stream?
Your code has couple mistakes.
You are doing direct reading from socket when in the same time you are using QDataStream. This can break stuff.
Also your code is assuming that your application will receive data in same chunks as it was sent by other end. You do not have such warranty! It may happen that you will receive chunk data which are ending in middle of your frame. It works just by pure luck or you are ignoring some bugs of your application.
This should go like this:
while(true)
if (mysock->waitForReadyRead()) // IMO doing such loop is terrible approach
// but this is Out of the scope of question, so ignoring that
{
while (true)
{
stream.startTransaction();
float result;
qint32 somedata
stream >> somedata >> result; // I do not know binary format your application is using
if (!in.commitTransaction())
break;
AddDataToModel(result, somedata);
}
}
Edit:
From comment:
Please correct me if I'm wrong, but if I want 2 bytes to be discarded I need to do "stream >> someint(2 byte) >> somefloat(4 byte)"? How can I handle many values in stream?
qint16 toBeDiscarded;
float value;
// note stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
// is needed to read float as 32 bit floating point number
stream >> toBeDiscarded >> value;
ProcessValue(value);
I'm trying to read serial data from an Arduino UNO using an ofSerialobject and assign it as an int.
I am able to read in individual bytes, however, the values I'm receiving in the openframeworks console are not the same as the values I'm reading in the Arduino serial monitor.
I have provided screenshots of the respective consoles:
My Arduino code is simply the basic "AnalogReadSerial" example available with the Arduino IDE.
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
delay(1); // delay in between reads for stability
}
Whereas my C++ code is mostly copied from the documentation for the ofSerial readByte function.
void serialReader::setup()
{
serial.listDevices();
vector <ofSerialDeviceInfo> deviceList = serial.getDeviceList();
serial.setup("COM4", 9600); //open the first device and talk to it at 9600 baud
}
void serialReader::printByteToConsole()
{
int myByte = 0;
myByte = serial.readByte();
if ( myByte == OF_SERIAL_NO_DATA )
printf("\nno data was read");
else if ( myByte == OF_SERIAL_ERROR )
printf("\nan error occurred");
else
printf("\nmyByte is %d ", myByte);
}
Any insight into what may be causing this disparity between the readings would be greatly appreciated. Thank you.
Arduino's Serial.println translates the raw bytes into their ASCII equivalent and then sends those bytes followed by linefeed (10) and carriage return (13) bytes. So, the raw byte 12 is sent as 4 total bytes -- two bytes representing the ASCII 1 (49), 2 (50) and then (10) and (13) for the new line characters. So, since openFrameworks does not automatically translate the ASCII values back into raw bytes, you are seeing the ASCII version. The Arduino console shows you the ASCII version as readable text.
You can see the translation between ASCII and raw bytes (Decimal / aka DEC) here:
http://www.asciitable.com/
If you want the two numbers to match on both sides, consider using Serial.write in Arduino to write the raw bytes without ASCII translation and new line characters.
I am doing a synchronous read/write using boost-asio. The data is coming in binary format, without boundary, the length information is encoded in the packet format. So it is important to read in with specified size. Can ip::tcp::iostream do that? Can someone provide an example? Thanks.
Simple:
boost::asio::read(socket, buffers, boost::asio::transfer_exactly(your_fixed_size));
I work on a program wich send different data with different size. I use a fixed header of 8 byte to encode the size, then, I add the data :
enum { header_length = 8 }; //const header length
I get the size (m_outbound_data is a std::string == a serialized object)
//give header length
std::ostringstream header_stream
header_stream << std::setw(header_length) //set a field padding for header
<< std::hex //set next val to hexadecimal
<< m_data_out.m_outbound_data.size(); //write size in hexa
m_data_out.m_outbound_header = header_stream.str(); //m_outbound_head == size in hexa in a std::string
//m_outbound_header = [ 8 byte size ]
//m_outbound_data = [ serialized data ]
//write all data in the std::vector and send it
std::vector<boost::asio::const_buffer> buffer;
buffer.push_back(boost::asio::buffer(m_data_out.m_outbound_header));
buffer.push_back(boost::asio::buffer(m_data_out.m_outbound_data));
And for reading, you need to read in 2 time : 1st read 8 byte to get the size, then read the data in a vector and deserialize into object :
struct network_data_in {
char m_inbound_header[header_length]; //size of data to read
std::vector<char> m_inbound_data; // read data
};
I use this struct to get data, call read on the m_inbound_header to fill the buffer with size first, then, in the handle :
//get size of data
std::istringstream is(std::string(m_data_in.m_inbound_header, header_length));
std::size_t m_inbound_datasize = 0;
is >> std::hex >> m_inbound_datasize;
m_data_in.m_inbound_data.resize(m_inbound_datasize); //resize the vector
then call again read with the m_inbound_data on buffer, this result of reading exactly the data sent
In the second handle_read you juste have to deserialize the data :
//extract data
std::string archive_data (&(m_data_in.m_inbound_data[0]),m_data_in.m_inbound_data.size());
std::istringstream archive_stream(archive_data);
boost::archive::text_iarchive archive(archive_stream);
archive >> t; //deserialize
Hope that help you !
TCP is a stream-based protocol. This means that whatever you read is just a stream of bytes.
Let's consider an example: you have a message of a fixed size and you send it over TCP. How can the program at the other end read the entire message? there are two ways, one is to surround you message with control chracters (e.g. STX at start and ETX at end). At the start, the program would discard any chars before STX, then read any other chars into the message buffer until ETX is encountered.
Another way is to encode the message length in a fixed-size header (which apparently is your case). So the best thing you can do is figure out a way to read the message length, parse it and read the remaining bytes accordingly.
I've to read data from binary file.
This binary data format is:
0x00 0x00 0x01 - is delimiter
after this delimiter there is raw data byte array.
So, to sum up, my binary file looks like:
0x00 0x00 0x01 (here is raw data byte)
0x00 0x00 0x01 (here is another block
of raw data bytes) 0x00 0x00 0x01 ....
So i've wrote such code to parse my file (I'm not very familiar with C)
ifstream inp("myfile.bin",ios::binary);
char b1, b2, b3;
while (!inp.eof())
{
inp.read(&b1,sizeof(b1));
inp.read(&b2,sizeof(b2));
inp.read(&b3,sizeof(b3));
//finding first delimiter (data starts from delimiter)
while (!((0==b1)&&(0==b2)&&(1==b3)))
{
b1=b2;
b2=b3;
if (inp.eof())
break;
inp.read(&b3,sizeof(b3));
}
if (inp.eof())
break;
char* raw=new char[65535];
int rawSize=0;
inp.read(&b1,sizeof(b1));
inp.read(&b2,sizeof(b2));
inp.read(&b3,sizeof(b3));
raw[rawSize++]=b1;
raw[rawSize++]=b2;
if (inp.eof())
break;
//reading raw data until delimiter is found
while (!((0==b1)&&(0==b2)&&(1==b3)))
{
raw[rawSize++]=b3;
b1=b2;
b2=b3;
if (inp.eof())
break;
inp.read(&b3,sizeof(b3));
}
rawSize-=2; //because of two bytes of delimiter (0x00 0x00) would be added to raw
//Do something with raw data
if (inp.eof())
break;
inp.putback(1);
inp.putback(0);
inp.putback(0);
delete []raw;
}
But sometimes this code falls into infinite loop.
Could you advice me something?
Thanks
I think the problem there is that putback fails. As far as i recall, putback is guaranteed to work only once; second invocation will fail if the internal read buffer is aligned (that is, very rarely; seems like your situation).
To fix, get rid of putback. First of all, move the loop commented as "finding first delimiter" out of the outer while loop: the comment suggests that this code should only run once. After you do it, pay attention that at the beginning of the outer while loop, the sequence 0x00 0x00 0x01 has just been found, so the code doesn't have to use putback and look for it again.
You're using feof() wrong, it's only valid after a read has been attempted and failed.
How do you know that your magic byte sequence 0 0 1 doesn't appear inside the data? If the data is just a "binary array" that doesn't sound like it provides much of a guarantee ...