1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-21 23:55:13 -05:00
This commit is contained in:
srcejon 2023-09-01 20:09:37 +01:00
parent 1ec01ab2d9
commit 01ab3e440e
14 changed files with 173 additions and 173 deletions

BIN
doc/img/RTTYMod_plugin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -102,12 +102,12 @@ Full details of the API can be found in the Swagger documentation. Below are a f
To transmit the current text simply send a "tx" action:
curl -X POST "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/actions" -d '{"channelType": "RTTYMod", "direction": 1, "RTTYModActions": { "tx": 1}}'
curl -X POST "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/actions" -d '{"channelType": "RTTYMod", "direction": 1, "RTTYModActions": { "tx": 1 }}'
To transmit a packet from the command line:
To transmit text specified on the command line:
curl -X POST "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/actions" -d '{"channelType": "RTTYMod", "direction": 1, "RTTYModActions": { "tx": 1, "payload": {"text": "CQ CQ CQ anyone using SDRangel" }}}'
curl -X POST "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/actions" -d '{"channelType": "RTTYMod", "direction": 1, "RTTYModActions": { "tx": 1, "payload": {"text": "CQ CQ CQ anyone using SDRangel CQ" }}}'
To set the baud rate and frequency shift:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/settings" -d '{"channelType": "RTTYMod", "direction": 1, "RTTYModSettings": {"baud": 45.45; "frequencyShift": 170 }}'
curl -X PATCH "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/settings" -d '{"channelType": "RTTYMod", "direction": 1, "RTTYModSettings": {"baud": 45.45, "frequencyShift": 170 }}'

View File

