Qt Serial Communication not sending all data - c++

I am writing a Qt application for serial communication with a Qorvo MDEK-1001. All built-in serial commands I've had to use work fine except for one: aurs n k, where n and k are integers corresponding to the desired rate of data transmission (e.g. "aurs 1 1\r"). Write function is:
void MainWindow::serialWrite(const QByteArray &command)
{
if(mdek->isOpen())
{
mdek->write(command);
qDebug() << "Command: " << command;
//mdek->flush();
}
}
If I send the command "aurs 1 1\r". It doesn't actually get sent to the device until I send another command for some reason. So if I subsequently send the "quit" command to the device, the returned data from the device is: "aurs 1quit", which registers as an unknown command. Any assistance getting this command to send properly is appreciated.
I've tried a bunch of stuff (setting bytes to write as second parameter in write(), using QDataStream, appending individual hex bytes onto QByteArray and writing that), but nothing has worked. This is the first time I've had to use Qt's serial communication software so I've probably missed something obvious.
On Linux Manjaro (same thing happens on Windows 8.1)
Connection settings: 8 data bits, Baud: 115200, No Flow Control, No Parity, One Stop Bit

Related

Boost ASIO Serial Communication with Arduino: Error above 9600 bps

I'm developing a C++ interface to communicate with na Arduino UNO which is running some code.
To communicate with the Arduino, i'm using boost asio library. My application works well at a baud rate of 9600bps. Now, i wanted to communicate faster with the arduino, so, i tried to communicate at 115200bps, 57600bps, etc, without success.
At 115200bps, it seems that boost::write is sending two non-desirable bytes (both the same, with value ASCII 240 - this only happens for the first data transaction, so if i unplug and plug again the Arduino, this bytes will be sent during the first communication ). At this baud rate i can read the data that is being sent by Arduino (which is wrong for the first data communication, but is correct for the next ones).
At 57600bps, those 2 wrong bytes are not sent, but data is not read from arduino (it seems that write is not sending nothing).
The code to write to the serial is fairly simple, is just the boost::write and the code to read from the serial is just a loop and a boost::read of one byte (communications are synchronous just to test if everything was okay, which is not for higher baud rates than 9600bps).
The write function:
void sendMessage(char *c, unsigned int size) {
serial.write(c, size);
return;
}
The read function:
void readMessage(void) {
char c;
uint8_t count = 0;
for (;;)
{
boost::asio::read(serial, boost::asio::buffer(&c, 1));
cout << "Received char: " << static_cast<unsigned int>(c) << endl;
if (count == 3 ){
return;
}
count++;
}
return;
}
I know that the problem is not in the side of the arduino (that's why i posted the question here and not in the arduino stackexchange) because, using realterm and sending the exact same bytes that i send using boost, i get the proper reply from the Arduino for every baud rate (9600, 57600 and 115200bps).
If anyone can help, i would be appreciated, since at this moment i don't know which is the problem (and i'm a beginner to boost).
Best regards
Edit
At 74880 bps, I recieve four times the byte with value 252.

How to read from serial device in C++

