diff --git a/cachingqueue.h b/cachingqueue.h index 1533e52..30dfc05 100644 --- a/cachingqueue.h +++ b/cachingqueue.h @@ -61,6 +61,7 @@ signals: void haveCommand(funcs func, QVariant param, bool sub); void sendValue(cacheItem item); void cacheUpdated(cacheItem item); + void rigCapsUpdated(rigCapabilities* caps); public slots: // Can be called directly or via emit. @@ -87,7 +88,9 @@ private: bool aborted=false; QWaitCondition waiting; quint64 queueInterval=0; // Don't start the timer! - + + rigCapabilities* rigCaps = Q_NULLPTR; // Must be NULL until a radio is connected + // Functions void run(); @@ -117,6 +120,8 @@ public: QMultiMap getQueueItems(); void lockMutex() {mutex.lock();} void unlockMutex() {mutex.unlock();} + void setRigCaps(rigCapabilities* caps) { rigCaps = caps; emit rigCapsUpdated(rigCaps);} + rigCapabilities* getRigCaps() { return rigCaps; } }; Q_DECLARE_METATYPE(queueItemType) diff --git a/logcategories.cpp b/logcategories.cpp index 8ba2677..7d8fd39 100644 --- a/logcategories.cpp +++ b/logcategories.cpp @@ -16,3 +16,4 @@ Q_LOGGING_CATEGORY(logTcpServer, "tcpserver") Q_LOGGING_CATEGORY(logUsbControl, "usbcontrol") Q_LOGGING_CATEGORY(logAudioConverter, "audioconverter") Q_LOGGING_CATEGORY(logCluster, "cluster") +Q_LOGGING_CATEGORY(logTCIServer, "tci.server") diff --git a/logcategories.h b/logcategories.h index 36da605..56ec94d 100644 --- a/logcategories.h +++ b/logcategories.h @@ -19,6 +19,7 @@ Q_DECLARE_LOGGING_CATEGORY(logTcpServer) Q_DECLARE_LOGGING_CATEGORY(logUsbControl) Q_DECLARE_LOGGING_CATEGORY(logAudioConverter) Q_DECLARE_LOGGING_CATEGORY(logCluster) +Q_DECLARE_LOGGING_CATEGORY(logTCIServer) #if defined(Q_OS_WIN) && !defined(__PRETTY_FUNCTION__) diff --git a/rigcommander.cpp b/rigcommander.cpp index f67a0dd..62b6e7b 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -39,6 +39,7 @@ rigCommander::rigCommander(quint8 guid[GUIDLEN], QObject* parent) : QObject(pare rigCommander::~rigCommander() { qInfo(logRig()) << "closing instance of rigCommander()"; + queue->setRigCaps(Q_NULLPTR); // Remove access to rigCaps closeComm(); } @@ -1514,7 +1515,7 @@ void rigCommander::determineRigCaps() } haveRigCaps = true; - + queue->setRigCaps(&rigCaps); // Copy received guid so we can recognise this radio. memcpy(rigCaps.guid, this->guid, GUIDLEN); @@ -2534,7 +2535,7 @@ void rigCommander::receiveCommand(funcs func, QVariant value, bool sub) else if (!strcmp(value.typeName(),"uchar")) { payload.append(bcdEncodeChar(value.value())); - //qInfo(logRig()) << "**** setting uchar value" << funcString[func] << "val" << value.value(); + qInfo(logRig()) << "**** setting uchar value" << funcString[func] << "val" << value.value(); } else if (!strcmp(value.typeName(),"ushort")) { diff --git a/rigctld.cpp b/rigctld.cpp index b32d581..9f24491 100644 --- a/rigctld.cpp +++ b/rigctld.cpp @@ -789,6 +789,7 @@ int rigCtlClient::getCommand(QStringList& response, bool extended, const command ret = RIG_OK; if (cmd.type == 'i') { val.setValue(static_cast(params[0].toInt())); + qInfo(logRigCtlD()) << "Setting char value" << val << "original" << params[0]; } if (cmd.type == 's') { val.setValue(static_cast(params[0].toInt())); @@ -986,7 +987,7 @@ int rigCtlClient::getSubCommand(QStringList& response, bool extended, const comm // We are expecting a second argument to the command QVariant val; if (sub[i].type == 'i') { - uchar v = static_cast(params[1].toInt(NULL,16)); + uchar v = static_cast(params[1].toInt()); if (params[0] == "FBKIN") v = (v << 1) & 0x02; // BREAKIN is not bool! val.setValue(v); @@ -1036,7 +1037,7 @@ int rigCtlClient::getSubCommand(QStringList& response, bool extended, const comm int val = item.value.toInt(); if (params[0] == "FBKIN") val = (val >> 1) & 0x01; - resp.append(QString::number(val,16)); // Base 16 + resp.append(QString::number(val)); } else if (sub[i].type == 'f') { resp.append(QString::number(item.value.toFloat() / 255.0,'F',6)); @@ -1177,7 +1178,7 @@ int rigCtlClient::dumpState(QStringList &response, bool extended) { if (att == 0) continue; - attens.append(QString("%1 ").arg(att,0,16)); + attens.append(QString("%1 ").arg(att)); } if (attens.endsWith(" ")) attens.chop(1); diff --git a/tciaudiohandler.cpp b/tciaudiohandler.cpp index 66c8b2a..10562f5 100644 --- a/tciaudiohandler.cpp +++ b/tciaudiohandler.cpp @@ -88,6 +88,8 @@ bool tciAudioHandler::init(audioSetup setup) connect((tciServer*)setup.tci, SIGNAL(sendTCIAudio(QByteArray)), this, SLOT(receiveTCIAudio(QByteArray))); //connect(this,SIGNAL(setupTxPacket(int)), (tciServer*)setup.tci, SLOT(setupTxPacket(int))); //emit setupTxPacket((nativeFormat.bytesForDuration(setup.blockSize * 1000)*2)/sizeof(float)); + } else { + qCritical(logAudio()) << "***** TCI NOT FOUND *****"; } } else { diff --git a/tciserver.cpp b/tciserver.cpp index f127931..b986a99 100644 --- a/tciserver.cpp +++ b/tciserver.cpp @@ -4,32 +4,92 @@ +// Based on TCI v1.9 commands static const tciCommandStruct tci_commands[] = { - { "vfo_limits", funcNone, 'l', 'l'}, - { "if_limits", funcNone, 'l', 'l'}, + // u=uchar s=short f=float b=bool x=hz m=mode s=string + { "vfo_limits", funcNone, 'x', 'x'}, + { "if_limits", funcNone, 'x', 'x'}, { "trx_count", funcNone, 'u'}, { "channel_count", funcNone, 'u'}, - { "device", funcNone, 't'}, - { "receive_only", funcNone, 'u'}, + { "device", funcNone, 's'}, + { "receive_only", funcNone, 'b'}, { "modulations_list", funcNone, 's'}, + { "protocol", funcNone, 's'}, + { "ready", funcNone }, + { "start", funcNone }, + { "stop", funcNone }, + { "dds", funcNone, 'u','x'}, + { "if", funcNone, 'u','u','x'}, + { "vfo", funcNone, 'u','u','x'}, + { "modulation", funcNone, 'u','s'}, + { "trx", funcNone, 'u'}, + { "tune", funcNone, 'u'}, + { "drive", funcNone, 'u'}, + { "tune_drive", funcNone, 'u'}, + { "rit_enable", funcNone, 'u'}, + { "xit_enable", funcNone, 'u'}, + { "split_enable", funcNone, 'u'}, + { "rit_offset", funcNone, 'u'}, + { "xit_offset", funcNone, 'u'}, + { "rx_channel_enable", funcNone, 'u'}, + { "rx_filter_band", funcNone, 'u'}, + { "cw_macros_speed", funcNone, 'u'}, + { "cw_macros_delay", funcNone, 'u'}, + { "cw_keyer_speed", funcNone, 'u'}, + { "volume", funcNone, 'u'}, + { "mute", funcNone, 'u'}, + { "rx_mute", funcNone, 'u'}, + { "rx_volume", funcNone, 'u'}, + { "rx_balance", funcNone, 'u'}, + { "mon_volume", funcNone, 'u'}, + { "mon_enable", funcNone, 'u'}, + { "agc_mode", funcNone, 'u'}, + { "agc_gain", funcNone, 'u'}, + { "rx_nb_enable", funcNone, 'u'}, + { "rx_nb_param", funcNone, 'u'}, + { "rx_bin_enable", funcNone, 'u'}, + { "rx_nr_enable", funcNone, 'u'}, + { "rx_anc_enable", funcNone, 'u'}, + { "rx_anf_enable", funcNone, 'u'}, + { "rx_apf_enable", funcNone, 'u'}, + { "rx_dse_enable", funcNone, 'u'}, + { "rx_nf_enable", funcNone, 'u'}, + { "lock", funcNone, 'u'}, + { "sql_enable", funcNone, 'u'}, + { "sql_level", funcNone, 'u'}, { "tx_enable", funcNone, 'u','u'}, - { "ready", funcNone, }, + { "cw_macros_speed_up", funcNone, 'u','u'}, + { "cw_macros_speed_down", funcNone, 'u','u'}, + { "spot", funcNone, 'u','u'}, + { "spot_delete", funcNone, 'u','u'}, + { "iq_samplerate", funcNone, 'u'}, + { "audio_samplerate", funcNone, 'u'}, + { "iq_start", funcNone, 'u'}, + { "iq_stop", funcNone, 'u'}, + { "audio_start", funcNone, 'u'}, + { "audio_stop", funcNone, 'u'}, + { "line_out_start", funcNone, 'u'}, + { "line_out_stop", funcNone, 'u'}, + { "line_out_recorder_start", funcNone, 'u'}, + { "line_out_recorder_save", funcNone, 'u'}, + { "line_out_recorder_start", funcNone, 'u'}, + { "clicked_on_spot", funcNone, 'u'}, + { "rx_clicked_on_spot", funcNone, 'u'}, { "tx_footswitch", funcNone, 'u','b'}, - { "start", funcNone }, - { "stop", funcNone }, - { "dds", funcNone, 'u','u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, - { "trx_count", funcNone, 'u'}, + { "tx_frequency", funcNone, 'u','b'}, + { "app_focus", funcNone, 'u','b'}, + { "set_in_focus", funcNone, 'u','b'}, + { "keyer", funcNone, 'u','b'}, + { "rx_sensors_enable", funcNone, 'u','b'}, + { "tx_sensors_enable", funcNone, 'u','b'}, + { "rx_sensors", funcNone, 'u','b'}, + { "tx_sensors", funcNone, 'u','b'}, + { "audio_stream_sample_type", funcNone, 'u','b'}, + { "audio_stream_channels", funcNone, 'u','b'}, + { "audio_stream_samples", funcNone, 'u','b'}, + { "digl_offset", funcNone, 'u','b'}, + { "digu_offset", funcNone, 'u','b'}, { "", funcNone, 0x0 }, }; @@ -48,6 +108,8 @@ void tciServer::init(quint16 port) { connect (server, &QWebSocketServer::newConnection, this, &tciServer::onNewConnection); connect (server, &QWebSocketServer::closed, this, &tciServer::socketDisconnected); } + + this->setObjectName("TCI Server"); queue = cachingQueue::getInstance(this); connect(queue,SIGNAL(cacheUpdated(cacheItem)),this,SLOT(receiveCache(cacheItem))); @@ -80,15 +142,25 @@ tciServer::~tciServer() it.key()->deleteLater(); it = clients.erase(it); } +} - //qDeleteAll(clients.begin(), clients.end()); +void tciServer::receiveRigCaps(rigCapabilities *caps) +{ + rigCaps = caps; } void tciServer::onNewConnection() { - - this->setObjectName("TCI Server"); + QWebSocket *pSocket = server->nextPendingConnection(); + if (rigCaps == Q_NULLPTR) + { + qWarning(logTCIServer()) << "No current rig connection, denying connection request."; + pSocket->abort(); + return; + } + + qInfo(logTCIServer()) << "Got rigCaps for" << rigCaps->modelName; connect(pSocket, &QWebSocket::textMessageReceived, this, &tciServer::processIncomingTextMessage); connect(pSocket, &QWebSocket::binaryMessageReceived, this, &tciServer::processIncomingBinaryMessage); @@ -98,7 +170,7 @@ void tciServer::onNewConnection() clients.insert(pSocket,connStatus()); pSocket->sendTextMessage(QString("protocol:WFVIEW,1.5;\n")); pSocket->sendTextMessage(QString("device:WFVIEW;\n")); - pSocket->sendTextMessage(QString("receive_only:false;\n")); + pSocket->sendTextMessage(QString("receive_only:%0;\n").arg(rigCaps->hasTransmit?"false":"true")); pSocket->sendTextMessage(QString("trx_count:1;\n")); pSocket->sendTextMessage(QString("channel_count:1;\n")); pSocket->sendTextMessage(QString("vfo_limits:10000,52000000;\n")); diff --git a/tciserver.h b/tciserver.h index 0b74a4f..eef90dc 100644 --- a/tciserver.h +++ b/tciserver.h @@ -80,6 +80,7 @@ signals: public slots: void receiveTCIAudio(audioPacket audio); + void receiveRigCaps(rigCapabilities* caps); void init(quint16 port); @@ -98,6 +99,7 @@ private: QByteArray rxAudioData; QByteArray txAudioData; QByteArray txChrono; + rigCapabilities* rigCaps = Q_NULLPTR; }; #endif // TCISERVER_H diff --git a/wfmain.cpp b/wfmain.cpp index d4c6ae8..1ae2c7a 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -354,6 +354,13 @@ void wfmain::openRig() ui->connectBtn->setText("Cancel connection"); // We are attempting to connect connStatus = connConnecting; + // PET: This could be in a better place? + if (prefs.audioSystem == tciAudio) + { + prefs.rxSetup.tci = tci; + prefs.txSetup.tci = tci; + } + makeRig(); if (prefs.enableLAN) @@ -1750,6 +1757,7 @@ void wfmain::loadSettings() tciThread = new QThread(this); tciThread->setObjectName("TCIServer()"); tci->moveToThread(tciThread); + connect(queue,SIGNAL(rigCapsUpdated(rigCapabilities*)),tci, SLOT(receiveRigCaps(rigCapabilities*))); connect(this,SIGNAL(tciInit(quint16)),tci, SLOT(init(quint16))); connect(tciThread, SIGNAL(finished()), tci, SLOT(deleteLater())); tciThread->start(QThread::TimeCriticalPriority);