@ -51,8 +51,7 @@
MESSAGE_CLASS_DEFINITION(RttyMod::MsgConfigureRttyMod, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgTx, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgReportTx, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgTXPacketBytes, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgTXPacketData, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgTXText, Message)
const char* const RttyMod::m_channelIdURI = "sdrangel.channeltx.modrtty";
const char* const RttyMod::m_channelId = "RTTYMod";
@ -151,9 +150,9 @@ bool RttyMod::handleMessage(const Message& cmd)
return true;
}
else if (MsgTXPacketData::match(cmd))
else if (MsgTXText::match(cmd))
{
MsgTXPacketData* msg = new MsgTXPacketData((const MsgTXPacketData&)cmd);
MsgTXText* msg = new MsgTXText((const MsgTXText&)cmd);
m_basebandSource->getInputMessageQueue()->push(msg);
return true;
@ -209,6 +208,13 @@ void RttyMod::applySettings(const RttyModSettings& settings, bool force)
<< " m_channelMute: " << settings.m_channelMute
<< " m_repeat: " << settings.m_repeat
<< " m_repeatCount: " << settings.m_repeatCount
<< " m_text: " << settings.m_text
<< " m_characterSet: " << settings.m_characterSet
<< " m_unshiftOnSpace: " << settings.m_unshiftOnSpace
<< " m_msbFirst: " << settings.m_msbFirst
<< " m_spaceHigh: " << settings.m_spaceHigh
<< " m_prefixCRLF: " << settings.m_prefixCRLF
<< " m_postfixCRLF: " << settings.m_postfixCRLF
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIAddress: " << settings.m_reverseAPIPort
@ -254,10 +260,6 @@ void RttyMod::applySettings(const RttyModSettings& settings, bool force)
reverseAPIKeys.append("lpfTaps");
}
if ((settings.m_bbNoise != m_settings.m_bbNoise) || force) {
reverseAPIKeys.append("bbNoise");
}
if ((settings.m_rfNoise != m_settings.m_rfNoise) || force) {
reverseAPIKeys.append("rfNoise");
}
@ -274,6 +276,30 @@ void RttyMod::applySettings(const RttyModSettings& settings, bool force)
reverseAPIKeys.append("symbolSpan");
}
if ((settings.m_characterSet != m_settings.m_characterSet) || force) {
reverseAPIKeys.append("characterSet");
}
if ((settings.m_unshiftOnSpace != m_settings.m_unshiftOnSpace) || force) {
reverseAPIKeys.append("unshiftOnSpace");
}
if ((settings.m_msbFirst != m_settings.m_msbFirst) || force) {
reverseAPIKeys.append("msbFirst");
}
if ((settings.m_spaceHigh != m_settings.m_spaceHigh) || force) {
reverseAPIKeys.append("spaceHigh");
}
if ((settings.m_prefixCRLF != m_settings.m_prefixCRLF) || force) {
reverseAPIKeys.append("prefixCRLF");
}
if ((settings.m_postfixCRLF != m_settings.m_postfixCRLF) || force) {
reverseAPIKeys.append("postfixCRLF");
}
if ((settings.m_udpEnabled != m_settings.m_udpEnabled) || force) {
reverseAPIKeys.append("udpEnabled");
}
@ -450,14 +476,11 @@ void RttyMod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("lpfTaps")) {
settings.m_lpfTaps = response.getRttyModSettings()->getLpfTaps();
}
if (channelSettingsKeys.contains("bbNoise")) {
settings.m_bbNoise = response.getRttyModSettings()->getBbNoise() != 0;
}
if (channelSettingsKeys.contains("rfNoise")) {
settings.m_rfNoise = response.getRttyModSettings()->getRfNoise() != 0;
}
if (channelSettingsKeys.contains("text")) {
settings.m_text = *response.getRttyModSettings()->getData();
settings.m_text = *response.getRttyModSettings()->getText();
}
if (channelSettingsKeys.contains("beta")) {
settings.m_beta = response.getRttyModSettings()->getBeta();
@ -465,6 +488,24 @@ void RttyMod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("symbolSpan")) {
settings.m_symbolSpan = response.getRttyModSettings()->getSymbolSpan();
}
if (channelSettingsKeys.contains("characterSet")) {
settings.m_characterSet = (Baudot::CharacterSet) response.getRttyModSettings()->getCharacterSet();
}
if (channelSettingsKeys.contains("unshiftOnSpace")) {
settings.m_unshiftOnSpace = response.getRttyModSettings()->getUnshiftOnSpace();
}
if (channelSettingsKeys.contains("msbFirst")) {
settings.m_msbFirst = response.getRttyModSettings()->getMsbFirst();
}
if (channelSettingsKeys.contains("spaceHigh")) {
settings.m_spaceHigh = response.getRttyModSettings()->getSpaceHigh();
}
if (channelSettingsKeys.contains("prefixCRLF")) {
settings.m_prefixCRLF = response.getRttyModSettings()->getPrefixCrlf();
}
if (channelSettingsKeys.contains("postfixCRLF")) {
settings.m_postfixCRLF = response.getRttyModSettings()->getPostfixCrlf();
}
if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getRttyModSettings()->getRgbColor();
}
@ -531,10 +572,10 @@ int RttyMod::webapiActionsPost(
if (swgRttyModActions->getTx() != 0)
{
if (channelActionsKeys.contains("payload")
&& (swgRttyModActions->getPayload()->getData()))
&& (swgRttyModActions->getPayload()->getText()))
{
MsgTXPacketData *msg = MsgTXPacketData::create(
*swgRttyModActions->getPayload()->getData()
MsgTXText *msg = MsgTXText::create(
*swgRttyModActions->getPayload()->getText()
);
m_basebandSource->getInputMessageQueue()->push(msg);
}
@ -548,19 +589,19 @@ int RttyMod::webapiActionsPost(
}
else
{
errorMessage = "Packet must contain tx action";
errorMessage = "Must contain tx action";
return 400;
}
}
else
{
errorMessage = "Unknown action";
errorMessage = "Unknown RTTYMod action";
return 400;
}
}
else
{
errorMessage = "Missing RttyModActions in query";
errorMessage = "Missing RTTYModActions in query";
return 400;
}
return 0;
@ -577,18 +618,26 @@ void RttyMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respo
response.getRttyModSettings()->setRepeat(settings.m_repeat ? 1 : 0);
response.getRttyModSettings()->setRepeatCount(settings.m_repeatCount);
response.getRttyModSettings()->setLpfTaps(settings.m_lpfTaps);
response.getRttyModSettings()->setBbNoise(settings.m_bbNoise ? 1 : 0);
response.getRttyModSettings()->setRfNoise(settings.m_rfNoise ? 1 : 0);
if (response.getRttyModSettings()->getData()) {
*response.getRttyModSettings()->getData() = settings.m_text;
if (response.getRttyModSettings()->getText()) {
*response.getRttyModSettings()->getText() = settings.m_text;
} else {
response.getRttyModSettings()->setData(new QString(settings.m_text));
response.getRttyModSettings()->setText(new QString(settings.m_text));
}
response.getRttyModSettings()->setPulseShaping(settings.m_pulseShaping ? 1 : 0);
response.getRttyModSettings()->setBeta(settings.m_beta);
response.getRttyModSettings()->setSymbolSpan(settings.m_symbolSpan);
response.getRttyModSettings()->setCharacterSet((int) settings.m_characterSet);
response.getRttyModSettings()->setSymbolSpan(settings.m_symbolSpan);
response.getRttyModSettings()->setUnshiftOnSpace(settings.m_unshiftOnSpace);
response.getRttyModSettings()->setMsbFirst(settings.m_msbFirst);
response.getRttyModSettings()->setSpaceHigh(settings.m_spaceHigh);
response.getRttyModSettings()->setPrefixCrlf(settings.m_prefixCRLF);
response.getRttyModSettings()->setPostfixCrlf(settings.m_postfixCRLF);
response.getRttyModSettings()->setUdpEnabled(settings.m_udpEnabled);
response.getRttyModSettings()->setUdpAddress(new QString(settings.m_udpAddress));
response.getRttyModSettings()->setUdpPort(settings.m_udpPort);
@ -741,14 +790,11 @@ void RttyMod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("lpfTaps")) {
swgRttyModSettings->setLpfTaps(settings.m_lpfTaps);
}
if (channelSettingsKeys.contains("bbNoise")) {
swgRttyModSettings->setBbNoise(settings.m_bbNoise ? 1 : 0);
}
if (channelSettingsKeys.contains("rfNoise")) {
swgRttyModSettings->setRfNoise(settings.m_rfNoise ? 1 : 0);
}
if (channelSettingsKeys.contains("text")) {
swgRttyModSettings->setData(new QString(settings.m_text));
swgRttyModSettings->setText(new QString(settings.m_text));
}
if (channelSettingsKeys.contains("beta")) {
swgRttyModSettings->setBeta(settings.m_beta);
@ -756,6 +802,24 @@ void RttyMod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("symbolSpan")) {
swgRttyModSettings->setSymbolSpan(settings.m_symbolSpan);
}
if (channelSettingsKeys.contains("characterSet")) {
swgRttyModSettings->setCharacterSet((int) settings.m_characterSet);
}
if (channelSettingsKeys.contains("unshiftOnSpace")) {
swgRttyModSettings->setUnshiftOnSpace(settings.m_unshiftOnSpace);
}
if (channelSettingsKeys.contains("msbFirst")) {
swgRttyModSettings->setMsbFirst(settings.m_msbFirst);
}
if (channelSettingsKeys.contains("spaceHigh")) {
swgRttyModSettings->setSpaceHigh(settings.m_spaceHigh);
}
if (channelSettingsKeys.contains("prefixCRLF")) {
swgRttyModSettings->setPrefixCrlf(settings.m_prefixCRLF);
}
if (channelSettingsKeys.contains("postfixCRLF")) {
swgRttyModSettings->setPostfixCrlf(settings.m_postfixCRLF);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgRttyModSettings->setRgbColor(settings.m_rgbColor);
}
@ -838,7 +902,7 @@ void RttyMod::openUDP(const RttyModSettings& settings)
if (!m_udpSocket->bind(QHostAddress(settings.m_udpAddress), settings.m_udpPort))
qCritical() << "RttyMod::openUDP: Failed to bind to port " << settings.m_udpAddress << ":" << settings.m_udpPort << ". Error: " << m_udpSocket->error();
else
qDebug() << "RttyMod::openUDP: Listening for packets on " << settings.m_udpAddress << ":" << settings.m_udpPort;
qDebug() << "RttyMod::openUDP: Listening for text on " << settings.m_udpAddress << ":" << settings.m_udpPort;
connect(m_udpSocket, &QUdpSocket::readyRead, this, &RttyMod::udpRx);
}
@ -857,7 +921,7 @@ void RttyMod::udpRx()
while (m_udpSocket->hasPendingDatagrams())
{
QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
MsgTXPacketBytes *msg = MsgTXPacketBytes::create(datagram.data());
MsgTXText *msg = MsgTXText::create(QString(datagram.data()));
m_basebandSource->getInputMessageQueue()->push(msg);
}
}

