シリアルターミナル

QSerialPort の様々な機能の使い方を紹介します。

Terminalは、Qt Serial Port を使用して、シンプルなシリアルインターフェースのターミナルを作成する方法を示しています。

この例では、QSerialPort クラスの主な機能(設定、I/O 実装など)を示しています。また、QSerialPortInfo クラスを呼び出して、システムで利用可能なシリアルポートに関する情報を表示します。

QSerialPort は、2つの一般的なプログラミング・アプローチをサポートしています:

  • 非同期(ノンブロッキング)アプローチ。操作はスケジュールされ、制御がQtのイベントループに戻ったときに実行されます。QSerialPort 、操作が終了するとシグナルが出力されます。例えば、QSerialPort::write ()はすぐに戻ります。データがシリアル・ポートに送信されると、QSerialPortbytesWritten() を発信します。
  • 同期(ブロッキング)アプローチ。非GUIアプリケーションやマルチスレッド・アプリケーションでは、waitFor...() 関数を呼び出す(つまり、QSerialPort::waitForReadyRead())ことで、操作が完了するまで呼び出し元のスレッドを一時停止させることができます。

この例では、非同期アプローチを示している。Blocking Receiverの例では、同期的なアプローチを示している。

この例にはいくつかのGUIウィジェットが含まれている:

  • MainWindow ( ) - QMainWindow を継承し、設定、I/O 処理など、シリアル・ポート・プログラミングのすべての作業ロジックを含むメイン・アプリケーション・ウィンドウです。terminal/mainwindow.cpp
  • Console ( ) - メイン・ウィンドウの中心ウィジェットで、送受信データを表示します。このウィジェットはQPlainTextEditクラスから派生しています。terminal/console.cpp
  • SettingsDialog ( ) - シリアルポートを設定するためのダイアログで、利用可能なシリアルポートとその情報を表示します。terminal/settingsdialog.cpp

シリアルポートはMainWindow コンストラクタでインスタンス化されます。メインウィジェットが親として渡されるので、Qt の親子メカニズムに従ってオブジェクトの削除が自動的に行われます:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    m_ui(new Ui::MainWindow),
    m_serial(new QSerialPort(this))
{
    ...

この例では、次のQSerialPort シグナルを示します:

  • readyRead() - 新しいデータが受信され、利用可能になったことを示します。
  • bytesWritten() - 新しいデータが受信され、利用可能になったことを示します。
    ...
    connect(m_serial, &QSerialPort::readyRead, this, &MainWindow::readData);
    connect(m_serial, &QSerialPort::bytesWritten, this, &MainWindow::handleBytesWritten);
    ...
}

Connectボタンをクリックすると、openSerialPort() スロットが起動します:

void MainWindow::openSerialPort()
{
    const SettingsDialog::Settings p = m_settings->settings();
    m_serial->setPortName(p.name);
    m_serial->setBaudRate(p.baudRate);
    m_serial->setDataBits(p.dataBits);
    m_serial->setParity(p.parity);
    m_serial->setStopBits(p.stopBits);
    m_serial->setFlowControl(p.flowControl);
    if (m_serial->open(QIODevice::ReadWrite)) {
        m_console->setEnabled(true);
        m_console->setLocalEchoEnabled(p.localEchoEnabled);
        m_ui->actionConnect->setEnabled(false);
        m_ui->actionDisconnect->setEnabled(true);
        m_ui->actionConfigure->setEnabled(false);
        showStatusMessage(tr("Connected to %1 : %2, %3, %4, %5, %6")
                          .arg(p.name, p.stringBaudRate, p.stringDataBits,
                               p.stringParity, p.stringStopBits, p.stringFlowControl));
    } else {
        QMessageBox::critical(this, tr("Error"), m_serial->errorString());

        showStatusMessage(tr("Open error"));
    }
}

このスロットでは、SettingsDialog から設定が読み込まれ、それに応じてシリアルポートのオープンと初期化が試みられます。このスロットでは、 から設定が読み込まれ、それに従ってシリアルポートのオープンと初期化が試みられます。成功した場合は、ステータスバーに、指定した設定でオープンに成功した旨のメッセージが表示されます。そうでない場合は、メッセージボックスに適切なエラーコードとメッセージが表示されます。そうでない場合は、適切なエラー・コードとメッセージがメッセージ・ボックスに表示されます。シリアル・ポートの設定が一度も呼び出されたことがない場合、端末はデフォルトの設定でポートを開こうとします:9600 8N1.

切断ボタンをクリックすると、closeSerialPort() スロットが呼び出されます:

void MainWindow::closeSerialPort()
{
    if (m_serial->isOpen())
        m_serial->close();
    m_console->setEnabled(false);
    m_ui->actionConnect->setEnabled(true);
    m_ui->actionDisconnect->setEnabled(false);
    m_ui->actionConfigure->setEnabled(true);
    showStatusMessage(tr("Disconnected"));
}

この場合、シリアルポートのクローズによって処理されます。

Configureボタンをクリックすると、SettingsDialog ウィジェットに属するshow() スロットが呼び出されます。

このメソッド (terminal/settingsdialog.cpp) はSettingsDialog を表示し、ユーザは希望するシリアル・ポートを選択し、選択したポートに関する情報を確認し、指定したシリアル・ポートの希望するパラメータを設定することができます。

データの書き込み

コンソールに文字を入力すると、writeData() スロットが呼び出される:

void MainWindow::writeData(const QByteArray &data)
{
    const qint64 written = m_serial->write(data);
    if (written == data.size()) {
        m_bytesToWrite += written;
        m_timer->start(kWriteTimeout);
    } else {
        const QString error = tr("Failed to write all data to port %1.\n"
                                 "Error: %2").arg(m_serial->portName(),
                                                  m_serial->errorString());
        showWriteError(error);
    }
}

このスロットは、指定されたコンソールウィジェットに入力された文字をシリアルポートに送信します -terminal/console.cpp を参照してください。また、書き込みが実際に成功したかどうかを追跡するためにタイマーを開始します。bytesWritten() シグナルを使用して、すべてのバイトが実際に書き込まれたことを確認します。これはMainWindow::handleBytesWritten() スロットに接続されています:

void MainWindow::handleBytesWritten(qint64 bytes)
{
    m_bytesToWrite -= bytes;
    if (m_bytesToWrite == 0)
        m_timer->stop();
}
データの読み込み

シリアル・ポートが新しいデータを受信すると、シグナルreadyRead ()が発せられ、このシグナルはMainWindow::readData() スロットに接続される:

void MainWindow::readData()
{
    const QByteArray data = m_serial->readAll();
    m_console->putData(data);
}

このスロットはシリアルポートからデータを読み取り、コンソールウィジェットに表示します。

サンプルを実行する

Qt Creator からサンプルを実行するには、Welcome モードを開き、Examples からサンプルを選択します。詳細については、Building and Running an Example を参照してください。

サンプルプロジェクト @ code.qt.io

Blocking Receiverも参照してください

©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。