Sending hex data via serial communication with QT - c++

I am finding way to send hex data via serial communication
i searched it several times and followed some ways but it didn't work.
i checked that protocol is working with using other software that sending hex data to device
below is my code
const char data[]={0xAA,0xAA,0x01,0x00,0x00,0x0E,0x00,0x01,0x00,0x00,0x00,0x2D,0x37,0x1D,0xAA,0xAA,0x01,0x00,0x00,0x0E,0x00,0x0C,0x10,0x00,0x00,0x01,0x76,0x13};
serial->setPortName(("COM8"));
initSerialPort(); // baud rate and etc
if(serial->open(QIODevice::ReadWrite))
{
qDebug()<<"Port is open!";
if(serial->isWritable())
{
qDebug()<<"Yes, i can write to port!";
int size = sizeof(data);
serial->write(data,size);
}
}
and when i use other declare like uint16_t, uchar, write function cannot convert argument 1 from uint16_t (or uchar) to const char *
i did try also this form
QByteArray hex("AAAA0100000E00010000002D371DAAAA0100000E000C100000017613");
QByteArray data = QByteArray::fromHex(hex);
and it also didnt work

You can do this using only QByteArray like:
connect(serial, &QSerialPort::readyRead, this, &YourClass::doSomeStuff);
QByteArray arr;
arr += static_cast<char>(0xAA);
arr += static_cast<char>(0x01);
<...>
serial->setPortName("COM8");
initSerialPort(); // baud rate and etc
if(serial->open(QIODevice::ReadWrite) && serial->isWritable())
serial->write(arr);

Related

toLocal8bit send over TCP

Im creating TCP Server/Client application in QT Creator framework. I want to get some data from UI input field and send it over TCP.
Im doing something like this in client application:
void MainWindow::on_btn_login_clicked()
{
QByteArray text = (ui->login_input->text()).toLocal8Bit();
char* out = text.data();
connection->ConnectAndSendData(out);
}
and in the ConnectAndSendData function:
void TcpConnect::ConnectAndSendData(const char* data)
{
socket = new QTcpSocket(this);
int port = 1234;
socket->connectToHost("localhost", port);
if(socket->waitForConnected(3000))
{
qDebug() << "connected to s. localhost at port " << port;
socket->flush();
socket->write(data, sizeof(data));
qDebug() << data << "\n";
socket->waitForReadyRead();
char* serverresponse;
socket->read(serverresponse, 128);
if(serverresponse == MESSAGE_LOGINRQ)
socket->write(data);
socket->flush();
socket->close();
}
else
{
/**/
}
}
and the data in line socket->write(data, sizeof(data)); is properly send to server, but when server echoes it, it looks like "something/x00/x00/x00/x00" or somethinglike that. Also when i to do something like this:
#define MESSAGE_WANTLOGIN "wanlogin"
socket->write(MESSAGE_WANTLOGIN, sizeof(MESSAGE_WANTLOGIN));
message is messed up with those null signs.
on the server side receiving data look as simple as:
void Thread::readyRead()
{
socket->flush();
QByteArray data = socket->readAll();
qDebug() << "data received: " << data;
if(data == MESSAGE_WANTLOGIN)
{
socket->write(MESSAGE_LOGINRQ);
} else
{
qDebug() << "error not messageloginrq";
}
}
and like u can assume, though i send "wanlogin" message, server receiving something like "wanlogin/x00/x00" and this if obviously returns false.
this trash is applied on the end of data, and this impossible to check what message was send. The other thing is that maximum size of send data is 8 chars, but also to data of this length trash is applied so it looks like "wanlogin/x00/x00"; however, when i type more chars, for example 10, the send data is just cut to 8 signs, with no /x00s.
So my question is how to clear data from those /x00s and how to send more than 1 byte of information(i need it e.g. to send login and password of user). Sorry if there's some stupid mistake, its my first client/server application which also using multithreading for each client.
sizeof(data) is 4 or 8 depending if you are on a 32-bit or 64-bit machine. It is not the size of your data, but the size (in byte) of a pointer.
So what happens is that your actual wanlogin is in fact a 6 character string, and you end up sending 2 more bytes. In this case you are lucky: the char array returned by data() is null-terminated, so you have one extra 0 that you can access, but accessing the second 0 is undefined behavior i.e anything can happen.
The solution is to use strlen() instead of sizeof. Or, better, to directly call write() with a QByteArray by changing ConnectAndSendData(const char* data) to ConnectAndSendData(const QByteArray &data).
void MainWindow::on_btn_login_clicked()
{
const QByteArray text = (ui->login_input->text()).toLocal8Bit();
connection->ConnectAndSendData(text);
}
void TcpConnect::ConnectAndSendData(const QByteArray & data)
{
socket = new QTcpSocket(this);
quint16 port = 1234;
socket->connectToHost("localhost", port);
if(socket->waitForConnected(3000))
{
qDebug() << "connected to s. localhost at port " << port;
socket->write(data);
...
}
...
}

recieving Frame of 8 bytes in QT Creator GUI via serial port