View File

@ -102,40 +102,22 @@ public:
{ }
};
class MsgTXPacketBytes : public Message {
class MsgTXText : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgTXPacketBytes* create(QByteArray data) {
return new MsgTXPacketBytes(data);
}
QByteArray m_data;
private:
MsgTXPacketBytes(QByteArray data) :
Message(),
m_data(data)
{ }
};
class MsgTXPacketData : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgTXPacketData* create(QString data)
static MsgTXText* create(QString text)
{
return new MsgTXPacketData(data);
return new MsgTXText(text);
}
QString m_data;
QString m_text;
private:
MsgTXPacketData(QString data) :
MsgTXText(QString text) :
Message(),
m_data(data)
m_text(text)
{ }
};

View File

@ -152,21 +152,14 @@ bool RttyModBaseband::handleMessage(const Message& cmd)
else if (RttyMod::MsgTx::match(cmd))
{
qDebug() << "RttyModBaseband::handleMessage: MsgTx";
m_source.addTXPacket(m_settings.m_text);
m_source.addTXText(m_settings.m_text);
return true;
}
else if (RttyMod::MsgTXPacketBytes::match(cmd))
else if (RttyMod::MsgTXText::match(cmd))
{
RttyMod::MsgTXPacketBytes& tx = (RttyMod::MsgTXPacketBytes&) cmd;
m_source.addTXPacket(tx.m_data);
return true;
}
else if (RttyMod::MsgTXPacketData::match(cmd))
{
RttyMod::MsgTXPacketData& tx = (RttyMod::MsgTXPacketData&) cmd;
m_source.addTXPacket(tx.m_data);
RttyMod::MsgTXText& tx = (RttyMod::MsgTXText&) cmd;
m_source.addTXText(tx.m_text);
return true;
}

