write and read hexadecimale trame qt serial port - c++

How can I write and read hex data when I open serial port?
if (serial->isOpen()) {
qDebug() << "seccus: " ;
static const char buff[] = {0xA1, 0xFF, 0xFF, 0x00,97};
serial->write(buff,sizeof(buff));
}
if (serial->bytesAvailable()) { // If there are bytes available
QByteArray f_data; // data container
f_data.clear();
if (serial->open(QIODevice::ReadWrite)) { // Try to open the port
while(serial->bytesAvailable()) { // Reading loop
f_data.append(serial->readAll());
}
serial->flush();
}
qDebug()<< "the result" << f_data; // Check the result
}
if(!serial->isOpen())
qDebug() << "carte disconnect"<<serial->errorString();

To debug your issue, I would start with simplifying what you're trying to do. Try writing some test code to start, to make sure things work as you expect:
Test serial is open - should not be
Open serial
Test serial is open - should be
Test if bytes are available - should not be
write data to serial. Flush.
Test if bytes are available - should be
Read and print to screen (i.e test your reading it correctly)
Close the serial port - test its not open
Perhaps if one of these steps doesn't work as you expect, you can at least focus on why that particular part is not working.
Good luck.

Related

How to use C++ for transmitting data using xbee?

For a project i need to establish 2 way xbee communication. But I have a problem sending data from my pc. I use cpp with termios to transmitt a char array but on the xbee tx pin I do only get a signal (I observe this on an oscilloscope) when one of the chars is 0x0A.
The XBee module is on a 30011662-02 board, which is connected to my pc via usb.
I thought maybe this is some kind of starting parameter needed by the xbee board to transmit but couldnt find any information on this.
ctx->debug = debug;
//open USB port for read/write and check success
ctx->fd = open(devFileName, O_RDWR | O_NOCTTY); //opens the usb port for reading
if (ctx->fd < 0) {
cerr << "Could not open the USB Port. Try adding User to group dialout!" << endl;
return 0;
}
//is the opened port a terminal?
if(!isatty(ctx->fd)) {
close(ctx->fd);
errno = ENOTTY;
return 0;
}
//setup termios
tcgetattr(ctx->fd, &(ctx->oldtio));
cfmakeraw(&newtio);
cfsetispeed(&newtio, baudrate);
cfsetospeed(&newtio, baudrate);
tcsetattr(ctx->fd, TCSANOW, &newtio); //connects fd to newtio
tcflush(ctx->fd, TCIOFLUSH); //discards data not transmitted or received
lseek(ctx->fd, 0, SEEK_END);
ctx->bufIO = fdopen(ctx->fd, "r+");
bool connection_status=0;
unsigned char frame_id=0x00;
unsigned char checksum=0xff;
int j=0;
while(!connection_status){
checksum=0xFF;
unsigned char buffer[] = {
0x7E, //start delimiter
0x00,0x07,//length of the data packet
0x01,//API identifier (refer to XBee module manual for further details)
frame_id++, //frame id
0x00,0x0B,//destination address
0x00,//options
0x02,0x03,//data: 0,receiver address,mode
0x00}; //checksumm
for(unsigned int i=0;i<sizeof(buffer);i++){
checksum-=buffer[i];
}
cout << buffer << endl;
j++;
buffer[10]=checksum;
fwrite(buffer,sizeof(char),sizeof(buffer),ctx->bufIO);
usleep(2000000);
}
I do expect to see data on the xbee tx pin in every itteration of the while loop but so far it only works when frame_id is 0x0A or i manually enter 0x0A in the array buffer. But still it does not seem to be sending the correct data. Maybe you have some hints for me.
You're probably missing a setting (maybe O_NDELAY?) for the serial port (tty) and it's in line mode. You might want to look at this serial driver used in an Open Source XBee Host Library written in ANSI C (instead of C++). You might even be able to build your application on top of that library. At the very least, you could compile the samples and see if they work with your module as a way to verify your wiring and XBee configuration.

QSerialPort has bytes available but can't read

