Need explanation QSerialPort vs Pyserial
-
I'm trying to reset an Arduino Leonardo into boot loader mode by opening and closing the usb serial with a baudrate of 1200. This does not seem to work with Qt. When I tried this with PySerial, just opening and closing the port it works. I also tested with stty and that also works.
Does anybody have any ideas why QSerialPort does not work ?
void Programmer::resetAvr() { m_port.setBaudRate(QSerialPort::Baud1200); m_port.setDataBits(QSerialPort::Data8); m_port.setParity(QSerialPort::NoParity); m_port.setStopBits(QSerialPort::OneStop); m_port.setFlowControl(QSerialPort::NoFlowControl); m_port.setPortName(m_portName); if(m_port.open(QIODevice::ReadWrite) == true) { m_port.close(); } }
#!/usr/bin/env python import serial, sys serialPort = sys.argv[1] print serialPort ser = serial.Serial( port=serialPort, baudrate=1200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS ) ser.isOpen() ser.close() # close port
stty -F /dev/ttyACM0 1200 cs8 -cstopb -parenb
-
Well after spending many hours digging through usb protocol documentation I have finally got to a point where I can say the problem is with QSerialPort. Since I cannot upload files I will try and explain.
PySerial and linux stty both exhibit the same behavior when viewed in wireshark usb capture:
- Host send command 0x22 with value 0x03 to enable RTS and DTR
- Host send comand 0x20 with 7 bytes data to configure BAUD, DATABITS, PARITY and STOPBITS
1200, 8, n, 1 - Host send command 0x22 with value 0x00 to disable RTS/DTR
Now the device resets and goes into boot mode.
QSerialPort behaves as follows - Open/Close :
- Host send command 0x22 with value 0x03 to enable RTS and DTR
- Host send command 0x20 with 7 bytes data to configure BAUD, DATABITS, PARITY and STOPBITS
(all these configurations are sent)
400000, 8, n, 1
9600, 8, n, 1
1200, 8, n, 1
115200, 8, n, 1 - Host send command 0x22 with value 0x00 to disable RTS and DTR
#include <QCoreApplication> #include <QDebug> #include <QSerialPort> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QSerialPort mPort; mPort.setBaudRate(QSerialPort::Baud1200); mPort.setDataBits(QSerialPort::Data8); mPort.setStopBits(QSerialPort::OneStop); mPort.setParity(QSerialPort::NoParity); mPort.setPortName("/dev/ttyACM0"); qDebug() << "Open Port"; mPort.open(QIODevice::ReadWrite); if(mPort.isOpen()) { qDebug() << "Close Port"; mPort.close(); } exit(0); // return a.exec(); }
Anybody ??
-
Hi @moscowbob,
just opening and closing a serial port without sending data will not change anything for the other side (independent of the baud rate).
So there is most likely a control line (RTS, CTS, RTR) involved that actually does the reset? Do you have a description how the reset is supposed to work?
And if it is working like this, there can be indeed a difference between pyserial and QSerialPort.
-
@aha_1980 , thanks for response.
The connection is a USB CDC connection, the AT32U4 chip has an embedded usb that is configured as a virtual comport. So there are no control lines connected. As I understand, when the host opens the port, it will configure the device endpoint and it is there where the 1200 baud is used to reset the device into bootloader mode.I have captured the usb conversation between the host pc and device for all 3 methods and the QSerialPort conversation looks completely different - unfortunately my knowledge is very limited when it comes to this, so if you want, I can post the three Wireshark capure files for viewing.
-
Hi @moscowbob,
yeah, you can post them, but I have to admit that my knowledge is also limited here :)
But maybe someone else can help you here...
-
@moscowbob
Hi
It only wants
What type are you trying ? -
Well after spending many hours digging through usb protocol documentation I have finally got to a point where I can say the problem is with QSerialPort. Since I cannot upload files I will try and explain.
PySerial and linux stty both exhibit the same behavior when viewed in wireshark usb capture:
- Host send command 0x22 with value 0x03 to enable RTS and DTR
- Host send comand 0x20 with 7 bytes data to configure BAUD, DATABITS, PARITY and STOPBITS
1200, 8, n, 1 - Host send command 0x22 with value 0x00 to disable RTS/DTR
Now the device resets and goes into boot mode.
QSerialPort behaves as follows - Open/Close :
- Host send command 0x22 with value 0x03 to enable RTS and DTR
- Host send command 0x20 with 7 bytes data to configure BAUD, DATABITS, PARITY and STOPBITS
(all these configurations are sent)
400000, 8, n, 1
9600, 8, n, 1
1200, 8, n, 1
115200, 8, n, 1 - Host send command 0x22 with value 0x00 to disable RTS and DTR
#include <QCoreApplication> #include <QDebug> #include <QSerialPort> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QSerialPort mPort; mPort.setBaudRate(QSerialPort::Baud1200); mPort.setDataBits(QSerialPort::Data8); mPort.setStopBits(QSerialPort::OneStop); mPort.setParity(QSerialPort::NoParity); mPort.setPortName("/dev/ttyACM0"); qDebug() << "Open Port"; mPort.open(QIODevice::ReadWrite); if(mPort.isOpen()) { qDebug() << "Close Port"; mPort.close(); } exit(0); // return a.exec(); }
Anybody ??
-
Well, finally a breakthrough !
It turn out that the deprecated function
mPort.setSettingsRestoredOnClose(false);
Does the trick.
Although the Arduino now does reset, since QSerialPort does not send the restored values before closing the port, it still sends a garbage packet before setting the 1200 baud. I have not figured that one out yet, and I am now getting tired.
So I will mark this as solved but will raise another post to query the strange behavior when QSerialPort opens.
-
Please report this at bugreports.qt.io (and provide a link to the bug here).
You will have better possibilities to discuss the behavior with the developers there and you should also be able to attach the Wireshark logs.
Thanks.