I'm trying to figure out how I should read/write to my Arduino using serial communication in Linux C++. Currently I'm trying to read a response from my Arudino that I "trigger" with
echo "g" > /dev/ttyACM0"
I've tried looking at the response from my Arduino in my terminal, by using the following command:
tail -f /dev/ttyACM0
This is working as it should. Now I want to do the same thing in a C++ application. So I made this test
void testSerialComm()
{
std::string port = "/dev/ttyACM0";
int device = open(port.c_str(), O_RDWR | O_NOCTTY | O_SYNC);
std::string response;
char buffer[64];
do
{
int n = read(device, buffer, sizeof buffer);
if (n > 0) {
response += std::string(buffer);
std::cout << buffer;
}
} while (buffer[0] != 'X'); // 'X' means end of transmission
std::cout << "Response is: " << std::endl;
std::cout << response << std::endl;
close(device);
}
After a few "messages", the transmission gets a little messed up. My test application writes the response characters in random order and something's not right. I tried configuring the /dev/ttyACM0 device by this command:
stty -F /dev/ttyUSB0 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
No dice. Can someone help me understand how to communicate with my Arduino in C++?
The shown code opens /dev/ttyACM0, attempts to seek to the end of this "file", and based on the resulting file position allocates an old-fashioned, C-style memory buffer.
The problem with this approach is that you can only seek through regular, plain, garden-variety files. /dev/ttyACM0 is not a regular file. It's a device. Although some devices are seekable, this one isn't. Which, according to the comments, you've discovered independently.
Serial port devices are readable and writable. They are not seekable. There's no such thing as "seek"ing on a serial port. That makes no sense.
To read from the serial port you just read it, that's all. The operating system does maintain an internal buffer of some size, so if some characters were already received over the serial port, the initial read will return them all (provided that the read() buffer size is sufficiently large). If you pass a 1024 character buffer, for example, and five characters were already read from the serial port read() will return 5, to indicate that accordingly.
If no characters have been read, and you opened the serial port as a blocking device, read() will block at least until one character has been read from the serial port, and then return.
So, in order to read from the serial port all you have to do is read from it, until you've decided that you've read all there is to read from it. How do you decide that? That's up to you. You may decide that you want to read only until reading a newline character. Or you may decide that you want to read only until a fixed #n number of characters have been read. That's entirely up to you.
And, of course, if the hardware is suitably arranged, and you make the necessary arrangements with the serial port device to respect the serial port control pins, and, depending on your configuration, the DCD and/or DSR pins are signaled to indicate that the serial port device is no longer available, your read() will immediately return 0, to indicate a pseudo-end of file condition on the serial port device. That's also something that you will need to implement the necessary logic to handle.
P.S. neither C-style stdio, nor C++-style iostreams will work quite well with character devices, due to their own internal buffering algorithms. When working with serial ports, using open(2), read(2), write(2), and close(2) is better. But all of the above still applies.

Can't read from serial device

I'm trying to write a library to read data from a serial device, a Mipex-02 gas sensor. Unfortunately, my code doesn't seem to open the serial connection properly, and I can't figure out why.
The full source code is available on github, specifically, here's the configuration of the serial connection:
MipexSensor::MipexSensor(string devpath) {
if (!check_dev_path(devpath))
throw "Invalid devpath";
this->path = devpath;
this->debugout_ = false;
this->sensor.SetBaudRate(SerialStreamBuf::BAUD_9600);
this->sensor.SetCharSize(SerialStreamBuf::CHAR_SIZE_8);
this->sensor.SetNumOfStopBits(1);
this->sensor.SetParity(SerialStreamBuf::PARITY_NONE);
this->sensor.SetFlowControl(SerialStreamBuf::FLOW_CONTROL_NONE);
this->last_concentration = this->last_um = this->last_ur = this->last_status = 0;
cout << "Connecting to "<< devpath << endl;
this->sensor.Open(devpath);
}
I think the meaning of the enums here are obvious enough. The values are from the instruction manual:
UART characteristics:
exchange rate – 9600 baud,
8-bit message,
1 stop bit,
without check for parity
So at first I was using interceptty to test it, and it worked perfectly fine. But when I tried to connect to the device directly, I couldn't read anything. the RX LED flashes on the devices so clearly the program manages to send something, but -unlike with interceptty- the TX LED never flash.
So I don't know if it's sending data incorrectly, if it's not sending all of it, and I can't even sniff the connection since it only happens when interceptty isn't in the middle. Interceptty's command-line is interceptty -s 'ispeed 9600 ospeed 9600 -parenb -cstopb -ixon cs8' -l /dev/ttyUSB0 (-s options are passed to stty) which is in theory the same options set in the code.
Thanks in advance.

Emitting signal when bytes are received in serial port