I'm writing a Qt GUI application that receives and sends data to an Arduino over serial. It writes correctly, but when trying to read it doesn't work.
My problem is:
I have an Arduino code that sends things over Serial, I programmed it to turn on and off a LED on pin 13 depending on the received data:
#define ARDUINO_TURNED_LED_ON "LEDON"
#define ARDUINO_TURNED_LED_OFF "LEDOFF"
#define PC_REQUESTED_LED_STATE_CHANGE u8"CHANGELED"
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
String serialCmd = "";
bool ledState=false;
void loop()
{
// put your main code here, to run repeatedly:
if (Serial.available())
{
serialCmd=Serial.readString();
if (serialCmd==PC_REQUESTED_LED_STATE_CHANGE)
{
if (ledState)
{
digitalWrite(13, LOW);
Serial.write(ARDUINO_TURNED_LED_OFF);
}
else
{
digitalWrite(13, HIGH);
Serial.write(ARDUINO_TURNED_LED_ON);
};
ledState=!ledState;
serialCmd = "";
}
}
}
I'm using the following signal and slot at MainWindow class:
#define ARDUINO_TURNED_LED_ON "LEDON"
#define ARDUINO_TURNED_LED_OFF "LEDOFF"
#define PC_REQUESTED_LED_STATE_CHANGE u8"CHANGELED"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/* Create Object the Class QSerialPort*/
serialPort = new QSerialPort(this);
/* Create Object the Class Arduino to manipulate read/write*/
arduino = new Arduino(serialPort);
//connect signal:
connect(serialPort, SIGNAL(readyRead()), this, SLOT(ReadData()));
}
//slot
void MainWindow::ReadData()
{
QString received = arduino->Read();
qDebug() << "received data:" << received;
if (received==ARDUINO_TURNED_LED_ON)
{
qDebug() << "led on";
}
else if (received==ARDUINO_TURNED_LED_OFF)
{
qDebug() << "led off";
}
}
And the Arduino::Read() method that is called by the previous slot:
QString Arduino::Read()
{
QString bufRxSerial;
qDebug() << "bytes available:" << serialPort->bytesAvailable();
/* Awaits read all the data before continuing */
while (serialPort->waitForReadyRead(20)) {
bufRxSerial += serialPort->readAll();
}
return bufRxSerial;
}
When writing to the Arduino it works well, the LED changes as it should, the problem happens when Qt tries to read the replied data.
In most of the times that the Arduino sends something, the signal is emitted and serialPort->bytesAvailable() returns a number that is not zero, but
serialPort->waitForReadyRead(20) times out without receiving anything and serialPort->readAll() returns an empty QString. If I use serialPort->waitForReadyRead(-1) the window freezes.
The weirdest thing is that, in a random moment that something is sent, everything works well and the function returns all the data that couldn't be read previously.
Here's an example of what happens:
1st attempt (fails)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns on)
Arduino writes ARDUINO_TURNED_LED_ON ("LEDON") to the serial port
Qt reads an empty QString from the Arduino
2nd attempt (fails)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns off)
Arduino writes ARDUINO_TURNED_LED_OFF ("LEDOFF") to the serial port
Qt reads an empty QString from the Arduino
3rd attempt (this is a random attempt that everything works)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns on)
Arduino writes ARDUINO_TURNED_LED_ON ("LEDON") to the serial port
Qt reads "LEDONLEDOFFLEDON" from the Arduino, that is everything that couldn't be read previosly.
4th attempt (fails)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns off)
Arduino writes ARDUINO_TURNED_LED_OFF ("LEDOFF") to the serial port
Qt reads an empty QString from the Arduino
5th attempt (this is another random attempt that everything works)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns on)
Arduino writes ARDUINO_TURNED_LED_ON ("LEDON") to the serial port
Qt reads "LEDOFFLEDON" from the Arduino, that is everything that couldn't be read previosly.
I tested using the Arduino IDE serial monitor and it worked as it was supposed to be: I wrote "CHANGELED", then the LED changed and the Arduino replied "LEDON" or "LEDOFF" all the times.
What can I do to solve this problem?
Thanks
Edit: the complete code can be found here
The Read method is incorrect and unnecessary. You should never use the waitFor methods. You also shouldn't be using QString when dealing with simple ASCII data that QByteArray handles fine:
class MainWindow : ... {
QByteArray m_inBuffer;
...
};
void MainWindow::ReadData() {
m_inBuffer.append(arduino->readAll());
QByteArray match;
while (true) {
if (m_inBuffer.startsWith((match = ARDUINO_TURNED_LED_ON))) {
qDebug() << "led on";
} else if (m_inBuffer.startsWith((match = ARDUINO_TURNED_LED_OFF))) {
qDebug() << "led off";
} else {
match = {};
break;
}
}
m_inBuffer.remove(0, match.size());
}
The deal is simple: ReadData can be called with any number of bytes available - even a single byte. Thus you must accumulate data until a full "packet" is received. In your case, packets can only be delineated by matching a full response string.
You'd make your life much easier if Arduino sent full lines - replace Serial.write with Serial.println. Then the lines are packets, and you don't need to buffer the data yourself:
void MainWindow::ReadData() {
while (arduino->canReadLine()) {
auto line = arduino->readLine();
line.chop(1); // remove the terminating '\n'
QDebug dbg; // keeps everything on a single line
dbg << "LINE=" << line;
if (line == ARDUINO_TURNED_LED_ON)
dbg << "led on";
else if (line == ARDUINO_TURNED_LED_OFF)
dbg << "led off";
}
}
See? It's much simpler that way.
You can also leverage Qt to "simulate" Arduino code without running real Arduino hardware, see this answer for an example.
This sounds like a buffering problem. Your Qt application receives the bytes, but there is nothing that tells it the reception is complete. I would add line feeds (\n) as terminator character after each string, just use Serial.println() instead of Serial.write(). Then you can use readLine() in Qt and always be sure that what you get is exactly one complete command string.
If you're on Linux you could also try to stty your device to raw with
stty -F /dev/ttyACM0 raw
to have the serial characters sent straight through instead of default line buffering (see What’s the difference between a “raw” and a “cooked” device driver?).
Note that then you might get a new issue: Your Qt application might be so fast that you receive only one letter at a time in your callback.

