QSerialPort and sending bytes (with value > 127?) - c++

I have:
QString hex = "0234301c4c49541d4741546f77617220a5a91e42411e43311e44332c30301e45332c30301e47737a74756b613742413303";
QByteArray test = QByteArray::fromHex(hex.toLatin1());
Now, i want to send it over SerialPort:
serial = new QSerialPort(this);
serial->setPortName("ttyACM0");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
if(serial->open(QIODevice::ReadWrite))
{
qDebug()<<"Port is open!";
if(serial->isWritable())
{
qDebug()<<"Yes, i can write to port!";
}
serial->waitForBytesWritten(-1);
serial->write(test.data());
serial->flush(); // Port Error 12 (timed out???)
serial->close()
}
I become no result (also char/byte values they are less than 127 seems to be send, but not those they are over this value)
My question -> how to convert this QByteArray to send all bytes corectly?
(i tried to found the answer in google, but without success / i'm newbie)

You almost certainly do not want to be calling the QSerialPort write overload that takes a const char*. Look at the docs for that overload:
Writes data from a zero-terminated string of 8-bit characters to the device.
But you are NOT writing a zero-terminated C-string, you're writing arbitrary binary data. So you need to call the write overload that takes a QByteArray directly, like this:
serial->write(test);
As stated in some of the other comments, the stuff about waitForBytesWritten before calling write doesn't make a lot of sense either, but your biggest issue is trying to treat your QByteArray of arbitrary data as a null-terminated C-String.

they was an error in crc code (downloaded from some web-portal)
it was cast to uint16_t instead uint8_t
now it really works.
thank You for help!

Related

Qt: memcpy failed.. How to copy?

My question today is about Qt and the memcpy() function..
I got a QByteArray i_byte_array containing my raw data that I need. First thing I tried is to copy those data in a char* l_array.
Which gives me:
void blablafunctionblabla(const QByteArray& i_byte_array)
{
char* l_array = (char*)malloc(i_byte_array.size());
memcpy(l_array, i_byte_array, i_byte_array.size());
// OR: char* l_array = i_byte_array.data(); // same result
}
When I run the code I expected to copy the whole contents of i_byte_array which is:
i_byte_array values
As a result I get only this...:
l_array value
It seems the copying stopped at the first /0 ignoring the size I request him to copy..
So my questions is Why that happens with memcpy function? And How do I need to proceed in order to copy all raw data? (even /0 which is a useful data for me)
Actually memcpy does not ignore the null character. I guess the IDE (maybe Qt Creator) ignores the null character so you can't see the entire content of the char string.
If you import the l_array to a QByteArray by the following way:
QByteArray ba = QByteArray::fromRawData(l_array, i_byte_array.size());
You will see the content of ba is the same as i_byte_array.
You can check SO's question for the memcpy: How could I copy data that contain '\0' character.

Qt QDataStream: operator>> for quint16 - I didn't get it at all

I have such code:
QByteArray portnoStr = "41034";
quint16 portno;
QDataStream stream(&portnoStr, QIODevice::ReadOnly);
stream >> portno;
std::cout << "portno: " << portno << "\n";
And as completely unexpected it print
portno: 13361
I look at the code of Qt (4x + 5x):
inline QDataStream &QDataStream::operator>>(quint16 &i)
{ return *this >> reinterpret_cast<qint16&>(i); }
At now I understand why it give me such result,
but I can not understand why QDataStream has such strange implementation?
QDataStream is not meant for converting data from one type to another in order to display text. From the docs:
You can also use a data stream to read/write raw unencoded binary data. If you want a "parsing" input stream, see QTextStream.
The QDataStream class implements the serialization of C++'s basic data types, like char, short, int, char *, etc. Serialization of more complex data is accomplished by breaking up the data into primitive units.
A data stream cooperates closely with a QIODevice. A QIODevice represents an input/output medium one can read data from and write data to. The QFile class is an example of an I/O device.
You're using cout to print encoded binary data, which is interpreted as an integer. That data is meant for reading and writing to IO devices, not printing.
Regarding reinterpret_cast to a qint16: since QDataStream simply writes raw binary data, pretending an unsigned int is signed has no effect on the output to the data stream. This is just a cheap way of reusing code: the bits are ultimately written as bits, regardless of type. It's up to you to cast them back to the appropriate data type (quint16) when reading back out from the data stream.

The difference between QDataStream and QByteArray

QTemporaryFile tf;
tf.open ();
QDataStream tfbs (&tf);
tfbs << "hello\r\n" << "world!\r\n";
const int pos = int (tf.pos ());
QByteArray ba;
ba.append ("hello\r\n");
ba.append ("world!\r\n");
const int size = ba.size ();
Basically my question is, what am I doing wrong? Why is pos > size? Should I not be using << ? Should I not be using QDataStream?
Edit: Is there a way to configure QDataStream or QTemporaryFile so that the << operator doesn't prepend strings with 32bit lengths and store the null terminators in the file? Calling QDataStream::writeBytes when I just have a series of quoted strings and QStrings makes for very ugly code.
The answer is in the docs. I'm not going to go over QByteArray, as I believe it's fairly obvious that it is working as expected.
The QDataStream operator<<(char*) overload evaluates to the writeBytes() function.
This function outputs:
Writes the length specifier len and the buffer s to the stream and
returns a reference to the stream. The len is serialized as a quint32,
followed by len bytes from s. Note that the data is not encoded.
So for "hello\r\n", I would expect the output to be:
0,0,0,8,'h','e','l','l','o','\r','\n',0
The 4-byte length, followed by the bytes from the string. The string-ending NULL is probably also being added to the end, which would account for the otherwise mysterious extra two bytes.
So I ended up writing my own helper class to serialize my data:
class QBinaryStream
{
public:
QBinaryStream (QIODevice& iod) : m_iod (iod) {}
QBinaryStream& operator << (const char* data)
{
m_iod.write (data);
return *this;
}
QBinaryStream& operator << (const QString& data)
{
return operator << (data.toUtf8 ());
}
QBinaryStream& operator << (const QByteArray& data)
{
m_iod.write (data);
return *this;
}
private:
QIODevice& m_iod;
};
Should I not be using QDataStream?
In your case maybe QTextStream or even QString would do.
The QTextStream class provides a convenient interface for reading and
writing text.
QTextStream can operate on a QIODevice, a QByteArray or a QString.
Using QTextStream's streaming operators, you can conveniently read and
write words, lines and numbers.
As for QByteArray, Qstring should be preferred to it whenever possible
The QByteArray class provides an array of bytes.
QByteArray can be used to store both raw bytes (including '\0's) and
traditional 8-bit '\0'-terminated strings. Using QByteArray is much
more convenient than using const char *. Behind the scenes, it always
ensures that the data is followed by a '\0' terminator, and uses
implicit sharing (copy-on-write) to reduce memory usage and avoid
needless copying of data.
In addition to QByteArray, Qt also provides the QString class to store
string data. For most purposes, QString is the class you want to use.
It stores 16-bit Unicode characters, making it easy to store
non-ASCII/non-Latin-1 characters in your application. Furthermore,
QString is used throughout in the Qt API. The two main cases where
QByteArray is appropriate are when you need to store raw binary data,
and when memory conservation is critical (e.g., with Qt for Embedded
Linux).

Storing integer to QByteArray using only 4 bytes

It takes 4 bytes to represent an integer. How can I store an int in a QByteArray so that it only takes 4 bytes?
QByteArray::number(..) converts the integer to string thus taking up more than 4 bytes.
QByteArray((const char*)&myInteger,sizeof(int)) also doesn't seem to work.
There are several ways to place an integer into a QByteArray, but the following is usually the cleanest:
QByteArray byteArray;
QDataStream stream(&byteArray, QIODevice::WriteOnly);
stream << myInteger;
This has the advantage of allowing you to write several integers (or other data types) to the byte array fairly conveniently. It also allows you to set the endianness of the data using QDataStream::setByteOrder.
Update
While the solution above will work, the method used by QDataStream to store integers can change in future versions of Qt. The simplest way to ensure that it always works is to explicitly set the version of the data format used by QDataStream:
QDataStream stream(&byteArray, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_10); // Or use earlier version
Alternately, you can avoid using QDataStream altogether and use a QBuffer:
#include <QBuffer>
#include <QByteArray>
#include <QtEndian>
...
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
myInteger = qToBigEndian(myInteger); // Or qToLittleEndian, if necessary.
buffer.write((char*)&myInteger, sizeof(qint32));
#Primož Kralj did not get around to posting a solution with his second method, so here it is:
int myInt = 0xdeadbeef;
QByteArray qba(reinterpret_cast<const char *>(&myInt), sizeof(int));
qDebug("QByteArray has bytes %s", qPrintable(qba.toHex(' ')));
prints:
QByteArray has bytes ef be ad de
on an x64 machine.
Recently I faced the same problem with a little variation. I had to store a vector of unsigned short into QByteArray. The trick with QDataStream did not work for unknown reason. So, my solution is:
QVector<uint16_t> d={1,2,3,4,5};
QByteArray dd((char*)d.data(),d.size()*sizeof(uint16_t));
The way to get the vector back is:
QVector<uint16_t> D;
for(int i=0; i<dd.size()/sizeof(uint16_t); ++i){
D.push_back(*(uint16_t*)(dd.data()+i*sizeof(uint16_t)) );
}

How to convert AS3 ByteArray into wchar_t const* filename? (Adobe Alchemy)

How to convert AS3 ByteArray into wchar_t const* filename?
So in my C code I have a function waiting for a file with void fun (wchar_t const* filename) how to send to that function my ByteArray? (Or, how should I re-write my function?)
A four month old question. Better late than never?
To convert a ByteArray to a String in AS3, there are two ways depending on how the String was stored. Firstly, if you use writeUTF it will write an unsigned short representing the String's length first, then write out the string data. The string is easiest to recover this way. Here's how it's done in AS3:
byteArray.position = 0;
var str:String = byteArray.readUTF();
Alternatively, toString also works in this case. The second way to store is with writeUTFBytes. This won't write the length to the beginning, so you'll need to track it independantly somehow. It sounds like you want the entire ByteArray to be a single String, so you can use the ByteArray's length.
byteArray.position = 0;
var str:String = byteArray.readUTFBytes(byteArray.length);
Since you want to do this with Alchemy, you just need to convert the above code. Here's a conversion of the second example:
std::string batostr(AS3_Val byteArray) {
AS3_SetS(byteArray, "position", AS3_Int(0));
return AS3_StringValue(AS3_CallS("readUTFBytes", byteArray,
AS3_Array("AS3ValType", AS3_GetS(byteArray, "length")) ));
}
This has a ridiculous amount of memory leaks, of course, since I'm not calling AS3_Release anywhere. I use a RAII wrapper for AS3_Val in my own code... for the sake of my sanity. As should you.
Anyway, the std::string my function returns will be UTF-8 multibyte. Any standard C++ technique for converting to wide characters should work from here. (search the site for endless reposts) I suggest leaving it is as it, though. I can't think of any advantage to using wide characters on this platform.