I'm working to send frame of 8 bytes to Micro-controller Xmega128a1 (via RS232) the frame looks like this
{header1,header2,CMD,D1,D2,D3,D4,CRC},
for example
{0x55,0xaa,0xFF,0x59,0xfd,0x64,0x68,0x32},
Micro-controller has to resend the frame back to PC, if it's 'correct'.
I built GUI in QT Creator I defined the Headers (header0=0x55, header1=0xaa) and CMD=01 also calculated the CRC,
the user has to enter the data field in the Line_Edit which is value in RPM(Real value) The Micro-controller Receive the frame byte byte and resend the full frame, so I have to send the frame in the form of bytes, when I send the frame I receive the headers, command and CRC correctly, but data field Received not in proper way such in the picture below, my problem is with converting the input value in the Line_Edit to bytes to be send inside the frame, when I tried to send the value 1265 RPM I received the frame {55aa0100209e44fb} but I want to receive the frame look like this {55aa014F109e44fb}, where: (1265)DC=(4F1)HEX, I couldn't figure what's the problem with my code:
the way I read data from serial port:
void MainWindow::read()
{
uint64_t size = serial->bytesAvailable();
if (size > 0)
{
QByteArray data;
data.append(serial->readAll());
ui->termial_textEdit->append(data.toHex());
}
}
the send value in RPM code:
#define CMD_SPEED_REF2 0x01
void MainWindow::on_speed_ref2_lineEdit_returnPressed()
{
uint8_t frame2[8];
frame2[0] = 0x55;
frame2[1] = 0xAA;
frame2[2] = CMD_SPEED_REF2;
float fdata2 = 0.0f;
fdata2 = ui->speed_ref2_lineEdit->text().toFloat();
uint8_t *data2 = new uint8_t();
data2 = (uint8_t*)&fdata2;
frame2[3] = data2[0];
frame2[4] = data2[1];
frame2[5] = data2[2];
frame2[6] = data2[3];
frame2[7] = frame2[2] ^ frame2[3] ^ frame2[4] ^ frame2[5] ^ frame2[6];
serial->write((char*)frame2, 8);
}
this Image Illustrate what happens:recived frame
I think your code mostly looks ok. The one area that looks very suspect is your conversion of the text/string back into binary.
Since you convert your binary into a string with:
ui->termial_textEdit->append(data.toHex());
You should in theory be able to use the following to convert it back:
// Convert back...
QByteArray binaryData = QByteArray::fromHex(ui->speed_ref2_lineEdit->text().toLatin1());
// Print to debug to check it...
qDebug("d1: %02x, d2: %02x...etc...\n", binaryData[0], binaryData[1]);
// or just
qDebug() << "data:" << binaryData.toHex() << endl;
Not on my qt PC until Monday so I can't verify this code, so there may be a bug in there somewhere... I'll check it on Monday!
For serial comms I always use QByteArray's instead of char/uint8_t arrays (when using Qt) because they are so easy to use. You can re-build your array like this:
QByteArray frame2;
frame2.append((char) 0x55); // not sure you need to cast it here
frame2.append((char) 0xAA);
frame2.append((char) CMD_SPEED_REF2);
:
etc
:
If you MUST send as a char * then just do:
serial->write(frame2.data(), 8);
//or
serial->write(frame2.data(), frame2.size()); // if you want to send the whole thing

copying char to QbyteArray with datastream contains some extra bytes

Overview of problem:
OS : Ubuntu
I am using qt utility to receive video data from remote machine( remote machine is using gstreamer to send live data) and write that data to port say 5000.
Port 5000 is already bind to another gstreamer utility. this utility listen to port 5000 and convert data into video streaming. Obviously things are not exactly working and I cant view video. So I have two questions:
1) With Qt utility , is it legal to write to port 5000 although port is bind to gstreamer utility.
2) I am using 3rd party library and its api to receive data from external source. The data get stored in array of characters. If I convert that into qbytearray then qbytearray has same size as char buffer. example
rc = zco_receive_source(sdr, &reader, bytesToRead, buffer); // this is 3rd part function
qDebug() << " copy buffer size =" << rc; // genrally this size is 1412
QByteArray msgRecvd;
msgRecvd = QByteArray(reinterpret_cast<char*>(buffer), rc);
if(! msgRecvd.isEmpty() )
{
qDebug() << " size of msgRecv =" << msgRecvd.size();// again 1412
udpSock->writeDatagram( msgRecvd, QHostAddress::LocalHost, 5000 );
}
But if I use QDataStream then QbyteArray got 4 extra bytes. code shown below
rc = zco_receive_source(sdr, &reader, bytesToRead, buffer); // this is 3rd part function
qDebug() << " copy buffer size =" << rc; // genrally this size is 1412
QByteArray msgRecvd;
QDataStream dataStream( &msgRecvd, QIODevice::WriteOnly );
dataStream.writeBytes( ( const char* )buffer, rc );
if(! msgRecvd.isEmpty() )
{
qDebug() << " size of msgRecv =" << msgRecvd.size();// got 4 extra bytes .. size is 1415. why ???
udpSock->writeDatagram( msgRecvd, QHostAddress::LocalHost, 5000 );
}
I want to know why QbyteArray got extra character and do I need to serialise data to forward it to port 5000?
Answering on second question:
Try QDataStream::writeRawData().
Form Qt docs:
QDataStream & QDataStream::writeBytes(const char * s, uint len)
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.