View File

@ -71,7 +71,7 @@ QByteArray RttyModGUI::serialize() const
bool RttyModGUI::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
if (m_settings.deserialize(data)) {
displaySettings();
applySettings(true);
return true;
@ -246,8 +246,7 @@ void RttyModGUI::on_endian_clicked(bool checked)
m_settings.m_msbFirst = checked;
if (checked) {
ui->endian->setText("MSB");
}
else {
} else {
ui->endian->setText("LSB");
}
applySettings();
@ -258,8 +257,7 @@ void RttyModGUI::on_spaceHigh_clicked(bool checked)
m_settings.m_spaceHigh = checked;
if (checked) {
ui->spaceHigh->setText("M-S");
}
else {
} else {
ui->spaceHigh->setText("S-M");
}
applySettings();
@ -436,10 +434,9 @@ RttyModGUI::RttyModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum);
// Extra /2 here because SSB?
ui->glSpectrum->setCenterFrequency(8000/4);
ui->glSpectrum->setSampleRate(8000/2);
ui->glSpectrum->setLsbDisplay(true);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(2000);
ui->glSpectrum->setLsbDisplay(false);
SpectrumSettings spectrumSettings = m_spectrumVis->getSettings();
spectrumSettings.m_ssb = false;
@ -464,7 +461,7 @@ RttyModGUI::RttyModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
m_channelMarker.setColor(Qt::red);
m_channelMarker.setBandwidth(12500);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setTitle("Packet Modulator");
m_channelMarker.setTitle("RTTY Modulator");
m_channelMarker.setSourceOrSinkStream(false);
m_channelMarker.blockSignals(false);
m_channelMarker.setVisible(true); // activate signal on the last setting only
@ -496,18 +493,9 @@ RttyModGUI::~RttyModGUI()
delete ui;
}
void RttyModGUI::transmit(const QString& str)
void RttyModGUI::transmit(const QString& text)
{
QString s = str;
if (m_settings.m_prefixCRLF) {
s.prepend("\r\r\n>"); // '>' switches to letters
}
if (m_settings.m_postfixCRLF) {
s.append("\r\r\n");
}
RttyMod::MsgTXPacketData *msg = RttyMod::MsgTXPacketData::create(s);
RttyMod::MsgTXText*msg = RttyMod::MsgTXText::create(text);
m_rttyMod->getInputMessageQueue()->push(msg);
}
@ -566,12 +554,11 @@ void RttyModGUI::displaySettings()
ui->mode->setCurrentText("Custom");
ui->rfBWText->setText(formatFrequency(m_settings.m_rfBandwidth));
ui->rfBW->setValue(m_settings.m_rfBandwidth / 100.0);
ui->rfBW->setValue(m_settings.m_rfBandwidth);
QString baudRate;
if (m_settings.m_baud < 46.0f && m_settings.m_baud > 45.0f) {
baudRate = "45.45";
}
else {
} else {
baudRate = QString("%1").arg(m_settings.m_baud);
}
ui->baudRate->setCurrentIndex(ui->baudRate->findText(baudRate));
@ -583,15 +570,13 @@ void RttyModGUI::displaySettings()
ui->endian->setChecked(m_settings.m_msbFirst);
if (m_settings.m_msbFirst) {
ui->endian->setText("MSB");
}
else {
} else {
ui->endian->setText("LSB");
}
ui->spaceHigh->setChecked(m_settings.m_spaceHigh);
if (m_settings.m_spaceHigh) {
ui->spaceHigh->setText("M-S");
}
else {
} else {
ui->spaceHigh->setText("S-M");
}

