| 389 | } // namespace |
| 390 | |
| 391 | RadioModel::RadioModel(QObject* parent) |
| 392 | : QObject(parent) |
| 393 | { |
| 394 | // PanadapterStream runs on its own network thread (#502) |
| 395 | m_networkThread = new QThread(this); |
| 396 | m_networkThread->setObjectName("PanadapterStream"); |
| 397 | m_panStream = new PanadapterStream; // no parent — will be moved to thread |
| 398 | m_panStream->moveToThread(m_networkThread); |
| 399 | connect(m_networkThread, &QThread::started, m_panStream, &PanadapterStream::init); |
| 400 | m_networkThread->start(); |
| 401 | |
| 402 | // RadioConnection runs on its own worker thread (#502) so TCP I/O |
| 403 | // (including ping RTT measurement) is never blocked by paintEvent. |
| 404 | m_connThread = new QThread(this); |
| 405 | m_connThread->setObjectName("RadioConnection"); |
| 406 | m_connection = new RadioConnection; // no parent — will be moved to thread |
| 407 | m_connection->moveToThread(m_connThread); |
| 408 | connect(m_connThread, &QThread::started, m_connection, &RadioConnection::init); |
| 409 | m_connThread->start(); |
| 410 | |
| 411 | // Signals from RadioConnection auto-queue to main thread (#502) |
| 412 | connect(m_connection, &RadioConnection::statusReceived, |
| 413 | this, &RadioModel::onStatusReceived); |
| 414 | connect(m_connection, &RadioConnection::messageReceived, |
| 415 | this, &RadioModel::onMessageReceived); |
| 416 | connect(m_connection, &RadioConnection::connected, |
| 417 | this, &RadioModel::onConnected); |
| 418 | connect(m_connection, &RadioConnection::disconnected, |
| 419 | this, &RadioModel::onDisconnected); |
| 420 | connect(m_connection, &RadioConnection::errorOccurred, |
| 421 | this, &RadioModel::onConnectionError); |
| 422 | connect(m_connection, &RadioConnection::versionReceived, |
| 423 | this, &RadioModel::onVersionReceived); |
| 424 | |
| 425 | // Response callbacks: RadioConnection emits commandResponse on worker thread, |
| 426 | // we dispatch to the matching callback on the main thread. (#502) |
| 427 | connect(m_connection, &RadioConnection::commandResponse, |
| 428 | this, [this](quint32 seq, int code, const QString& body) { |
| 429 | auto it = m_pendingCallbacks.find(seq); |
| 430 | if (it != m_pendingCallbacks.end()) { |
| 431 | it.value()(code, body); |
| 432 | m_pendingCallbacks.erase(it); |
| 433 | } |
| 434 | }); |
| 435 | |
| 436 | // Forward VITA-49 meter packets to MeterModel (cross-thread, auto-queued) |
| 437 | connect(m_panStream, &PanadapterStream::meterDataReady, |
| 438 | &m_meterModel, &MeterModel::updateValues); |
| 439 | |
| 440 | // Forward tuner commands to the radio — route through tune inhibit check |
| 441 | connect(&m_tunerModel, &TunerModel::commandReady, this, [this](const QString& cmd){ |
| 442 | if (cmd.startsWith("tgxl autotune")) { |
| 443 | if (transmitStartBlockedByInhibit(QStringLiteral("tgxl-autotune"))) { |
| 444 | return; |
| 445 | } |
| 446 | applyTuneInhibit(); |
| 447 | } |
| 448 | sendCmd(cmd); |
nothing calls this directly
no test coverage detected