I am trying to connect a signal and a slot in C++ using the boost libraries. My code currently opens a file and reads data from it. However, I am trying to improve the code so that it can read and analyze data in real time using a serial port. What I would like to do is have the analyze functions called only once there is data available in the serial port.
How would I go about doing this? I have done it in Qt before, however I cannot use signals and slots in Qt because this code does not use their moc tool.
Your OS (Linux) provides you with the following mechanism when dealing with the serial port.
You can set your serial port to noncanonical mode (by unsetting ICANON flag in termios structure). Then, if MIN and TIME parameters in c_cc[] are zero, the read() function will return if and only if there is new data in the serial port input buffer (see termios man page for details). So, you may run a separate thread responsible for getting the incoming serial data:
ssize_t count, bytesReceived = 0;
char myBuffer[1024];
while(1)
{
if (count = read(portFD,
myBuffer + bytesReceived,
sizeof(myBuffer)-bytesReceived) > 0)
{
/*
Here we check the arrived bytes. If they can be processed as a complete message,
you can alert other thread in a way you choose, put them to some kind of
queue etc. The details depend greatly on communication protocol being used.
If there is not enough bytes to process, you just store them in buffer
*/
bytesReceived += count;
if (MyProtocolMessageComplete(myBuffer, bytesReceived))
{
ProcessMyData(myBuffer, bytesReceived);
AlertOtherThread(); //emit your 'signal' here
bytesReceived = 0; //going to wait for next message
}
}
else
{
//process read() error
}
}
The main idea here is that the thread calling read() is going to be active only when new data arrives. The rest of the time OS will keep this thread in wait state. Thus it will not consume CPU time. It is up to you how to implement the actual signal part.
The example above uses regular read system call to get data from port, but you can use the boost class in the same manner. Just use syncronous read function and the result will be the same.

Character encoding problem with QextSerialPort (Qt/C++)

I am developing a Qt/C++ programme in QtCreator that reads and writes from/to the serial port using QextSerialPort. My programme sends commands to a Rhino Mark IV controller and must read the response of those commands (just in case they produce any response). My development and deployment platform is Windows XP Professional.
When the Mark IV sends a response to a command and my programme reads that response from the serial port buffer, the data are not properly encoded; my programme does not seem to get plain ASCII data. For example, when the Mark IV sends an ASCII "0" (decimal 48) followed by a carriage return (decimal 13), my buffer (char *) gets -80 and 13. Characters are not properly encoded, but carriage returns are indeed. I have tried using both read (char *data, qint64 maxSize) and readAll ().
I have been monitoring the serial port traffic using two monitors that interpret ASCII data and display the corresponding characters, and the data sent in both ways seem to be correctly encoded (they are actually displayed correctly). Given that QByteArray does not interpret any character encoding and that I have tried using both read (char *data, qint64 maxSize) and readAll (), I have discarded that the problem may be caused by Qt. However, I am not sure if the problem is caused by QextSerialPort, because my programme send (writes) data properly, but does not read the correct bytes.
I have also tried talking to the Mark IV controller by hand using HyperTerminal, and the communication takes place correctly, too. I set up the connection using HyperTerminal with the following parammeters:
Baud rate: 9600
Data bits: 8
Parity bits: 0
Stop bits: 1
Flow control: Hardware
My programme sets up the serial port using the same parammeters. HyperTerminal works, my programme does not.
I started using QextSerialPort 1.1 from qextserialport.sourceforge.net and then tried with the latest source code from QextSerialPort on Google Code, and the problem remains.
What is causing the wrong character encoding?
What do I have to do to solve this issue?
48 vs. -80 smells like a signed char vs. unsigned char mismatch to me. Try with explicit unsigned char* instead of char*.
Finally, I have realized that I was not configuring the serial port correctly, as suggested by Judge Maygarden. I did not find that information in the device's manual, but in the manual of a software product developed for that device.
The correct way to set up the serial port for connecting to the Mark IV controller is to set
Baud rate: 9600
Data bits: 7
Parity: even
Stop bits: 2 bits
Flow control: Hardware
However, I am still wondering why did HyperTerminal show the characters properly even with the wrong configuration.