View File

@ -27,7 +27,7 @@ public:
explicit RttyModRepeatDialog(int repeatCount, QWidget* parent = 0);
~RttyModRepeatDialog();
int m_repeatCount; // Number of packets to transmit (-1 = infinite)
int m_repeatCount; // Number of times to transmit
private slots:
void accept();

View File

@ -43,7 +43,6 @@ void RttyModSettings::resetToDefaults()
m_repeat = false;
m_repeatCount = 10;
m_lpfTaps = 301;
m_bbNoise = false;
m_rfNoise = false;
m_writeToFile = false;
m_text = "CQ CQ CQ DE SDRangel CQ";
@ -94,7 +93,6 @@ QByteArray RttyModSettings::serialize() const
s.writeBool(7, m_repeat);
s.writeS32(9, m_repeatCount);
s.writeS32(23, m_lpfTaps);
s.writeBool(24, m_bbNoise);
s.writeBool(25, m_rfNoise);
s.writeBool(26, m_writeToFile);
s.writeString(30, m_text);
@ -165,7 +163,6 @@ bool RttyModSettings::deserialize(const QByteArray& data)
d.readBool(7, &m_repeat, false);
d.readS32(9, &m_repeatCount, -1);
d.readS32(23, &m_lpfTaps, 301);
d.readBool(24, &m_bbNoise, false);
d.readBool(25, &m_rfNoise, false);
d.readBool(26, &m_writeToFile, false);
d.readString(30, &m_text, "CQ CQ CQ anyone using SDRangel");

View File

@ -37,7 +37,6 @@ struct RttyModSettings
bool m_repeat;
int m_repeatCount;
int m_lpfTaps;
bool m_bbNoise;
bool m_rfNoise;
bool m_writeToFile;
QString m_text; // Text to send

View File