How to read data from the serial port in QT?

I am creating a script in QT for reading the format packages (AA), (BB), etc from serial port. I open the serial port, but when I go to check inside the QByteArray values, comes back that I could not read any value.
This is my code
...
QSerialPort *serialPort = new QSerialPort();
serialPort->setPortName("ttyUSB0");
serialPort->setParity(QSerialPort::NoParity);
serialPort->setBaudRate(QSerialPort::Baud9600, QSerialPort::AllDirections);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
serialPort->open(QIODevice::ReadOnly);
if (serialPort->isOpen()) {
qDebug() << "Serial port is open...";
QByteArray datas = serialPort->readAll();
if (datas.size() == 0) {
qDebug() << "Arrived data: 0";
} else {
for (int i = 0; i < datas.size(); i++){
if (datas.at(i)) {
qDebug() << datas[i];
}
}
}
} else {
qDebug() << "OPEN ERROR: " << serialPort->errorString();
}
serialPort->close();
qDebug() << "...serial port is closed!";
return 0;
...
You called readAll() immediately after open(). It probably took the computer a few nanoseconds to get from one to the other.
At 9600 baud, each byte of data takes slightly more than one millisecond to transfer. It would be absolutely impossible for any data to have arrived in that short an interval, so that's why you got no data.
Serial ports don't begin buffering incoming data until you open them (how could they, what baud rate and other settings would be used for receiving and buffering when no program has the port open?)
Use either a blocking read function of some sort (such as readLine()) or an event loop that reacts to data when it arrives.

qt 5.2 serial port write issues with windows 7

