building a qt 6.2 application — beginning usb comms

My Qt 6 application isn’t simple any more. It’s grown more complicated as I continue to add features and evolve it towards what I finally want. In this post I’m adding very basic serial communications via USB to my attached development boards. For this post I’m only communicating with the Raspberry Pi Pico W. I’ll be using QSerialPort to develop that functionality. I’ll show what additional source and libraries I had to install, the core modified code, and the application I had running on the Pico W to produce test output.

First things first. I had to install the headers and library files to support developing with Qt’s QSerialPort. Those extra packages are libqt6serialport6 and libqt6serialport6-dev. This will put the necessary header files down /usr/include/x86_64-linux-gnu/qt6/QtSerialPort/. You’ll also need to link against Qt6SerialPort.

Here’s the modified code module. I’ll highlight the pertinent sections after the code block.

#include <QStringList>
#include <QHeaderView>
#include <QTableWidgetItem>
#include <QSplitter>
#include <QPalette>
#include <QSerialPort>
#include <QByteArray>
#include <QScrollBar>
#include <QFont>

#include "MainWindow.hpp"
#include "devices.hpp"

void MainWindow::addCentralWidget() {
    console = new QPlainTextEdit(this);
    QPalette colors = palette();
    colors.setColor(QPalette::Base, Qt::black);
    colors.setColor(QPalette::Text, Qt::white);
    QFont font("Monospace", 12);

    serialPort = new QSerialPort(this);

        serialPort, &QSerialPort::readyRead, this, &MainWindow::readSerialData);


    table = new QTableWidget(this);
    QStringList headers = {"Device", "Adapter Name", "Hex Identification"};
    int row{0};

    for (auto [device, values] : getDevices()) {
        QString dev(device.c_str());
        QString v1(values[0].c_str());
        QString v2(values[1].c_str());
        table->setItem(row, 0, new QTableWidgetItem(dev));
        table->setItem(row, 1, new QTableWidgetItem(v1));
        table->setItem(row, 2, new QTableWidgetItem(v2));


    QSplitter *splitter = new QSplitter(Qt::Vertical, this);

void MainWindow::readSerialData() {
    QByteArray data = serialPort->readAll();
    QScrollBar *scrollBar = console->verticalScrollBar();

The text box is being used again as a console. Starting at line 15, we set up the foreground and background colors and the font we want to see any text in. This gives us a console with white text on a black background, with a 12pt Monospaced font using anti-aliasing. The default font is horrible.

Lines 24 through 27 are critical to this working. While Qt calls the ability to handle callbacks as signals (the call) and slots (the callback), this is their nomenclature for a feature as old as C, which is the ability to call pointers to functions. This was a feature in the Unix widget toolkit, Motif, in which controls had the ability to be programatically configured with pointers to functions that were called when a given control was activated. Line 26 sets up the callback (MainWindow::readSerialData) to be called by the serialPort when any data is present. The callback reads that data and places it to be displayed on the console. This is all done asynchronously such that the GUI event queue isn’t blocked. This is very similar to what Java tries to do with its GUI toolkits. The callback is in lines 61-66. When the application is running, it will open the port to the Pico W and then begin to read the data that the Pico W sends out.

These are early days for this. I only wrote enough to get the callback going and to read from the port. You’ll note that the port is hard coded for the Pico W. In the future I’ll be able to pick any port just by clicking on the entry in the upper table and the console will be fully bi-directional. I’m also going to add the ability to log everything in the console. As a stretch goal I’d like to be able to edit Micropython source in the attached microcontroller as well. But that’s a stretch goal which is going to require almost as much work as all the work leading up to finishing the first three goals.

Now for the interesting part. The Pico W is running Circuit Python 8 beta 6.

# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT

import os
import time
import ssl
import wifi
import socketpool
import microcontroller
import adafruit_requests
import json
import gc

# Adafruit quotes URL
quotes_url = ""

# Connect to your local hostspot.
# WIFI_SSID and WIFI_PASSWORD should be defined in your settings.toml
# file.
#'WIFI_SSID'), os.getenv('WIFI_PASSWORD'))

pool = socketpool.SocketPool(
session = adafruit_requests.Session(pool, ssl.create_default_context())
print("Fetching quotes from ", quotes_url)

while True:

        # Get a quote.
        response = session.get(quotes_url)
        dic = dict(json.loads(response.text)[0])
        qstr = dic['text'] + "."

        print("   " + qstr)
        print(".. " + dic['author'])
    # pylint: disable=broad-except
    except ValueError as e:
        print("Error: bad JSON")
    except Exception as e:
        print("Error:\n", str(e))
        print("Resetting microcontroller in 10 seconds")

The original code came from Adafruit. I cleaned up the while loop to make the output more readable. The original code just spat out the JSON strings that came back from the URL. I’ve done some formatting and cleanup instead.

That’s it for the time being. I’ll continue to clean up the C++ code. Hopefully I’ll have more progress to post by the weekend.

One thought on “building a qt 6.2 application — beginning usb comms

Comments are closed.