@ -29,10 +29,10 @@
RttyModSource::RttyModSource() :
m_channelSampleRate(48000),
m_channelFrequencyOffset(0),
m_spectrumRate(8000),
m_audioPhase(0.0f),
m_spectrumRate(2000),
m_fmPhase(0.0),
m_spectrumSink(nullptr),
m_specSampleBufferIndex(0),
m_magsq(0.0),
m_levelCalcCount(0),
m_peakLevel(0.0f),
@ -48,6 +48,7 @@ RttyModSource::RttyModSource() :
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
m_specSampleBuffer.resize(m_specSampleBufferSize);
m_interpolatorDistanceRemain = 0;
m_interpolatorConsumed = false;
m_interpolatorDistance = (Real)m_channelSampleRate / (Real)m_spectrumRate;
@ -98,21 +99,22 @@ void RttyModSource::pullOne(Sample& sample)
sample.m_imag = (FixReal) (ci.imag() * SDR_TX_SCALEF);
}
void RttyModSource::sampleToSpectrum(Real sample)
void RttyModSource::sampleToSpectrum(Complex sample)
{
if (m_spectrumSink)
{
Complex out;
Complex in;
in.real(sample);
in.imag(0.0f);
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, in, &out))
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, sample, &out))
{
sample = std::real(out);
m_sampleBuffer.push_back(Sample(sample * 0.891235351562f * SDR_TX_SCALEF, 0.0f));
m_spectrumSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), true);
m_sampleBuffer.clear();
m_interpolatorDistanceRemain += m_interpolatorDistance;
Real r = std::real(out) * SDR_TX_SCALEF;
Real i = std::imag(out) * SDR_TX_SCALEF;
m_specSampleBuffer[m_specSampleBufferIndex++] = Sample(r, i);
if (m_specSampleBufferIndex == m_specSampleBufferSize)
{
m_spectrumSink->feed(m_specSampleBuffer.begin(), m_specSampleBuffer.end(), false);
m_specSampleBufferIndex = 0;
}
}
}
}
@ -130,12 +132,12 @@ void RttyModSource::modulateSample()
// Encode a character at a time, so we get a TxReport after each character
QString s = m_textToTransmit.left(1);
m_textToTransmit = m_textToTransmit.mid(1);
encodePacket(s);
encodeText(s);
}
else
{
// Transmit "diddle"
encodePacket(">");
encodeText(">");
}
initTX();
}
@ -148,30 +150,20 @@ void RttyModSource::modulateSample()
m_sampleIdx = 0;
}
if (!m_settings.m_bbNoise)
// FSK
if (m_settings.m_pulseShaping)
{
// FSK
if (m_settings.m_pulseShaping)
{
if (m_sampleIdx == 1) {
audioMod = m_pulseShape.filter(m_bit ? 1.0f : -1.0f);
} else {
audioMod = m_pulseShape.filter(0.0f);
}
}
else
{
audioMod = m_bit ? 1.0f : -1.0f;
if (m_sampleIdx == 1) {
audioMod = m_pulseShape.filter(m_bit ? 1.0f : -1.0f);
} else {
audioMod = m_pulseShape.filter(0.0f);
}
}
else
{
audioMod = (Real)rand() / ((Real)RAND_MAX) - 0.5; // Noise to test filter frequency response
audioMod = m_bit ? 1.0f : -1.0f;
}
// Display baseband audio in spectrum analyser
sampleToSpectrum(audioMod);
// FM
m_fmPhase += m_phaseSensitivity * audioMod * (m_settings.m_spaceHigh ? -1.0f : 1.0f);
// Keep phase in range -pi,pi
@ -196,6 +188,9 @@ void RttyModSource::modulateSample()
// Apply low pass filter to limit RF BW
m_modSample = m_lowpass.filter(m_modSample);
// Display in spectrum analyser
sampleToSpectrum(m_modSample);
Real s = std::real(m_modSample);
calculateLevel(s);
@ -245,7 +240,12 @@ void RttyModSource::calculateLevel(Real& sample)
void RttyModSource::applySettings(const RttyModSettings& settings, bool force)
{
// Only recreate filters if settings have changed
if ((settings.m_baud != m_settings.m_baud) || force)
{
m_samplesPerSymbol = m_channelSampleRate / settings.m_baud;
qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << settings.m_baud << ")";
}
if ((settings.m_lpfTaps != m_settings.m_lpfTaps) || (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
{
qDebug() << "RttyModSource::applySettings: Creating new lpf with taps " << settings.m_lpfTaps << " rfBW " << settings.m_rfBandwidth;
@ -273,9 +273,6 @@ void RttyModSource::applySettings(const RttyModSettings& settings, bool force)
m_settings = settings;
m_samplesPerSymbol = m_channelSampleRate / m_settings.m_baud;
qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << m_settings.m_baud << ")";
// Precalculate FM sensensity and linear gain to save doing it in the loop
m_phaseSensitivity = 2.0f * M_PI * (m_settings.m_frequencyShift/2.0f) / (double)m_channelSampleRate;
m_linearGain = powf(10.0f, m_settings.m_gain/20.0f);
@ -320,6 +317,7 @@ void RttyModSource::applyChannelSettings(int channelSampleRate, int channelFrequ
m_channelFrequencyOffset = channelFrequencyOffset;
m_samplesPerSymbol = m_channelSampleRate / m_settings.m_baud;
qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << m_settings.m_baud << ")";
// Precalculate FM sensensity to save doing it in the loop
m_phaseSensitivity = 2.0f * M_PI * (m_settings.m_frequencyShift/2.0f) / (double)m_channelSampleRate;
@ -385,25 +383,26 @@ void RttyModSource::initTX()
m_bit = 0;
}
void RttyModSource::addTXPacket(QString data)
void RttyModSource::addTXText(QString text)
{
int count = m_settings.m_repeat ? m_settings.m_repeatCount : 1;
for (int i = 0; i < count; i++) {
m_textToTransmit.append(data);
QString s = text;
if (m_settings.m_prefixCRLF) {
s.prepend("\r\r\n>"); // '>' switches to letters
}
if (m_settings.m_postfixCRLF) {
s.append("\r\r\n");
}
m_textToTransmit.append(s);
}
}
void RttyModSource::addTXPacket(QByteArray data)
{
int count = m_settings.m_repeat ? m_settings.m_repeatCount : 1;
for (int i = 0; i < count; i++) {
m_textToTransmit.append(QString(data));
}
}
void RttyModSource::encodePacket(const QString& text)
void RttyModSource::encodeText(const QString& text)
{
// RTTY encoding
m_byteIdx = 0;

View File

@ -58,10 +58,7 @@ public:
void setSpectrumSink(BasebandSampleSink *sampleSink) { m_spectrumSink = sampleSink; }
void applySettings(const RttyModSettings& settings, bool force = false);
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
void addTXPacket(QString data);
void addTXPacket(QByteArray data);
//void encodePacket(uint8_t *packet, int packet_length, uint8_t *packet_end);
void encodePacket(const QString& data);
void addTXText(QString data);
void setChannel(ChannelAPI *channel) { m_channel = channel; }
int getChannelSampleRate() const { return m_channelSampleRate; }
@ -73,7 +70,6 @@ private:
ChannelAPI *m_channel;
NCO m_carrierNco;
Real m_audioPhase;
double m_fmPhase; // Double gives cleaner spectrum than Real
double m_phaseSensitivity;
Real m_linearGain;
@ -84,8 +80,10 @@ private:
Lowpass<Complex> m_lowpass; // Low pass filter to limit RF bandwidth
BasebandSampleSink* m_spectrumSink; // Spectrum GUI to display baseband waveform
SampleVector m_sampleBuffer;
Interpolator m_interpolator; // Interpolator to downsample to 4k in spectrum
SampleVector m_specSampleBuffer;
static const int m_specSampleBufferSize = 256;
int m_specSampleBufferIndex;
Interpolator m_interpolator; // Interpolator to downsample to spectrum
Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain;
bool m_interpolatorConsumed;
@ -121,13 +119,14 @@ private:
MessageQueue* getMessageQueueToGUI() { return m_messageQueueToGUI; }
void encodeText(const QString& data);
int getBit(); // Get bit from m_bits
void addBit(int bit); // Add bit to m_bits, with zero stuffing
void initTX();
void calculateLevel(Real& sample);
void modulateSample();
void sampleToSpectrum(Real sample);
void sampleToSpectrum(Complex sample);
};

View File

@ -39,7 +39,6 @@ RttyModTXSettingsDialog::RttyModTXSettingsDialog(RttyModSettings* settings, QWid
ui->beta->setValue(m_settings->m_beta);
ui->symbolSpan->setValue(m_settings->m_symbolSpan);
ui->lpfTaps->setValue(m_settings->m_lpfTaps);
ui->bbNoise->setChecked(m_settings->m_bbNoise);
ui->rfNoise->setChecked(m_settings->m_rfNoise);
}
@ -60,7 +59,6 @@ void RttyModTXSettingsDialog::accept()
m_settings->m_beta = ui->beta->value();
m_settings->m_symbolSpan = ui->symbolSpan->value();
m_settings->m_lpfTaps = ui->lpfTaps->value();
m_settings->m_bbNoise = ui->bbNoise->isChecked();
m_settings->m_rfNoise = ui->rfNoise->isChecked();
QDialog::accept();

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>351</width>
<height>546</height>
<height>554</height>
</rect>
</property>
<property name="font">
@ -220,16 +220,6 @@ ${location}</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="bbNoise">
<property name="toolTip">
<string>Generate white noise as baseband signal.</string>
</property>
<property name="text">
<string>Generate BB noise</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="rfNoise">
<property name="toolTip">
<string>Generate white noise as RF signal.</string>

View File

@ -23,12 +23,6 @@ RTTYModSettings:
type: integer
lpfTaps:
type: integer
bbNoise:
type: integer
description: >
Boolean
* 0 - off
* 1 - on
rfNoise:
type: integer
description: >