We are using FTDI serial port CHIP in our hardware. Now we have working code in Linux and we moved to windows 7. We get some weird problems.
The Problem:
We can't write data to Serial Port without running other console application which do this:
serial.setPortName("COM3");
if (serial.open(QIODevice::ReadWrite)) {
bool success = serial.setBaudRate(QSerialPort::Baud9600) &
serial.setStopBits(QSerialPort::OneStop) &
serial.setDataBits(QSerialPort::Data8) &
serial.setParity(QSerialPort::NoParity) &
serial.setFlowControl(QSerialPort::NoFlowControl);
qDebug() << "Connected to usb device: " << (success ? "OK" : "FAIL");
while(true) {
if(serial.waitForReadyRead(-1)) {
QByteArray out = serial.readAll();
for(int i=0; i< out.length(); i++) {
qDebug() << (int) out[i];
}
}
}
serial.close();
So its just loop with read all. Hardware dosen't send anything, so read is just infinity loop. After closing and running our write program it runs correctly.
char* input;
input = new char[size+3];
QByteArray bytearr;
for(int i=0;i<size+2;i++) {
input[i] = (char) package[i];
bytearr.append((unsigned char) package[i]);
}
QString serialPortName = "COM3";
QSerialPort serialPort;
serialPort.setPortName(serialPortName);
serialPort.open(QIODevice::ReadWrite);
serialPort.write(bytearr);
serialPort.flush();
serialPort.close();
After running read everything works, but without read all, it wont work. What are we doing wrong?
Thanks.
We had similar problem in our application with a board with FTDI chip. We tried to write bytes with 19200 baud/sec, had though in real about 1200 baud/sec (seen using oscilloscope). The problem was closing the serial port right after writing a byte. Just waiting using QThread::msleep(5) before closing the port helped. It seems, that the device gets a reset or something during close operation and latest bytes are sent with false baudrate and other parameters.
I found out that the QT serial port SW requires you to process QT events in order to work.
Putting a qApp->processEvents() in the loop before the read made it work for me.
(QT 4.8.5 on Windows-7)

Trouble sending Data with QSerialPort

I am trying to write a QT application that can communicate with a propeller over USB. Reading through the documentation QSerialPort seems to be exactly what I need. For a simple test, I am trying to send the number "2" to my propeller project. The project itself has its own OLED screen that I can read results on. Here is the QT code itself:
this->Serial=new QSerialPort(this);
this->Serial->setPortName("/dev/ttyUSB0");
this->Serial->setBaudRate(QSerialPort::Baud9600);
connect(this->Serial,SIGNAL(error(QSerialPort::SerialPortError)),this,SLOT(errorReport(QSerialPort::SerialPortError)));
if(this->Serial->open(QIODevice::ReadWrite))
{
QByteArray dayArray;
QDataStream stream(&dayArray, QIODevice::WriteOnly);
stream << 2;
qDebug()<< dayArray.toHex();
qDebug()<< this->Serial->portName();
if(this->Serial->setDataBits(QSerialPort::Data8))
{
qDebug()<<"bits set to 8";
}
this->Serial->write(dayArray.toHex());
this->Serial->waitForBytesWritten(-1);
this->Serial->close();
}
and the error report slot is:
void serial::errorReport(QSerialPort::SerialPortError error)
{
if(error!=0)
qDebug()<<"ERROR:"<<endl<<error;
}
The console debug statements print this:
"00000002"
"ttyUSB0"
bits set to 8
However when I read the values the propeller recieves, it ranges from 0xD0, 0xF0, or 0xE0, not the 0x02 I was expecting. The baud rates in the code match that of the chip and I am really not sure what is wrong. Can anyone point out the fault?
EDIT:
I know that the propeller code isn't the problem as it works fine with the Arduino's IDE serial console.
I finally figured it out. The working code is as follows:
if(this->Serial->open(QIODevice::ReadWrite))
{
this->Serial->setBaudRate(QSerialPort::Baud9600);
this->Serial->setParity(QSerialPort::NoParity);
this->Serial->setStopBits(QSerialPort::OneStop);
this->Serial->setFlowControl(QSerialPort::NoFlowControl);
this->Serial->setDataBits(QSerialPort::Data8);
QByteArray dayArray;
dayArray[0]=2;
this->Serial->write(dayArray);
this->Serial->waitForBytesWritten(-1);
this->Serial->close();
}