Reputation: 3076
I have open working connection to a emulated serial port created with tty0tty nullmodem emulator via QSerialPort and I can write data to it like:
QSerialPort serial_stream;
...
serial_stream.setPortName(QString("/dev/tnt0"));
bool loc = serial_stream.open(serial_stream.ReadWrite)
...
serial_stream.write(buf);
I open a terminal and make a connection to the connected (in this case tnt1) tnt-port (e.g. tnt0 <-> tnt1 are connected) via "screen":
screen /dev/tnt1
When I execute the program I get the expected input (here "buf") on the screen. But how can I send data the way back to the opened port in Qt so that I can do the following to read data:
int size = serial_stream.bytesAvailable();
QByteArray data = serial_stream.read(size);
I already tried to stop the program with "sleep"...:
#include <unistd.h>
...
usleep(15*1000000);
...and send the data to it like this:
echo “TEXT“ > /dev/tnt1
But it does not work. I am glad for your help!
Upvotes: 0
Views: 3789
Reputation: 3076
In two ways it is possible to build up a tty0tty-connection (between two virtual ports). Both ways may require the kernel header files. For the 2. it is definitively necessary otherwise an error while make is inevitable.
(1.) The short way:
cd
to [Path to tty0tty-folder]/tty0tty/pts
sudo ./tty0tty
Then the two connected pseudo terminal slaves should be shown:
(/dev/pts/X) <=> (/dev/pts/Y)
with X, Y variable.
(2.) the longer way (but more or less permanent):
Maybe the persisting across boots does not work so it is necessary to repeat the following parts of the Installation guide after reboot:
sudo depmod
sudo modprobe tty0tty
sudo chmod 666 /dev/tnt*
After execute ls /dev/tnt*
a list of ports shoud be shown:
/dev/tnt0 ... /dev/tnt7
The connection can be tested with cat:
Open a terminal[1] and let show the output of one pseudo/native terminal device:
cat /dev/pts/X
or (2.)cat /dev/tnt0
Open another terminal[2] and write to this pseudo/native terminal device:
echo "message" > /dev/pts/Y
or (2.)echo "hello" > /dev/tnt1
The output should be shown in terminal[1]:
message
Additional info: To stop cat press: Ctrl + Z
Add the serialport-reference to the Qt-specific configuration options in the [projectname].pro
-file:
QT += serialport
Additional info: It is allowed to put all references in one line:
i.e.
QT+= core gui serialport ...
Add required header file in the desired [name].h
-file:
#include <QtSerialPort/QSerialPort>
Add two QSerialPort-objects, set the path of the terminal devices via void QSerialPort::setPortName(const QString &name)
and open the ports via bool QSerialPort::open(OpenMode mode)
with desired permissions (ReadOnly
, WriteOnly
, ReadWrite
). Example:
std::string tty0ttyPort1 = "/dev/tnt0";// or = "/dev/pts/X
std::string tty0ttyPort2 = "/dev/tnt1";// or = "/dev/pts/Y
QSerialPort qport1;
QSerialPort qport2;
qport1.setPortName(QString(tty0ttyPort1.c_str()));
bool isOpen1 = qport1.open(qport1.ReadWrite);//Read and Write permission
std::cout << "isOpen1: " << isOpen1 << std::endl;
qport2.setPortName(QString(tty0ttyPort2.c_str()));
bool isOpen2 = qport2.open(qport2.ReadWrite);
std::cout << "isOpen2: " << isOpen2 << std::endl;
isOpen1
and isOpen2
should be true
:
isOpen1: 1
isOpen2: 1
Additional info 1: Maybe is it required to execute the compiled code with super user permission:
cd
to [Path to compiled project folder]/[projectname]
sudo [executable_file]
or run as super user su
(inadvisable)Additional info 2: If the following warning appears...:
QSocketNotifier: Can only be used with threads started with QThread
...there is no Qt event loop which should allways be in the main()
-function:
int main(int argc, char *argv[]){
QCoreApplication a(argc, argv);
//My Testcode (Showed above in section 3.3)
return a.exec();
}
(1.) Without Signals:
Use qint64 QIODevice::write(const char * data)
to write from one QSerialPort to another. Use qint64 QIODevice::read(char * data, qint64 maxSize)
or QByteArray QIODevice::readAll()
to read the sended data. Here it is import to know that it is necessary to use bool QIODevice::waitForReadyRead(int msecs)
after sending the data via QIODevice::write()
otherwise it will not work. I recommend also to use bool QIODevice::waitForBytesWritten(int msecs)
. Example:
const char* sendMessage = "myMessage";
std::cout << "sendMessage: " << sendMessage << std::endl;
qport1.write(sendMessage);
qport1.waitForBytesWritten(2000);
qport2.waitForReadyRead(2000);//required
const char* readMessage = qport2.readAll().data();
std::cout << "readMessage: " << readMessage << std::endl;
Should give the output:
readMessage: myMessage
If it is desired to read a defined number of bytes use QIODevice::read()
:
const char* readMessage = qport2.read(5);
std::cout << "readMessage: " << readMessage << std::endl;
Should give the output:
readMessage: myMess
Additional info: To check how many bytes are available to read use qint64 QIODevice::bytesAvailable() const
. Example:
std::cout << qport2.bytesAvailable() << std::endl;
(2.) With Signals:
In the constructor of a Class it is possible to connect a private slot to the readyRead()
signal using QObject::connect()
:
Classname::Classname(){
...
QObject::connect(&qport1, SIGNAL(readyRead()), this, SLOT(myPrivateSlotFunction()));
//with "qport1" as sender and "this" as receiver
}
...
Classname::myPrivateSlotFunction(){
...
const char* readMessage = qport1.readAll().data();
...
}
Upvotes: 3