Qserialport Cannot Open Tty After Application Has Previously Been Run by 'Root'

QSerialPort cannot open tty after application has previously been run by `root`

Update: this is a bug in Qt, and will be fixed in version 5.6.2, which is due for release later this month.

On Linux and Mac, QSerialPort creates a lock file in /var/lock/ when opening a serial port. The lockfile has permissions 0644, i.e. only the creator of the file can write to it.

If the process that opened the serial port dies or if the serial port is somehow improperly closed by any other means, the lock file will not be deleted. The lockfile contains the PID of the process that opened the serial port; if the process is no longer running, Qt will attempt to simply take possession of the lock, changing the PID in the file.

However, since the lockfile has 0644 permissions, if the improperly-closing process was run by root, the new process will be unable to delete or overwrite the lockfile, resulting in a permissions error.

This is fixed for version 5.6.2.

Note that QSerialPort does clean up after itself: when its destructor is called, the port is closed and the lockfile is deleted. However, by default, Qt does not call object destructors when SIGTERM or SIGINT causes the program to exit. (Personally, I think this is also a bug, but I recognize that this is more a matter of opinion.)

Also see the suggested dupe question. As can be seen from this question, the current behavior is actually an improvement--previously, the application would simply hang!

QSerialPort is causing a program stop (endless loop?) if opening device

I don't know what Mr. Papp is complaining about; I was able to reproduce your problem without any more information.

On Linux, if the Qt process with an open QSerialPort instance terminates abnormally or the QSerialPort instance is otherwise not destroyed upon process exit, then the lock file hangs around and can cause a problem. A stale lock file shouldn't cause this problem; the lock file contains the crashed application's PID, and the new application instance should recognize that no process with that PID exists and delete the lock immediately before creating a new one. strace will show you the lock file in question repeatedly with increasing backoff time as the new process repeatedly checks to see if the stale lock file has been deleted or whatever. So, delete the file (for example, /var/lock/LCK..ttyS0); you will own the lock file if you ran the application that crashed.

A random side note: if you are using QSerialPort in Python through PyQt5 (which does work, by the way!), be sure you have explicitly deleted the QSerialPort instance before the Python interpreter exits. If you're manipulating the port in IPython, then do "%xdel portobject" before exiting.

It's a dumb workaround, but provided you are using some other mechanism to ensure that you don't have two instances of your program running and using the same port - or if you simply don't care - you could have a line of code delete that lock file before opening the port.

IMHO, Qt shouldn't be emulating completely worthless Windows style nanny state protections in the first place. I can sudo rm -rf / and it happens! I can even rm the serial port. Given such unfettered, primal, god like power, I should be able to open a serial port whenever and however I please...

QSerialPort fails to open /dev/ttyUSB0 on Ubuntu

As Frank suggested, you can always get the error diagnostics with errorString(). See our examples for details.

I cannot reproduce the problem, but based on your comment, your serial port was already used by another process, so this means it is not a QtSerialPort issue. Any other software would have had an issue with this, e.g. a new minicom session.

Glad that it works now. :)

QSerialPort Error: Device Not Open

Add yourself to the dialout group:

sudo usermod -a -G dialout YOURUSERNAME

or

sudo adduser YOURUSERNAME dialout

Then logout and login again to take affect.

How to use a GPIO pin, for serial flow control with Qt?

  1. What is that extra delay being added when I use the naive, QThread::usleep approach, that causes the stretch of the pulse?

Linux is not a real-time operating system a thread sleep suspends the process fo no less than the time specified. During the sleep, other threads and processes may run and may not yield the processor for a longer time than your sleep period, or may not yield at all and consume their entire OS allocated time-slice. Beside that kernel driver interrupt handlers will always preempt a user-level process. Linus has a build option for real-time scheduling, but the guarantees remain less robust that a true RTOS and latencies typically worse.

Note also that not only can your thread be suspended for longer than the sleep period, but the transmission may be extended by more than the number of bits over baud-rate - the kernel driver can be preempted by other drivers and introduce inter-character gaps over which you have no control.


  1. Why the signal-slot approach is not working, since it is event-driven?

The documentation for QSerialPort::waitForBytesWritten() states:

This function blocks until at least one byte has been written to the serial port and the bytesWritten() signal has been emitted.

So it is clear that the semantics of this are that "some data has been written" rather than "all data has been written". It will return whenever a byte is written, then if you call it again, it will likely return immediatly if bytes are continuing to be written (because QSerialPort is buffered and will write data independently of you application).


  1. In general, how can I instruct the pin to go active ONLY during the transmission of data and then drop again to zero, so I can receive the slave's reply?

Qt is not unfortunately the answer; this behaviour needs to be implemented in the serial port kernel driver or at least at a lower-level that Qt. The Qt QSerialPort abstraction does not give you the level of control or insight into the actual occurrence "on the wire" that you need. It is somewhat arms-length from the hardware - for good reason.

However there is a simple solution - don't bother! it seems entirely unnecessary. It is a master-slave communication, and as such the data itself is flow control. The slave does not talk until spoken to, and the master must expect and wait for a reply after it has spoken. Why does the slave need any permission to speak other than that implied by being spoken to?



Related Topics



Leave a reply



Submit