Replace STDIN with a Serial port
-
wrote on 12 Dec 2014, 21:52 last edited by
So I'm working on a project with an "Olinuxino A20":https://www.olimex.com/wiki/A20-OLinuXino-MICRO and its supposed to replace an HMI (human machine interface). We didn't want to go for the touch screen since it will be used pretty roughly and we don't want it to get broken. So instead we went ahead for an old ATM style, with buttons on both sides.
For the moment I've been programming on a desktop computer for simplicity and emulating the event's with the keyboard with a handler like this one:
@void PyCGui::keyPressEvent(QKeyEvent* event){
switch( event->key() ) {
//~ stuff done with that key
@In the real situation, our hardware keyboard is another microcontroler that sends the key-codes (as chars) over a serial port. I found that Qt4.8 had some classes to replace directly the stdin with any device you like, but currently I can't find how to do it.
I've even tried the 'rough way'
@kp_fd = open("/dev/ttyS7", O_RDWR );
close(STDIN_FILENO);
dup(kp_fd);
@But it didn't work!
-
Hi and welcome to devnet,
Are you thinking of something like "QSerialPort":http://doc.qt.io/qt-5/qserialport.html ?
-
wrote on 12 Dec 2014, 22:04 last edited by
But how do I connect that class to the GUI events?
I'm currently using 2 serial ports in the program for communication and I write the C code directly where it's needed since I'm more used to that. But if have to use this class to connect it with the GUI I have no problem in changing it!
-
It will offer you an easier more integrated way to get the data from your serial ports. From there you can create and post key events to the event loop and have them processed like it would come from a standard keyboard
-
wrote on 12 Dec 2014, 23:12 last edited by
From there you can create and post key events to the event loop
Something like this?
@
QSerialPort *keypad= new QSerialPort("/dev/ttyS7", (QObject *)my_gui);
@And that's it? How do I manually connect the signals from the port to my gui?
-
You should rather write a little class that represent that keypad and have the QSerialPort in there. You'll connect that class to your GUI to keep things cleanly separated.
On a side note, QWidget is a QObject so there's no need to cast. Furthermore, never use c style cast with QObject derived class, use qobject_cast.
-
wrote on 13 Dec 2014, 12:03 last edited by
It' very easy to do. I know and use Olimex A20 with serial devices and graphic interaction.
I suggest you to write a class based on QSerialPort and implement events on special data.
If you want I can to it for you.Which kind of hardware do you use?
-
wrote on 14 Dec 2014, 17:26 last edited by
What i'm missing is: should I create a new thread for it to monitor the serial port and create the events? or not?
-
wrote on 14 Dec 2014, 17:35 last edited by
In this case I normally use an Object based on QThread to manage the serial device. I normally add to the object the Tcp features, because sometimes the serial device can be attached with a rs232 - tct converter.
The object has to manage the device and can emit an event at particular situations.
For example, if you have a usb - rfid reader, when a tag will read, the object emit an event with the read tag code. -
wrote on 14 Dec 2014, 20:04 last edited by
So it has to be something like this:
@
class Keypad : public Qthread {public: Keypad(){ initialize_serial_port(); this->start();
}
private: QSerialPort serial; void run() { while(1) { serial.get_stff(); generate_event_for_gui(); }
}
};@ -
Technically, threads are not mandatory at all in this case unless you start heavy processing on the data you received.
-
wrote on 14 Dec 2014, 20:49 last edited by
But I don't see where and how to create a loop for the events in the GUI.
-
You already have an event loop after you call app.exec(). Use QSerialPort in asynchronous mode
-
wrote on 14 Dec 2014, 21:18 last edited by
but how do I get in that loop!?! That's what I don't get
-
You don't need to get in that loop, once app.exec is called, the loop runs. Events are sent, signals and slots activates when needed etc.
-
wrote on 14 Dec 2014, 22:58 last edited by
Yeah.. that's what I'm trying to do now. Since I can't use the serial port in a separated thread.
So what now? Do I have to create a signal handler for the serial?
I'm quite new to GUIs writing, I'm mainly a microcontroller programmer. Sorry if this are really n00b questions. -
I never said it won't work in a separated thread, just that it's really not needed.
Something like this:
@
class KeyPad :: public QObject {
Q_OBJECT
public:
KeyPad(QObject *parent = 0 ) :
QObject(parent)
{
connect(&serialPort, SIGNAL(readyRead()), SLOT(processData()));
}bool initialize(const QString &portName)
{
serialPort.setPortName(portName);
// setup portreturn serialPort.open(QIODevice::ReadWrite); // or ReadOnly if you won't write anything in it
}
signals:
valueChanged(int newValue);private slots:
void processData() {
data.append(serialPort.readAll());
// check if enough data is there
// parse data
// removed processed data from buffer
// emit signal(s)
}private:
QByteArray data;
QSerialPort serialPort;
};
@I've wrote everything in the "header" for brevity only
-
wrote on 14 Dec 2014, 23:19 last edited by
@ connect(&serialPort, SIGNAL(readyRead()), SLOT(processData()));@
I get it now, I was doing right that as you write! SO that's what gets it in the "main event loop" right?
Of course you didn't said it won't work in a separated thread, but I tried just that and it didn't work because of some "can't create new thread issue"
THANKS A LOT!!
-
wrote on 15 Dec 2014, 21:53 last edited by
So I got it, now I can navigate the menues with the serial port as I did with the keyboard. But the only thing that's not working are text entries. Whenever I need to input some text in a QLineEdit widget it doesn't recognizes the input as a keystroke!
@
void Keypad::SerialPortHandler (void){
char buff;serial->read(&buff,1);
QKeyEvent *last_key = new QKeyEvent( QEvent::KeyPress, buff , Qt::GroupSwitchModifier, QString(buff) );
QCoreApplication::sendEvent(pycgui,last_key);
}
@I use Qt::GroupSwitchModifier only to differentiate the events I create from the real one so I can manually delete them. But it's not the reason the input is not working!
-
AFAIK, text input requires a press and a release event
1/20