Reading binary files - c++

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 ...

Related

Reading value with I2C protocol from magnetoscope

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

trying to append new text to an existing file using fwrite() with mode "a+" but get weird string written

I am writing a program that is to insert texts to a file every time when it is called. I don't want to rewrite the entire file, and I want the new text could be inserted to a new line. Here is my test code:
void writeFile()
{
FILE *pFile;
char* data = "hahaha";
int data_size = 7;
int count = 1;
pFile = fopen("textfile.bin","a+");
if (pFile!=NULL)
{
fwrite (data, data_size, count, pFile);
fclose (pFile);
}
}
At the first time it got called, everything worked fine. A new file was created and the data was successfully written. But when I called it again and expected that a new data to be inserted, I got weird strings in the file, something like:慨慨慨栀桡桡a.
I am not really familiar with C++ I/O functions. Can someone tell me what I did wrong? Also, any suggestion for appending text to the next line?
I think you are running into a code set issue, and the program you're using to look at the file you write expects to find UTF-16 data in the file.
I base this on an analysis of the string you quote:
慨慨慨栀桡桡a
When that (UTF-8) data is converted to Unicode values, I get:
0xE6 0x85 0xA8 = U+6168
0xE6 0x85 0xA8 = U+6168
0xE6 0x85 0xA8 = U+6168
0xE6 0xA0 0x80 = U+6800
0xE6 0xA1 0xA1 = U+6861
0xE6 0xA1 0xA1 = U+6861
0x61 = U+0061
0x0A = U+000A
The Unicode values U+6168 is represented in little-endian as bytes 0x68 0x61, and the ASCII code for h is 104 (0x68) and for a is 97 (0x61). So, the data is probably written correctly, but the interpretation of the data that is written is incorrect.
As I noted in a comment:
If you want lines in the file, you'll need to put them there (by adding newlines to the data that is written), because fwrite() won't output any newlines unless they are in the data it is given to write. You have written a null byte to the file (because you used data_size = 7), which means the file is not really a text file (text files don't contain null bytes). What happens next depends on the code set you're using.
The trailing single-byte codes in the output appear because the second null byte isn't visible in what's pasted on this page, and the trailing U+000A was added by the echo in the command line I used for the analysis (where utf8-unicode is a program I wrote):
echo "慨慨慨栀桡桡a" | utf8-unicode
Change your code to this:
char* data = "hahaha\0";
pFile = fopen("textfile.bin","a+");
if (pFile!=NULL)
{
fwrite (data, sizeof(char), strlen(data), pFile);
fclose (pFile);
}

QSerialPort reads hex values sepereatly

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

Append quint16/unsigned short to QByteArray quickly

In my project I'm working with QByteArrays appending data to them as the program goes. Most of the time, a simple quint8 gets appended just fine using QByteArray::append(). But when a quint16 gets appended, only 1 byte gets appended instead of 2.
QByteArray ba = QByteArray::fromHex("010203");
quint number(300);//300 in hex is 012c
ba.append(number);//What should be appended instead of just number?
//the current incorrect result is
ba.toHex() == "0102032c"
//the desired result is
ba.toHex() == "010203012c"
I've already tried this, but it just inserts the value as a string (4 bytes):
ba.append(QByteArray::number(number, 16));
What should I append to the QByteArray so both bytes of "number" get appended instead of just one byte? Also, the fastest method possible is preferred since this program needs to have great performance times. So absolutely no converting to QStrings.
Thanks for your time.
On its own, QByteArray only supports appending bytes; to append a big-endian representation of fixed-size integer types you can build your own operator<< (or what you prefer) overloads using the appropriate bit shifts:
QByteArray &operator<<(QByteArray &l, quint8 r)
{
l.append(r);
return l;
}
QByteArray &operator<<(QByteArray &l, quint16 r)
{
return l<<quint8(r>>8)<<quint8(r);
}
QByteArray &operator<<(QByteArray &l, quint32 r)
{
return l<<quint16(r>>16)<<quint16(r);
}
This allows you to write code like:
QByteArray b;
b<<quint16(300); // appends 0x01 0x2c
b<<quint8(4); // appends 0x04
b<<quint16(4); // appends 0x00 0x04
b<<quint32(123456); // appends 0x00 0x01 0xe2 0x40
b<<quint8(1)<<quin16(2)<<quint32(3); // appends 0x01 0x00 0x02 0x00 0x00 0x00 0x03
You should probably avoid writing
QByteArray b;
b<<1;
because in theory the output depends on the size of the current platform integer (although AFAIK on all platforms supported by Qt int is 32 bit).

QtDataStream::writeRawData reorders my bytes

I am trying to save a raw byte array into a file:
mDataStream.writeRawData( ( (const char *)&testPacket), 188);
The test packet is just an array of unsigned char, the packet is copied in the right size, but the bytes are reordered. ie: 0x47 0x00 0x10 0x20 ... becomes 0x00 0x47 ox20 0x10.
This looks like an endianness problem, but i've tried setting the byte order to little endian with unsuccessful results.