mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
Channel Power: Add absolute frequency setting.
This commit is contained in:
parent
b30588b28a
commit
9334a7f16a
@ -1,6 +1,6 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
|
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
|
||||||
// Copyright (C) 2023 Jon Beniston, M7RCE //
|
// Copyright (C) 2023-2024 Jon Beniston, M7RCE //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// 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 //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "channelpowergui.h"
|
|
||||||
|
|
||||||
#include "device/deviceuiset.h"
|
#include "device/deviceuiset.h"
|
||||||
#include "device/deviceapi.h"
|
#include "device/deviceapi.h"
|
||||||
#include "dsp/dspengine.h"
|
#include "dsp/dspengine.h"
|
||||||
@ -36,6 +34,7 @@
|
|||||||
#include "maincore.h"
|
#include "maincore.h"
|
||||||
|
|
||||||
#include "channelpower.h"
|
#include "channelpower.h"
|
||||||
|
#include "channelpowergui.h"
|
||||||
|
|
||||||
ChannelPowerGUI* ChannelPowerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
|
ChannelPowerGUI* ChannelPowerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
|
||||||
{
|
{
|
||||||
@ -62,11 +61,14 @@ QByteArray ChannelPowerGUI::serialize() const
|
|||||||
|
|
||||||
bool ChannelPowerGUI::deserialize(const QByteArray& data)
|
bool ChannelPowerGUI::deserialize(const QByteArray& data)
|
||||||
{
|
{
|
||||||
if(m_settings.deserialize(data)) {
|
if (m_settings.deserialize(data))
|
||||||
|
{
|
||||||
displaySettings();
|
displaySettings();
|
||||||
applyAllSettings();
|
applyAllSettings();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
resetToDefaults();
|
resetToDefaults();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -90,8 +92,7 @@ bool ChannelPowerGUI::handleMessage(const Message& message)
|
|||||||
DSPSignalNotification& notif = (DSPSignalNotification&) message;
|
DSPSignalNotification& notif = (DSPSignalNotification&) message;
|
||||||
m_deviceCenterFrequency = notif.getCenterFrequency();
|
m_deviceCenterFrequency = notif.getCenterFrequency();
|
||||||
m_basebandSampleRate = notif.getSampleRate();
|
m_basebandSampleRate = notif.getSampleRate();
|
||||||
ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2);
|
calcOffset();
|
||||||
ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2));
|
|
||||||
ui->rfBW->setValueRange(floor(log10(m_basebandSampleRate))+1, 0, m_basebandSampleRate);
|
ui->rfBW->setValueRange(floor(log10(m_basebandSampleRate))+1, 0, m_basebandSampleRate);
|
||||||
updateAbsoluteCenterFrequency();
|
updateAbsoluteCenterFrequency();
|
||||||
return true;
|
return true;
|
||||||
@ -115,9 +116,23 @@ void ChannelPowerGUI::handleInputMessages()
|
|||||||
|
|
||||||
void ChannelPowerGUI::channelMarkerChangedByCursor()
|
void ChannelPowerGUI::channelMarkerChangedByCursor()
|
||||||
{
|
{
|
||||||
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
applySetting("inputFrequencyOffset");
|
m_settings.m_frequency = m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset;
|
||||||
|
|
||||||
|
qint64 value = 0;
|
||||||
|
|
||||||
|
if (m_settings.m_frequencyMode == ChannelPowerSettings::Offset) {
|
||||||
|
value = m_settings.m_inputFrequencyOffset;
|
||||||
|
} else if (m_settings.m_frequencyMode == ChannelPowerSettings::Absolute) {
|
||||||
|
value = m_settings.m_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->deltaFrequency->blockSignals(true);
|
||||||
|
ui->deltaFrequency->setValue(value);
|
||||||
|
ui->deltaFrequency->blockSignals(false);
|
||||||
|
|
||||||
|
updateAbsoluteCenterFrequency();
|
||||||
|
applySettings({"frequency", "inputFrequencyOffset"});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelPowerGUI::channelMarkerHighlightedByCursor()
|
void ChannelPowerGUI::channelMarkerHighlightedByCursor()
|
||||||
@ -127,10 +142,23 @@ void ChannelPowerGUI::channelMarkerHighlightedByCursor()
|
|||||||
|
|
||||||
void ChannelPowerGUI::on_deltaFrequency_changed(qint64 value)
|
void ChannelPowerGUI::on_deltaFrequency_changed(qint64 value)
|
||||||
{
|
{
|
||||||
m_channelMarker.setCenterFrequency(value);
|
qint64 offset = 0;
|
||||||
|
|
||||||
|
if (m_settings.m_frequencyMode == ChannelPowerSettings::Offset)
|
||||||
|
{
|
||||||
|
offset = value;
|
||||||
|
m_settings.m_frequency = m_deviceCenterFrequency + offset;
|
||||||
|
}
|
||||||
|
else if (m_settings.m_frequencyMode == ChannelPowerSettings::Absolute)
|
||||||
|
{
|
||||||
|
m_settings.m_frequency = value;
|
||||||
|
offset = m_settings.m_frequency - m_deviceCenterFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_channelMarker.setCenterFrequency(offset);
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
updateAbsoluteCenterFrequency();
|
updateAbsoluteCenterFrequency();
|
||||||
applySetting("inputFrequencyOffset");
|
applySettings({"frequency", "inputFrequencyOffset"});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelPowerGUI::on_rfBW_changed(qint64 value)
|
void ChannelPowerGUI::on_rfBW_changed(qint64 value)
|
||||||
@ -255,7 +283,6 @@ ChannelPowerGUI::ChannelPowerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet,
|
|||||||
|
|
||||||
connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
|
connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
|
||||||
|
|
||||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
|
||||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||||
|
|
||||||
@ -334,7 +361,8 @@ void ChannelPowerGUI::displaySettings()
|
|||||||
|
|
||||||
blockApplySettings(true);
|
blockApplySettings(true);
|
||||||
|
|
||||||
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
|
ui->frequencyMode->setCurrentIndex((int) m_settings.m_frequencyMode);
|
||||||
|
on_frequencyMode_currentIndexChanged((int) m_settings.m_frequencyMode);
|
||||||
|
|
||||||
ui->rfBW->setValue(m_settings.m_rfBandwidth);
|
ui->rfBW->setValue(m_settings.m_rfBandwidth);
|
||||||
|
|
||||||
@ -427,6 +455,47 @@ void ChannelPowerGUI::tick()
|
|||||||
m_tickCount++;
|
m_tickCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChannelPowerGUI::on_frequencyMode_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
m_settings.m_frequencyMode = (ChannelPowerSettings::FrequencyMode) index;
|
||||||
|
ui->deltaFrequency->blockSignals(true);
|
||||||
|
|
||||||
|
if (m_settings.m_frequencyMode == ChannelPowerSettings::Offset)
|
||||||
|
{
|
||||||
|
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||||
|
ui->deltaFrequency->setValue(m_settings.m_inputFrequencyOffset);
|
||||||
|
ui->deltaUnits->setText("Hz");
|
||||||
|
}
|
||||||
|
else if (m_settings.m_frequencyMode == ChannelPowerSettings::Absolute)
|
||||||
|
{
|
||||||
|
ui->deltaFrequency->setValueRange(true, 11, 0, 99999999999, 0);
|
||||||
|
ui->deltaFrequency->setValue(m_settings.m_frequency);
|
||||||
|
ui->deltaUnits->setText("Hz");
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->deltaFrequency->blockSignals(false);
|
||||||
|
|
||||||
|
updateAbsoluteCenterFrequency();
|
||||||
|
applySetting("frequencyMode");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate input frequency offset, when device center frequency changes
|
||||||
|
void ChannelPowerGUI::calcOffset()
|
||||||
|
{
|
||||||
|
if (m_settings.m_frequencyMode == ChannelPowerSettings::Offset)
|
||||||
|
{
|
||||||
|
ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qint64 offset = m_settings.m_frequency - m_deviceCenterFrequency;
|
||||||
|
m_channelMarker.setCenterFrequency(offset);
|
||||||
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
|
updateAbsoluteCenterFrequency();
|
||||||
|
applySetting("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChannelPowerGUI::on_clearMeasurements_clicked()
|
void ChannelPowerGUI::on_clearMeasurements_clicked()
|
||||||
{
|
{
|
||||||
m_channelPower->resetMagLevels();
|
m_channelPower->resetMagLevels();
|
||||||
@ -434,6 +503,7 @@ void ChannelPowerGUI::on_clearMeasurements_clicked()
|
|||||||
|
|
||||||
void ChannelPowerGUI::makeUIConnections()
|
void ChannelPowerGUI::makeUIConnections()
|
||||||
{
|
{
|
||||||
|
QObject::connect(ui->frequencyMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ChannelPowerGUI::on_frequencyMode_currentIndexChanged);
|
||||||
QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ChannelPowerGUI::on_deltaFrequency_changed);
|
QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ChannelPowerGUI::on_deltaFrequency_changed);
|
||||||
QObject::connect(ui->rfBW, &ValueDial::changed, this, &ChannelPowerGUI::on_rfBW_changed);
|
QObject::connect(ui->rfBW, &ValueDial::changed, this, &ChannelPowerGUI::on_rfBW_changed);
|
||||||
QObject::connect(ui->pulseTH, QOverload<int>::of(&QDial::valueChanged), this, &ChannelPowerGUI::on_pulseTH_valueChanged);
|
QObject::connect(ui->pulseTH, QOverload<int>::of(&QDial::valueChanged), this, &ChannelPowerGUI::on_pulseTH_valueChanged);
|
||||||
@ -443,5 +513,12 @@ void ChannelPowerGUI::makeUIConnections()
|
|||||||
|
|
||||||
void ChannelPowerGUI::updateAbsoluteCenterFrequency()
|
void ChannelPowerGUI::updateAbsoluteCenterFrequency()
|
||||||
{
|
{
|
||||||
setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset);
|
setStatusFrequency(m_settings.m_frequency);
|
||||||
|
if ( (m_basebandSampleRate > 1)
|
||||||
|
&& ( (m_settings.m_inputFrequencyOffset >= m_basebandSampleRate / 2)
|
||||||
|
|| (m_settings.m_inputFrequencyOffset < -m_basebandSampleRate / 2))) {
|
||||||
|
setStatusText("Frequency out of band");
|
||||||
|
} else {
|
||||||
|
setStatusText("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,7 @@ private:
|
|||||||
void displaySettings();
|
void displaySettings();
|
||||||
bool handleMessage(const Message& message);
|
bool handleMessage(const Message& message);
|
||||||
void makeUIConnections();
|
void makeUIConnections();
|
||||||
|
void calcOffset();
|
||||||
void updateAbsoluteCenterFrequency();
|
void updateAbsoluteCenterFrequency();
|
||||||
void on_clearMeasurements_clicked();
|
void on_clearMeasurements_clicked();
|
||||||
|
|
||||||
@ -99,6 +100,7 @@ private:
|
|||||||
void enterEvent(EnterEventType*);
|
void enterEvent(EnterEventType*);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void on_frequencyMode_currentIndexChanged(int index);
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
void on_rfBW_changed(qint64 value);
|
void on_rfBW_changed(qint64 value);
|
||||||
void on_clearChannelPower_clicked();
|
void on_clearChannelPower_clicked();
|
||||||
|
@ -74,16 +74,32 @@
|
|||||||
<number>2</number>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="deltaFrequencyLabel">
|
<widget class="QComboBox" name="frequencyMode">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>16</width>
|
<width>40</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="maximumSize">
|
||||||
<string>Df</string>
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select frequency entry mode.</string>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Δf</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>f</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -36,6 +36,8 @@ void ChannelPowerSettings::resetToDefaults()
|
|||||||
m_rfBandwidth = 10000.0f;
|
m_rfBandwidth = 10000.0f;
|
||||||
m_pulseThreshold= -50.0f;
|
m_pulseThreshold= -50.0f;
|
||||||
m_averagePeriodUS = 100000;
|
m_averagePeriodUS = 100000;
|
||||||
|
m_frequencyMode = Offset;
|
||||||
|
m_frequency = 0;
|
||||||
m_rgbColor = QColor(102, 40, 220).rgb();
|
m_rgbColor = QColor(102, 40, 220).rgb();
|
||||||
m_title = "Channel Power";
|
m_title = "Channel Power";
|
||||||
m_streamIndex = 0;
|
m_streamIndex = 0;
|
||||||
@ -56,6 +58,8 @@ QByteArray ChannelPowerSettings::serialize() const
|
|||||||
s.writeFloat(2, m_rfBandwidth);
|
s.writeFloat(2, m_rfBandwidth);
|
||||||
s.writeFloat(3, m_pulseThreshold);
|
s.writeFloat(3, m_pulseThreshold);
|
||||||
s.writeS32(4, m_averagePeriodUS);
|
s.writeS32(4, m_averagePeriodUS);
|
||||||
|
s.writeS32(5, (int) m_frequencyMode);
|
||||||
|
s.writeS64(6, m_frequency);
|
||||||
|
|
||||||
s.writeU32(21, m_rgbColor);
|
s.writeU32(21, m_rgbColor);
|
||||||
s.writeString(22, m_title);
|
s.writeString(22, m_title);
|
||||||
@ -102,6 +106,8 @@ bool ChannelPowerSettings::deserialize(const QByteArray& data)
|
|||||||
d.readFloat(2, &m_rfBandwidth, 10000.0f);
|
d.readFloat(2, &m_rfBandwidth, 10000.0f);
|
||||||
d.readFloat(3, &m_pulseThreshold, 50.0f);
|
d.readFloat(3, &m_pulseThreshold, 50.0f);
|
||||||
d.readS32(4, &m_averagePeriodUS, 100000);
|
d.readS32(4, &m_averagePeriodUS, 100000);
|
||||||
|
d.readS32(5, (int *) &m_frequencyMode, (int) Offset);
|
||||||
|
d.readS64(6, &m_frequency);
|
||||||
|
|
||||||
d.readU32(21, &m_rgbColor, QColor(102, 40, 220).rgb());
|
d.readU32(21, &m_rgbColor, QColor(102, 40, 220).rgb());
|
||||||
d.readString(22, &m_title, "Channel Power");
|
d.readString(22, &m_title, "Channel Power");
|
||||||
@ -161,6 +167,18 @@ void ChannelPowerSettings::applySettings(const QStringList& settingsKeys, const
|
|||||||
if (settingsKeys.contains("averagePeriodUS")) {
|
if (settingsKeys.contains("averagePeriodUS")) {
|
||||||
m_averagePeriodUS = settings.m_averagePeriodUS;
|
m_averagePeriodUS = settings.m_averagePeriodUS;
|
||||||
}
|
}
|
||||||
|
if (settingsKeys.contains("frequencyMode")) {
|
||||||
|
m_frequencyMode = settings.m_frequencyMode;
|
||||||
|
}
|
||||||
|
if (settingsKeys.contains("frequency")) {
|
||||||
|
m_frequency = settings.m_frequency;
|
||||||
|
}
|
||||||
|
if (settingsKeys.contains("rgbColor")) {
|
||||||
|
m_rgbColor = settings.m_rgbColor;
|
||||||
|
}
|
||||||
|
if (settingsKeys.contains("title")) {
|
||||||
|
m_title = settings.m_title;
|
||||||
|
}
|
||||||
if (settingsKeys.contains("useReverseAPI")) {
|
if (settingsKeys.contains("useReverseAPI")) {
|
||||||
m_useReverseAPI = settings.m_useReverseAPI;
|
m_useReverseAPI = settings.m_useReverseAPI;
|
||||||
}
|
}
|
||||||
@ -191,6 +209,12 @@ QString ChannelPowerSettings::getDebugString(const QStringList& settingsKeys, bo
|
|||||||
if (settingsKeys.contains("averagePeriodUS") || force) {
|
if (settingsKeys.contains("averagePeriodUS") || force) {
|
||||||
ostr << " m_averagePeriodUS: " << m_averagePeriodUS;
|
ostr << " m_averagePeriodUS: " << m_averagePeriodUS;
|
||||||
}
|
}
|
||||||
|
if (settingsKeys.contains("frequencyMode") || force) {
|
||||||
|
ostr << " m_frequencyMode: " << m_frequencyMode;
|
||||||
|
}
|
||||||
|
if (settingsKeys.contains("frequency") || force) {
|
||||||
|
ostr << " m_frequency: " << m_frequency;
|
||||||
|
}
|
||||||
if (settingsKeys.contains("useReverseAPI") || force) {
|
if (settingsKeys.contains("useReverseAPI") || force) {
|
||||||
ostr << " m_useReverseAPI: " << m_useReverseAPI;
|
ostr << " m_useReverseAPI: " << m_useReverseAPI;
|
||||||
}
|
}
|
||||||
@ -200,7 +224,7 @@ QString ChannelPowerSettings::getDebugString(const QStringList& settingsKeys, bo
|
|||||||
if (settingsKeys.contains("reverseAPIPort") || force) {
|
if (settingsKeys.contains("reverseAPIPort") || force) {
|
||||||
ostr << " m_reverseAPIPort: " << m_reverseAPIPort;
|
ostr << " m_reverseAPIPort: " << m_reverseAPIPort;
|
||||||
}
|
}
|
||||||
if (settingsKeys.contains("everseAPIDeviceIndex") || force) {
|
if (settingsKeys.contains("reverseAPIDeviceIndex") || force) {
|
||||||
ostr << " m_reverseAPIDeviceIndex: " << m_reverseAPIDeviceIndex;
|
ostr << " m_reverseAPIDeviceIndex: " << m_reverseAPIDeviceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
|
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
|
||||||
// Copyright (C) 2023 Jon Beniston, M7RCE //
|
// Copyright (C) 2023-2024 Jon Beniston, M7RCE //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// 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 //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
@ -32,6 +32,11 @@ struct ChannelPowerSettings
|
|||||||
Real m_rfBandwidth;
|
Real m_rfBandwidth;
|
||||||
float m_pulseThreshold;
|
float m_pulseThreshold;
|
||||||
int m_averagePeriodUS;
|
int m_averagePeriodUS;
|
||||||
|
enum FrequencyMode {
|
||||||
|
Offset,
|
||||||
|
Absolute
|
||||||
|
} m_frequencyMode;
|
||||||
|
qint64 m_frequency;
|
||||||
|
|
||||||
quint32 m_rgbColor;
|
quint32 m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
Loading…
Reference in New Issue
Block a user