0
votes

I'm writing a qt bridge to access serial thermal printers by web apps. I'm having an issue settings serial port settings, here is my code:

bool Bridge::printToSerial(QByteArray arr, QString serialPortName, quint16 baud) {

/*
QProcess    proc;
QStringList args = QStringList() << QString("mode COM1 BAUD=%1 PARITY=%2 DATA=%3" ).arg(9600).arg( "n" ).arg(8);
proc.start( "cmd.exe", args );
proc.waitForStarted();
proc.close();
*/

QSerialPort* m_port = new QSerialPort(this);
m_port->setPortName(serialPortName); // \\.\COM1
if(!m_port->open(QSerialPort::ReadWrite)) {
   qDebug() << "Error serial open";
} else {
    if (arr.isEmpty()) {
        qDebug() << QObject::tr("Either no data was currently available on the standard input for reading, or an error occurred for port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
        delete m_port;
        return 1;
    }

    m_port->setBaudRate(baud);
    m_port->setDataBits(QSerialPort::Data8);
    m_port->setParity(QSerialPort::NoParity);
    m_port->setStopBits(QSerialPort::OneStop);

    //m_port->setBreakEnabled(true);

    qint64 bytesWritten = m_port->write(arr);
    if (bytesWritten == -1) {
        qDebug() << QObject::tr("Failed to write the data to port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
        delete m_port;
        return 1;
    } else if (bytesWritten != arr.size()) {
        qDebug() << QObject::tr("Failed to write all the data to port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
        delete m_port;
        return 1;
    } else if (!m_port->waitForBytesWritten(500)) {
        qDebug() << QObject::tr("Operation timed out or an error occurred for port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
        delete m_port;
        return 1;
    }
    m_port->close();
    delete m_port;
    qDebug() << QObject::tr("Data successfully sent to port %1").arg(serialPortName) << endl;
    return false;
}
delete m_port;
return true;
}

the problem is that the data prints but doesn't finish, which made me thing that data bits is not set to 8 bits.

I executed the command: mode COM1 and it shows that the port isn't configured properly ( baud rate, bits, parity all wrong ). btw the device manager is showing the default settings of the port and a different result than the cmd line: "mode COM1"

To make it work, I either have to execute the cmd line: mode COM1 BAUD=9600 PARITY=n DATA=8 before I run the program. or call m_port->setBreakEnabled(true); after I open the port. This call hangs the program, and I have to recompile the exe without to work. When the system restarts, command line mode show the old results ( baud rate 1200, data bits 7 etc )

Any clue why I'm having this behavior ? It seems QSerialPort is unable to effectively change all the settings I require.

2

2 Answers

1
votes

Why are you opening and closing the port each time you send some data out? Furthermore, just because write or waitForBytesWritten has returned something that indicates that the data was "written", it only means that the data has been flushed from the top level device driver's buffers. The USB requests to actually push all that data to the hardware might be still pending, the device's FIFOs might still have the data, etc.

Yet when you close the device, you typically abort any transactions still in progress, and cause the hardware to clear its buffers. Writing is asynchronous and streaming to keep the performance up, device closing is a synchronous, instant-result type of an action.

Keep your device open. You only need to reopen it when you get informed, in a platform-specific manner, of a device going away, or a new device being added.

0
votes

@Kuba Ober was right. I ended up modifying the function to look like this, tracking ports opened: (I dunno if I should have a QSerialPort pointer for each port or like below use it to redefine the ports settings everytime I write data, the above works though.)

bool Bridge::printToSerial(QByteArray arr, QString serialPortName, quint16 baud) {

if (arr.isEmpty()) {
    qDebug() << QObject::tr("Either no data was currently available on the standard input for reading, or an error occurred for port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
    return false;
}

bool portOpen = m_opened.contains(serialPortName);

if(!portOpen) {
    if(m_port == NULL) {
        m_port = new QSerialPort(this);
    }
    m_port->setPortName(serialPortName);
    if(!m_port->open(QSerialPort::WriteOnly)) {
        qDebug() << "Error serial open";
        return false;
    }
    portOpen = true;
    m_opened[serialPortName] = true;
} else {
    m_port->setPortName(serialPortName); // \\.\COM1
}

m_port->setBaudRate(baud);
m_port->setDataBits(QSerialPort::Data8);
m_port->setParity(QSerialPort::NoParity);
m_port->setStopBits(QSerialPort::OneStop);

qint64 bytesWritten = m_port->write(arr);
if (bytesWritten == -1) {
    qDebug() << QObject::tr("Failed to write the data to port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
    delete m_port;
    return 1;
} else if (bytesWritten != arr.size()) {
    qDebug() << QObject::tr("Failed to write all the data to port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
    delete m_port;
    return 1;
} else if (!m_port->waitForBytesWritten(5000)) {
    qDebug() << QObject::tr("Operation timed out or an error occurred for port %1, error: %2").arg(serialPortName).arg(m_port->errorString()) << endl;
    delete m_port;
    return 1;
}
qDebug() << QObject::tr("Data successfully sent to port %1").arg(serialPortName) << endl;
return true;
}