Determine Data Type on a TCP Socket in Qt

I am writing a program to send images captured from an OpenCV window over a TCP connection, using Qt libraries to setup the connections etc.
I have to functions (below) which are both working to send either text or a byte array. The problem I have is at the other end how can I tell if the data coming in is plain text, or an array containing an image. Is there an inbuilt way to do this, or do I need to put a byte at the start of the data to tell the receiver what data is coming? I already put the array length at the start of the serialized image data.
void Screenshot_controller::sendText(std::string textToSend)
{
if(connectionMade)
{
std::string endLine = "\r\n";
textToSend = textToSend + endLine;
const char * textChar = textToSend.c_str();
sendSocket->write(textChar);
sendSocket->flush();
qDebug() << "Text Sent from Server";
}
}
void Screenshot_controller::sendData(QByteArray dataToSend)
{
if(connectionMade)
{
sendSocket->write(dataToSend);
sendSocket->flush();
qDebug() << "Data Sent from Server";
}
}
You need to define the protocol yourself, whether that's with a byte, string, JSON header or any other method. The Tcp socket will allow you to transfer the data, but doesn't care what that data is; it's up to you to handle that.

Sending data over socket from C server to qt Client

I am in bit of a problematic situation here:
I have a simple C server (can't use Qt TcpServer, limitations of the embedded board) which sends double data (generated by GPIO ports) over tcpsocket using send(). If I have a simple C client (in my Linux PC) then I am able to get the real time data as is generated with the help of recv(). Here is my server code:
int main (void){
int s,b,l,fd,sa,bytes,on=1;
char buf[BUF_SIZE],fname[255];
struct sockaddr_in channel;
long long sum=0;
double average=0;
int i,j;
int srno=0;
s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s<0)
{
printf("socket creation failure");
exit(0);
}
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on));
memset(&channel,0,sizeof(channel));
channel.sin_family=AF_INET;
channel.sin_addr.s_addr=htonl(INADDR_ANY);
channel.sin_port=htons(SERVER_PORT);
b=bind(s, (struct sockaddr *)&channel,sizeof(channel));
if(b<0)
{
printf("bind error");
exit(0);
}
listen(s,5);
while(1)
{
printf("waiting for request\n");
sa=accept(s,0,0);
if(sa<0)
{
printf("accept failure");
}
for (i=1; i<=56; i++) //for 10 sec >> 56
{
for(j=1;j<=20;j++)
{
//more than 100 lines of code here
}
average=(sum/20)*1.22;
send(sa, &average, sizeof(average), 0);
//int tmp = htonl((uint32_t)average); //tried this also
//send(sa, &tmp, sizeof(tmp), 0);
// int n = write(sa, &average, sizeof(average)) //and tried this also
// if(n<0){
// printf("error");}
printf("%lld \n", average);
srno++;
sum=0;
average=0;
}
}
remove_gpio();
close(s);
return 0;
}
But I am unable to get to display the data in Qt Client, it is driving me crazy. In my QtextEdit I get non-ASCII characters, whatever I try. inside my startRead() I did
...
QByteArray Data = socket->readAll();
ui->textEdit->append(QString(Data));
...
I also tried using other methods bytesavailable() canreadLine(), and also went through other links but was unsuccessful.
Non-ASCII crazy characters is what I get everytime. Sorry not able to give a pic due to low rep.
I need help regarding sending double data through socket and be able to work with the data or atleast display them in a QTextEdit/QPlainTextEdit.
Thanks.
as ciphor said you are trying to display binary directly as text
you'll want to use a datastream to convert
QByteArray Data = socket->readAll();
QDataStream dstream (Data);
double d;
while(!dstream.atEnd())
{
dstream >> d;
ui->textEdit->append(QString::number(d));
}
You need to actually design, specify, and implement a protocol. Otherwise, it's as if your client is speaking Chinese and your server listening for Spanish. Because TCP is a byte-stream protocol, you need to precisely specify how the two programs will interchange data as a stream of bytes. Then design both sides to send a stream of bytes in accord with the specification and receive a stream of bytes in accord with the specification. To help you get started, you should thoroughly study the specifications for existing protocols layered on top of TCP such as IRC, NNTP, SMTP, IMAP, and so on.
The conversion specifier for double is "lf".
The "lld" the code is using is for long long integer.
So use:
printf("%lf\n", average);
You are sending the data in format of double precision binary, but trying to display as a string in your client, that is the reason of non-ASCII.
If you want to send ASCII, you should convert the data into string format before sending it at server side.
char buf[20] = {0};
average=(sum/20)*1.22;
sprintf(buf, "%lld", average);
send(sa, &buf[0], strlen(buf), 0);