mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 10:05:46 -05:00
Audio CAT SISO: implemented basic CAT connection
This commit is contained in:
parent
b392c34fe5
commit
de79baa0a9
@ -15,6 +15,7 @@
|
|||||||
"DAB_DIR": "/opt/install/libdab",
|
"DAB_DIR": "/opt/install/libdab",
|
||||||
"DSDCC_DIR": "/opt/install/dsdcc",
|
"DSDCC_DIR": "/opt/install/dsdcc",
|
||||||
"HACKRF_DIR": "/opt/install/libhackrf",
|
"HACKRF_DIR": "/opt/install/libhackrf",
|
||||||
|
"HAMLIB_DIR": "/opt/build/hamlib-prefix",
|
||||||
"IIO_DIR": "/opt/install/libiio",
|
"IIO_DIR": "/opt/install/libiio",
|
||||||
"LIBSIGMF_DIR": "/opt/install/libsigmf",
|
"LIBSIGMF_DIR": "/opt/install/libsigmf",
|
||||||
"LIMESUITE_DIR": "/opt/install/LimeSuite",
|
"LIMESUITE_DIR": "/opt/install/LimeSuite",
|
||||||
|
@ -8,6 +8,7 @@ set(audiocatsiso_SOURCES
|
|||||||
audiocatsisosettings.cpp
|
audiocatsisosettings.cpp
|
||||||
audiocatsisowebapiadapter.cpp
|
audiocatsisowebapiadapter.cpp
|
||||||
audiocatsisohamlib.cpp
|
audiocatsisohamlib.cpp
|
||||||
|
audiocatsisocatworker.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(audiocatsiso_HEADERS
|
set(audiocatsiso_HEADERS
|
||||||
@ -18,6 +19,7 @@ set(audiocatsiso_HEADERS
|
|||||||
audiocatsisosettings.h
|
audiocatsisosettings.h
|
||||||
audiocatsisowebapiadapter.h
|
audiocatsisowebapiadapter.h
|
||||||
audiocatsisohamlib.h
|
audiocatsisohamlib.h
|
||||||
|
audiocatsisocatworker.h
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "audiocatsiso.h"
|
#include "audiocatsiso.h"
|
||||||
#include "audiocatinputworker.h"
|
#include "audiocatinputworker.h"
|
||||||
#include "audiocatoutputworker.h"
|
#include "audiocatoutputworker.h"
|
||||||
|
#include "audiocatsisocatworker.h"
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(AudioCATSISO::MsgConfigureAudioCATSISO, Message)
|
MESSAGE_CLASS_DEFINITION(AudioCATSISO::MsgConfigureAudioCATSISO, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(AudioCATSISO::MsgStartStop, Message)
|
MESSAGE_CLASS_DEFINITION(AudioCATSISO::MsgStartStop, Message)
|
||||||
@ -50,13 +51,16 @@ AudioCATSISO::AudioCATSISO(DeviceAPI *deviceAPI) :
|
|||||||
m_settings(),
|
m_settings(),
|
||||||
m_inputWorker(nullptr),
|
m_inputWorker(nullptr),
|
||||||
m_outputWorker(nullptr),
|
m_outputWorker(nullptr),
|
||||||
|
m_catWorker(nullptr),
|
||||||
m_inputWorkerThread(nullptr),
|
m_inputWorkerThread(nullptr),
|
||||||
m_outputWorkerThread(nullptr),
|
m_outputWorkerThread(nullptr),
|
||||||
|
m_catWorkerThread(nullptr),
|
||||||
m_deviceDescription("AudioCATSISO"),
|
m_deviceDescription("AudioCATSISO"),
|
||||||
m_rxRunning(false),
|
m_rxRunning(false),
|
||||||
m_rxAudioDeviceIndex(-1),
|
m_rxAudioDeviceIndex(-1),
|
||||||
m_txRunning(false),
|
m_txRunning(false),
|
||||||
m_txAudioDeviceIndex(-1),
|
m_txAudioDeviceIndex(-1),
|
||||||
|
m_catRunning(false),
|
||||||
m_masterTimer(deviceAPI->getMasterTimer())
|
m_masterTimer(deviceAPI->getMasterTimer())
|
||||||
{
|
{
|
||||||
m_mimoType = MIMOAsynchronous;
|
m_mimoType = MIMOAsynchronous;
|
||||||
@ -145,6 +149,27 @@ bool AudioCATSISO::startRx()
|
|||||||
qDebug("AudioCATSISO::startRx: started");
|
qDebug("AudioCATSISO::startRx: started");
|
||||||
m_rxRunning = true;
|
m_rxRunning = true;
|
||||||
|
|
||||||
|
qDebug() << "AudioCATSISO::startRx: start CAT";
|
||||||
|
|
||||||
|
m_catWorkerThread = new QThread();
|
||||||
|
m_catWorker = new AudioCATSISOCATWorker();
|
||||||
|
m_inputWorker->moveToThread(m_catWorkerThread);
|
||||||
|
|
||||||
|
QObject::connect(m_catWorkerThread, &QThread::started, m_catWorker, &AudioCATSISOCATWorker::startWork);
|
||||||
|
QObject::connect(m_catWorkerThread, &QThread::finished, m_catWorker, &QObject::deleteLater);
|
||||||
|
QObject::connect(m_catWorkerThread, &QThread::finished, m_catWorkerThread, &QThread::deleteLater);
|
||||||
|
|
||||||
|
m_catWorker->setMessageQueueToGUI(getMessageQueueToGUI());
|
||||||
|
m_catWorkerThread->start();
|
||||||
|
|
||||||
|
AudioCATSISOCATWorker::MsgConfigureAudioCATSISOCATWorker *msgToCAT = AudioCATSISOCATWorker::MsgConfigureAudioCATSISOCATWorker::create(
|
||||||
|
m_settings, QList<QString>(), true
|
||||||
|
);
|
||||||
|
m_catWorker->getInputMessageQueue()->push(msgToCAT);
|
||||||
|
|
||||||
|
qDebug() << "AudioCATSISO::startRx: CAT started";
|
||||||
|
m_catRunning = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +230,18 @@ void AudioCATSISO::stopRx()
|
|||||||
audioDeviceManager->removeAudioSource(&m_inputFifo);
|
audioDeviceManager->removeAudioSource(&m_inputFifo);
|
||||||
|
|
||||||
qDebug("AudioCATSISO::stopRx: stopped");
|
qDebug("AudioCATSISO::stopRx: stopped");
|
||||||
|
qDebug("AudioCATSISO::stopRx: stop CAT");
|
||||||
|
m_catRunning = false;
|
||||||
|
|
||||||
|
if (m_catWorkerThread)
|
||||||
|
{
|
||||||
|
m_catWorkerThread->quit();
|
||||||
|
m_catWorkerThread->wait();
|
||||||
|
m_catWorkerThread = nullptr;
|
||||||
|
m_catWorker = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("AudioCATSISO::stopRx: CAT stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioCATSISO::stopTx()
|
void AudioCATSISO::stopTx()
|
||||||
@ -352,6 +389,34 @@ bool AudioCATSISO::handleMessage(const Message& message)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (AudioCATSISOSettings::MsgPTT::match(message))
|
||||||
|
{
|
||||||
|
AudioCATSISOSettings::MsgPTT& cmd = (AudioCATSISOSettings::MsgPTT&) message;
|
||||||
|
qDebug("AudioCATSISO::handleMessage: MsgPTT: %s", cmd.getPTT() ? "on" : "off");
|
||||||
|
if (m_catRunning)
|
||||||
|
{
|
||||||
|
m_catWorker->getInputMessageQueue()->push(&cmd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (AudioCATSISOSettings::MsgCATConnect::match(message))
|
||||||
|
{
|
||||||
|
AudioCATSISOSettings::MsgCATConnect& cmd = (AudioCATSISOSettings::MsgCATConnect&) message;
|
||||||
|
qDebug("AudioCATSISO::handleMessage: MsgCATConnect: %s", cmd.getConnect() ? "on" : "off");
|
||||||
|
if (m_catRunning)
|
||||||
|
{
|
||||||
|
m_catWorker->getInputMessageQueue()->push(&cmd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -37,6 +37,7 @@ class QNetworkReply;
|
|||||||
class QThread;
|
class QThread;
|
||||||
class AudioCATInputWorker;
|
class AudioCATInputWorker;
|
||||||
class AudioCATOutputWorker;
|
class AudioCATOutputWorker;
|
||||||
|
class AudioCATSISOCATWorker;
|
||||||
|
|
||||||
class AudioCATSISO : public DeviceSampleMIMO {
|
class AudioCATSISO : public DeviceSampleMIMO {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -168,8 +169,10 @@ private:
|
|||||||
AudioCATSISOSettings m_settings;
|
AudioCATSISOSettings m_settings;
|
||||||
AudioCATInputWorker* m_inputWorker;
|
AudioCATInputWorker* m_inputWorker;
|
||||||
AudioCATOutputWorker* m_outputWorker;
|
AudioCATOutputWorker* m_outputWorker;
|
||||||
|
AudioCATSISOCATWorker* m_catWorker;
|
||||||
QThread *m_inputWorkerThread;
|
QThread *m_inputWorkerThread;
|
||||||
QThread *m_outputWorkerThread;
|
QThread *m_outputWorkerThread;
|
||||||
|
QThread *m_catWorkerThread;
|
||||||
QString m_deviceDescription;
|
QString m_deviceDescription;
|
||||||
bool m_rxRunning;
|
bool m_rxRunning;
|
||||||
int m_rxAudioDeviceIndex;
|
int m_rxAudioDeviceIndex;
|
||||||
@ -177,6 +180,7 @@ private:
|
|||||||
bool m_txRunning;
|
bool m_txRunning;
|
||||||
int m_txAudioDeviceIndex;
|
int m_txAudioDeviceIndex;
|
||||||
int m_txSampleRate;
|
int m_txSampleRate;
|
||||||
|
bool m_catRunning;
|
||||||
const QTimer& m_masterTimer;
|
const QTimer& m_masterTimer;
|
||||||
QNetworkAccessManager *m_networkManager;
|
QNetworkAccessManager *m_networkManager;
|
||||||
QNetworkRequest m_networkRequest;
|
QNetworkRequest m_networkRequest;
|
||||||
|
170
plugins/samplemimo/audiocatsiso/audiocatsisocatworker.cpp
Normal file
170
plugins/samplemimo/audiocatsiso/audiocatsisocatworker.cpp
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Edouard Griffiths, F4EXB //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "audiocatsisocatworker.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(AudioCATSISOCATWorker::MsgConfigureAudioCATSISOCATWorker, Message)
|
||||||
|
|
||||||
|
AudioCATSISOCATWorker::AudioCATSISOCATWorker(QObject* parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_inputMessageQueueToGUI(nullptr),
|
||||||
|
m_running(false),
|
||||||
|
m_connected(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioCATSISOCATWorker::~AudioCATSISOCATWorker()
|
||||||
|
{
|
||||||
|
stopWork();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOCATWorker::startWork()
|
||||||
|
{
|
||||||
|
if (m_running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
|
||||||
|
m_running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOCATWorker::stopWork()
|
||||||
|
{
|
||||||
|
if (!m_running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOCATWorker::applySettings(const AudioCATSISOSettings& settings, const QList<QString>& settingsKeys, bool force)
|
||||||
|
{
|
||||||
|
qDebug() << "AudioCATSISOCATWorker::applySettings: "
|
||||||
|
<< " force:" << force
|
||||||
|
<< settings.getDebugString(settingsKeys, force);
|
||||||
|
|
||||||
|
if (force) {
|
||||||
|
m_settings = settings;
|
||||||
|
} else {
|
||||||
|
m_settings.applySettings(settingsKeys, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioCATSISOCATWorker::handleMessage(const Message& message)
|
||||||
|
{
|
||||||
|
if (MsgConfigureAudioCATSISOCATWorker::match(message))
|
||||||
|
{
|
||||||
|
qDebug() << "AudioCATSISO::handleMessage: MsgConfigureAudioCATSISOCATWorker";
|
||||||
|
MsgConfigureAudioCATSISOCATWorker& conf = (MsgConfigureAudioCATSISOCATWorker&) message;
|
||||||
|
applySettings(conf.getSettings(), conf.getSettingsKeys(), conf.getForce());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (AudioCATSISOSettings::MsgCATConnect::match(message))
|
||||||
|
{
|
||||||
|
AudioCATSISOSettings::MsgCATConnect& cmd = (AudioCATSISOSettings::MsgCATConnect&) message;
|
||||||
|
|
||||||
|
if (cmd.getConnect()) {
|
||||||
|
catConnect();
|
||||||
|
} else {
|
||||||
|
catDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOCATWorker::handleInputMessages()
|
||||||
|
{
|
||||||
|
Message* message;
|
||||||
|
|
||||||
|
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||||
|
{
|
||||||
|
if (handleMessage(*message)) {
|
||||||
|
delete message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOCATWorker::catConnect()
|
||||||
|
{
|
||||||
|
m_rig = rig_init(m_settings.m_hamlibModel);
|
||||||
|
|
||||||
|
if (!m_rig)
|
||||||
|
{
|
||||||
|
m_connected = false;
|
||||||
|
|
||||||
|
if (m_inputMessageQueueToGUI)
|
||||||
|
{
|
||||||
|
qCritical("AudioCATSISOCATWorker::catConnect: Unknown rig num: %u", m_settings.m_hamlibModel);
|
||||||
|
qCritical("AudioCATSISOCATWorker::catConnect: Please check riglist.h");
|
||||||
|
AudioCATSISOSettings::MsgCATReportStatus *msg = AudioCATSISOSettings::MsgCATReportStatus::create(
|
||||||
|
AudioCATSISOSettings::MsgCATReportStatus::StatusError
|
||||||
|
);
|
||||||
|
m_inputMessageQueueToGUI->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("AudioCATSISOCATWorker::catConnect: rig initialized with num: %u", m_settings.m_hamlibModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rig->state.rigport.type.rig = RIG_PORT_SERIAL;
|
||||||
|
m_rig->state.rigport.parm.serial.rate = AudioCATSISOSettings::m_catSpeeds[m_settings.m_catSpeedIndex];
|
||||||
|
m_rig->state.rigport.parm.serial.data_bits = AudioCATSISOSettings::m_catDataBits[m_settings.m_catDataBitsIndex];
|
||||||
|
m_rig->state.rigport.parm.serial.stop_bits = AudioCATSISOSettings::m_catStopBits[m_settings.m_catStopBitsIndex];
|
||||||
|
m_rig->state.rigport.parm.serial.parity = RIG_PARITY_NONE;
|
||||||
|
m_rig->state.rigport.parm.serial.handshake = (serial_handshake_e) AudioCATSISOSettings::m_catHandshakes[m_settings.m_catHandshakeIndex];
|
||||||
|
strncpy(m_rig->state.rigport.pathname, m_settings.m_catDevicePath.toStdString().c_str() , HAMLIB_FILPATHLEN - 1);
|
||||||
|
int retcode = rig_open(m_rig);
|
||||||
|
AudioCATSISOSettings::MsgCATReportStatus *msg;
|
||||||
|
|
||||||
|
if (retcode == RIG_OK)
|
||||||
|
{
|
||||||
|
m_connected = true;
|
||||||
|
msg = AudioCATSISOSettings::MsgCATReportStatus::create(AudioCATSISOSettings::MsgCATReportStatus::StatusConnected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_connected = false;
|
||||||
|
msg = AudioCATSISOSettings::MsgCATReportStatus::create(AudioCATSISOSettings::MsgCATReportStatus::StatusError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_inputMessageQueueToGUI) {
|
||||||
|
m_inputMessageQueueToGUI->push(msg);
|
||||||
|
} else {
|
||||||
|
delete msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOCATWorker::catDisconnect()
|
||||||
|
{
|
||||||
|
rig_close(m_rig); /* close port */
|
||||||
|
rig_cleanup(m_rig); /* if you care about memory */
|
||||||
|
|
||||||
|
if (m_inputMessageQueueToGUI)
|
||||||
|
{
|
||||||
|
AudioCATSISOSettings::MsgCATReportStatus *msg = AudioCATSISOSettings::MsgCATReportStatus::create(
|
||||||
|
AudioCATSISOSettings::MsgCATReportStatus::StatusNone
|
||||||
|
);
|
||||||
|
m_inputMessageQueueToGUI->push(msg);
|
||||||
|
}
|
||||||
|
}
|
83
plugins/samplemimo/audiocatsiso/audiocatsisocatworker.h
Normal file
83
plugins/samplemimo/audiocatsiso/audiocatsisocatworker.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Edouard Griffiths, F4EXB //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_AUDIOCATSISOCATWORKER_H
|
||||||
|
#define INCLUDE_AUDIOCATSISOCATWORKER_H
|
||||||
|
|
||||||
|
#include <hamlib/rig.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "util/message.h"
|
||||||
|
#include "util/messagequeue.h"
|
||||||
|
#include "audiocatsisosettings.h"
|
||||||
|
|
||||||
|
class AudioCATSISOCATWorker : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
class MsgConfigureAudioCATSISOCATWorker : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const AudioCATSISOSettings& getSettings() const { return m_settings; }
|
||||||
|
const QList<QString>& getSettingsKeys() const { return m_settingsKeys; }
|
||||||
|
bool getForce() const { return m_force; }
|
||||||
|
|
||||||
|
static MsgConfigureAudioCATSISOCATWorker* create(const AudioCATSISOSettings& settings, const QList<QString>& settingsKeys, bool force) {
|
||||||
|
return new MsgConfigureAudioCATSISOCATWorker(settings, settingsKeys, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioCATSISOSettings m_settings;
|
||||||
|
QList<QString> m_settingsKeys;
|
||||||
|
bool m_force;
|
||||||
|
|
||||||
|
MsgConfigureAudioCATSISOCATWorker(const AudioCATSISOSettings& settings, const QList<QString>& settingsKeys, bool force) :
|
||||||
|
Message(),
|
||||||
|
m_settings(settings),
|
||||||
|
m_settingsKeys(settingsKeys),
|
||||||
|
m_force(force)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioCATSISOCATWorker(QObject* parent = nullptr);
|
||||||
|
~AudioCATSISOCATWorker();
|
||||||
|
|
||||||
|
void startWork();
|
||||||
|
void stopWork();
|
||||||
|
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
|
void setMessageQueueToGUI(MessageQueue *queue) { m_inputMessageQueueToGUI = queue; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void applySettings(const AudioCATSISOSettings& settings, const QList<QString>& settingsKeys, bool force);
|
||||||
|
bool handleMessage(const Message& message);
|
||||||
|
void catConnect();
|
||||||
|
void catDisconnect();
|
||||||
|
|
||||||
|
MessageQueue m_inputMessageQueue;
|
||||||
|
MessageQueue *m_inputMessageQueueToGUI;
|
||||||
|
bool m_running;
|
||||||
|
bool m_connected;
|
||||||
|
AudioCATSISOSettings m_settings;
|
||||||
|
RIG *m_rig;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleInputMessages();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // INCLUDE_AUDIOCATSISOCATWORKER_H
|
@ -52,7 +52,8 @@ AudioCATSISOGUI::AudioCATSISOGUI(DeviceUISet *deviceUISet, QWidget* parent) :
|
|||||||
m_forceSettings(true),
|
m_forceSettings(true),
|
||||||
m_sampleMIMO(nullptr),
|
m_sampleMIMO(nullptr),
|
||||||
m_tickCount(0),
|
m_tickCount(0),
|
||||||
m_lastEngineState(DeviceAPI::StNotStarted)
|
m_lastEngineState(DeviceAPI::StNotStarted),
|
||||||
|
m_lastCATStatus(AudioCATSISOSettings::MsgCATReportStatus::StatusNone)
|
||||||
{
|
{
|
||||||
qDebug("AudioCATSISOGUI::AudioCATSISOGUI");
|
qDebug("AudioCATSISOGUI::AudioCATSISOGUI");
|
||||||
m_deviceUISet = deviceUISet;
|
m_deviceUISet = deviceUISet;
|
||||||
@ -72,6 +73,7 @@ AudioCATSISOGUI::AudioCATSISOGUI(DeviceUISet *deviceUISet, QWidget* parent) :
|
|||||||
m_helpURL = "plugins/samplemimo/metismiso/readme.md";
|
m_helpURL = "plugins/samplemimo/metismiso/readme.md";
|
||||||
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
ui->centerFrequency->setValueRange(9, 0, m_absMaxFreq);
|
ui->centerFrequency->setValueRange(9, 0, m_absMaxFreq);
|
||||||
|
ui->catStatusIndicator->setStyleSheet("QLabel { background-color:gray; border-radius: 7px; }");
|
||||||
|
|
||||||
for (const auto& comPortName : m_sampleMIMO->getComPorts()) {
|
for (const auto& comPortName : m_sampleMIMO->getComPorts()) {
|
||||||
ui->catDevice->addItem(comPortName);
|
ui->catDevice->addItem(comPortName);
|
||||||
@ -158,6 +160,18 @@ void AudioCATSISOGUI::on_startStop_toggled(bool checked)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOGUI::on_ptt_toggled(bool checked)
|
||||||
|
{
|
||||||
|
AudioCATSISOSettings::MsgPTT *msg = AudioCATSISOSettings::MsgPTT::create(checked);
|
||||||
|
m_sampleMIMO->getInputMessageQueue()->push(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOGUI::on_catConnect_toggled(bool checked)
|
||||||
|
{
|
||||||
|
AudioCATSISOSettings::MsgCATConnect *msg = AudioCATSISOSettings::MsgCATConnect::create(checked);
|
||||||
|
m_sampleMIMO->getInputMessageQueue()->push(msg);
|
||||||
|
}
|
||||||
|
|
||||||
void AudioCATSISOGUI::on_streamIndex_currentIndexChanged(int index)
|
void AudioCATSISOGUI::on_streamIndex_currentIndexChanged(int index)
|
||||||
{
|
{
|
||||||
if (ui->streamLock->isChecked())
|
if (ui->streamLock->isChecked())
|
||||||
@ -437,6 +451,8 @@ void AudioCATSISOGUI::displayCatDevice()
|
|||||||
|
|
||||||
if (catDevices.contains(m_settings.m_catDevicePath)) {
|
if (catDevices.contains(m_settings.m_catDevicePath)) {
|
||||||
ui->catDevice->setCurrentIndex(catDevices[m_settings.m_catDevicePath]);
|
ui->catDevice->setCurrentIndex(catDevices[m_settings.m_catDevicePath]);
|
||||||
|
} else if (ui->catDevice->count() > 0) {
|
||||||
|
m_settings.m_catDevicePath = ui->catDevice->itemText(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,7 +524,38 @@ void AudioCATSISOGUI::updateStatus()
|
|||||||
|
|
||||||
bool AudioCATSISOGUI::handleMessage(const Message& message)
|
bool AudioCATSISOGUI::handleMessage(const Message& message)
|
||||||
{
|
{
|
||||||
if (AudioCATSISO::MsgConfigureAudioCATSISO::match(message))
|
if (DSPMIMOSignalNotification::match(message))
|
||||||
|
{
|
||||||
|
DSPMIMOSignalNotification& notif = (DSPMIMOSignalNotification&) message;
|
||||||
|
int istream = notif.getIndex();
|
||||||
|
bool sourceOrSink = notif.getSourceOrSink();
|
||||||
|
qint64 frequency = notif.getCenterFrequency();
|
||||||
|
|
||||||
|
if (sourceOrSink)
|
||||||
|
{
|
||||||
|
m_rxSampleRate = notif.getSampleRate();
|
||||||
|
m_settings.m_rxCenterFrequency = frequency;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_txSampleRate = notif. getSampleRate();
|
||||||
|
m_settings.m_txCenterFrequency = frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "AudioCATSISOGUI::handleInputMessages: DSPMIMOSignalNotification: "
|
||||||
|
<< "sourceOrSink:" << sourceOrSink
|
||||||
|
<< "istream:" << istream
|
||||||
|
<< "m_rxSampleRate:" << m_rxSampleRate
|
||||||
|
<< "m_txSampleRate:" << m_txSampleRate
|
||||||
|
<< "frequency:" << frequency;
|
||||||
|
|
||||||
|
displayFrequency();
|
||||||
|
displaySampleRate();
|
||||||
|
updateSpectrum();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (AudioCATSISO::MsgConfigureAudioCATSISO::match(message))
|
||||||
{
|
{
|
||||||
qDebug("AudioCATSISOGUI::handleMessage: MsgConfigureAudioCATSISO");
|
qDebug("AudioCATSISOGUI::handleMessage: MsgConfigureAudioCATSISO");
|
||||||
const AudioCATSISO::MsgConfigureAudioCATSISO& cfg = (AudioCATSISO::MsgConfigureAudioCATSISO&) message;
|
const AudioCATSISO::MsgConfigureAudioCATSISO& cfg = (AudioCATSISO::MsgConfigureAudioCATSISO&) message;
|
||||||
@ -539,6 +586,12 @@ bool AudioCATSISOGUI::handleMessage(const Message& message)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (AudioCATSISOSettings::MsgCATReportStatus::match(message))
|
||||||
|
{
|
||||||
|
AudioCATSISOSettings::MsgCATReportStatus& notif = (AudioCATSISOSettings::MsgCATReportStatus&) message;
|
||||||
|
updateCATStatus(notif.getStatus());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -551,44 +604,9 @@ void AudioCATSISOGUI::handleInputMessages()
|
|||||||
|
|
||||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||||
{
|
{
|
||||||
if (DSPMIMOSignalNotification::match(*message))
|
if (handleMessage(*message)) {
|
||||||
{
|
|
||||||
DSPMIMOSignalNotification* notif = (DSPMIMOSignalNotification*) message;
|
|
||||||
int istream = notif->getIndex();
|
|
||||||
bool sourceOrSink = notif->getSourceOrSink();
|
|
||||||
qint64 frequency = notif->getCenterFrequency();
|
|
||||||
|
|
||||||
if (sourceOrSink)
|
|
||||||
{
|
|
||||||
m_rxSampleRate = notif->getSampleRate();
|
|
||||||
m_settings.m_rxCenterFrequency = frequency;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_txSampleRate = notif->getSampleRate();
|
|
||||||
m_settings.m_txCenterFrequency = frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "AudioCATSISOGUI::handleInputMessages: DSPMIMOSignalNotification: "
|
|
||||||
<< "sourceOrSink:" << sourceOrSink
|
|
||||||
<< "istream:" << istream
|
|
||||||
<< "m_rxSampleRate:" << m_rxSampleRate
|
|
||||||
<< "m_txSampleRate:" << m_txSampleRate
|
|
||||||
<< "frequency:" << frequency;
|
|
||||||
|
|
||||||
displayFrequency();
|
|
||||||
displaySampleRate();
|
|
||||||
updateSpectrum();
|
|
||||||
|
|
||||||
delete message;
|
delete message;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (handleMessage(*message))
|
|
||||||
{
|
|
||||||
delete message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +633,32 @@ void AudioCATSISOGUI::displaySampleRate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioCATSISOGUI::updateCATStatus(AudioCATSISOSettings::MsgCATReportStatus::Status status)
|
||||||
|
{
|
||||||
|
if (m_lastCATStatus != status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case AudioCATSISOSettings::MsgCATReportStatus::StatusNone:
|
||||||
|
ui->catStatusIndicator->setStyleSheet("QLabel { background-color:gray; border-radius: 7px; }");
|
||||||
|
ui->catStatusIndicator->setToolTip("Idle");
|
||||||
|
break;
|
||||||
|
case AudioCATSISOSettings::MsgCATReportStatus::StatusConnected:
|
||||||
|
ui->catStatusIndicator->setStyleSheet("QLabel { background-color:rgb(35, 138, 35); border-radius: 7px; }");
|
||||||
|
ui->catStatusIndicator->setToolTip("Connected");
|
||||||
|
break;
|
||||||
|
case AudioCATSISOSettings::MsgCATReportStatus::StatusError:
|
||||||
|
ui->catStatusIndicator->setStyleSheet("QLabel { background-color:rgb(232, 85, 85); border-radius: 7px; }");
|
||||||
|
ui->catStatusIndicator->setToolTip("Error");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lastCATStatus = status;
|
||||||
|
}
|
||||||
|
|
||||||
void AudioCATSISOGUI::updateSpectrum()
|
void AudioCATSISOGUI::updateSpectrum()
|
||||||
{
|
{
|
||||||
qint64 centerFrequency;
|
qint64 centerFrequency;
|
||||||
@ -671,6 +715,8 @@ void AudioCATSISOGUI::makeUIConnections()
|
|||||||
QObject::connect(ui->spectrumSource, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AudioCATSISOGUI::on_spectrumSource_currentIndexChanged);
|
QObject::connect(ui->spectrumSource, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AudioCATSISOGUI::on_spectrumSource_currentIndexChanged);
|
||||||
QObject::connect(ui->streamLock, &QToolButton::toggled, this, &AudioCATSISOGUI::on_streamLock_toggled);
|
QObject::connect(ui->streamLock, &QToolButton::toggled, this, &AudioCATSISOGUI::on_streamLock_toggled);
|
||||||
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AudioCATSISOGUI::on_startStop_toggled);
|
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AudioCATSISOGUI::on_startStop_toggled);
|
||||||
|
QObject::connect(ui->ptt, &ButtonSwitch::toggled, this, &AudioCATSISOGUI::on_ptt_toggled);
|
||||||
|
QObject::connect(ui->catConnect, &ButtonSwitch::toggled, this, &AudioCATSISOGUI::on_catConnect_toggled);
|
||||||
QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AudioCATSISOGUI::on_centerFrequency_changed);
|
QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AudioCATSISOGUI::on_centerFrequency_changed);
|
||||||
QObject::connect(ui->log2Decim, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AudioCATSISOGUI::on_log2Decim_currentIndexChanged);
|
QObject::connect(ui->log2Decim, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AudioCATSISOGUI::on_log2Decim_currentIndexChanged);
|
||||||
QObject::connect(ui->dcBlock, &ButtonSwitch::toggled, this, &AudioCATSISOGUI::on_dcBlock_toggled);
|
QObject::connect(ui->dcBlock, &ButtonSwitch::toggled, this, &AudioCATSISOGUI::on_dcBlock_toggled);
|
||||||
|
@ -64,6 +64,7 @@ private:
|
|||||||
int m_lastEngineState;
|
int m_lastEngineState;
|
||||||
MessageQueue m_inputMessageQueue;
|
MessageQueue m_inputMessageQueue;
|
||||||
static const int m_absMaxFreq = 61440; // kHz
|
static const int m_absMaxFreq = 61440; // kHz
|
||||||
|
AudioCATSISOSettings::MsgCATReportStatus::Status m_lastCATStatus;
|
||||||
|
|
||||||
void blockApplySettings(bool block) { m_doApplySettings = !block; }
|
void blockApplySettings(bool block) { m_doApplySettings = !block; }
|
||||||
void displaySettings();
|
void displaySettings();
|
||||||
@ -73,6 +74,7 @@ private:
|
|||||||
void displayCatDevice();
|
void displayCatDevice();
|
||||||
void displayCatType();
|
void displayCatType();
|
||||||
void updateSpectrum();
|
void updateSpectrum();
|
||||||
|
void updateCATStatus(AudioCATSISOSettings::MsgCATReportStatus::Status status);
|
||||||
void sendSettings();
|
void sendSettings();
|
||||||
void setCenterFrequency(qint64 centerFrequency);
|
void setCenterFrequency(qint64 centerFrequency);
|
||||||
bool handleMessage(const Message& message);
|
bool handleMessage(const Message& message);
|
||||||
@ -84,6 +86,8 @@ private slots:
|
|||||||
void on_spectrumSource_currentIndexChanged(int index);
|
void on_spectrumSource_currentIndexChanged(int index);
|
||||||
void on_streamLock_toggled(bool checked);
|
void on_streamLock_toggled(bool checked);
|
||||||
void on_startStop_toggled(bool checked);
|
void on_startStop_toggled(bool checked);
|
||||||
|
void on_ptt_toggled(bool checked);
|
||||||
|
void on_catConnect_toggled(bool checked);
|
||||||
void on_centerFrequency_changed(quint64 value);
|
void on_centerFrequency_changed(quint64 value);
|
||||||
void on_log2Decim_currentIndexChanged(int index);
|
void on_log2Decim_currentIndexChanged(int index);
|
||||||
void on_dcBlock_toggled(bool checked);
|
void on_dcBlock_toggled(bool checked);
|
||||||
|
@ -764,31 +764,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="catLayout">
|
<layout class="QHBoxLayout" name="catLayout">
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="catStatusIndicator">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>14</width>
|
|
||||||
<height>14</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Idle</string>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">QLabel { background-color: gray; border-radius: 7px; }</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="catDeviceLabel">
|
<widget class="QLabel" name="catDeviceLabel">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -849,7 +824,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="catConnect">
|
<widget class="ButtonSwitch" name="catConnect">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>24</width>
|
<width>24</width>
|
||||||
@ -857,14 +832,39 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>CAT (re)connect</string>
|
<string>CAT connect/disconnect</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
<normaloff>:/arrow_left.png</normaloff>:/arrow_left.png</iconset>
|
<normaloff>:/link.png</normaloff>:/link.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="catStatusIndicator">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>14</width>
|
||||||
|
<height>14</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Idle</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QLabel { background-color: gray; border-radius: 7px; }</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
#include "audiocatsisosettings.h"
|
#include "audiocatsisosettings.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(AudioCATSISOSettings::MsgPTT, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(AudioCATSISOSettings::MsgCATConnect, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(AudioCATSISOSettings::MsgCATReportStatus, Message)
|
||||||
|
|
||||||
const int AudioCATSISOSettings::m_catSpeeds[] = {
|
const int AudioCATSISOSettings::m_catSpeeds[] = {
|
||||||
1200,
|
1200,
|
||||||
2400,
|
2400,
|
||||||
|
@ -20,8 +20,73 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include "audio/audiodeviceinfo.h"
|
#include "audio/audiodeviceinfo.h"
|
||||||
|
#include "util/message.h"
|
||||||
|
|
||||||
struct AudioCATSISOSettings {
|
struct AudioCATSISOSettings {
|
||||||
|
|
||||||
|
class MsgPTT : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool getPTT() const { return m_ptt; }
|
||||||
|
|
||||||
|
static MsgPTT* create(bool ptt) {
|
||||||
|
return new MsgPTT(ptt);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_ptt;
|
||||||
|
|
||||||
|
MsgPTT(bool ptt) :
|
||||||
|
Message(),
|
||||||
|
m_ptt(ptt)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgCATConnect : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool getConnect() const { return m_connect; }
|
||||||
|
|
||||||
|
static MsgCATConnect* create(bool connect) {
|
||||||
|
return new MsgCATConnect(connect);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_connect;
|
||||||
|
|
||||||
|
MsgCATConnect(bool connect) :
|
||||||
|
Message(),
|
||||||
|
m_connect(connect)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgCATReportStatus : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Status {
|
||||||
|
StatusNone,
|
||||||
|
StatusConnected,
|
||||||
|
StatusError
|
||||||
|
};
|
||||||
|
|
||||||
|
Status getStatus() const { return m_status; }
|
||||||
|
|
||||||
|
static MsgCATReportStatus* create(Status status) {
|
||||||
|
return new MsgCATReportStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Status m_status;
|
||||||
|
|
||||||
|
MsgCATReportStatus(Status status) :
|
||||||
|
Message(),
|
||||||
|
m_status(status)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FC_POS_INFRA = 0,
|
FC_POS_INFRA = 0,
|
||||||
FC_POS_SUPRA,
|
FC_POS_SUPRA,
|
||||||
|
Loading…
Reference in New Issue
Block a user