1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 17:28:50 -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: 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: 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::MsgConfigureRttyMod, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgTx, Message) MESSAGE_CLASS_DEFINITION(RttyMod::MsgTx, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgReportTx, Message) MESSAGE_CLASS_DEFINITION(RttyMod::MsgReportTx, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgTXPacketBytes, Message) MESSAGE_CLASS_DEFINITION(RttyMod::MsgTXText, Message)
MESSAGE_CLASS_DEFINITION(RttyMod::MsgTXPacketData, Message)
const char* const RttyMod::m_channelIdURI = "sdrangel.channeltx.modrtty"; const char* const RttyMod::m_channelIdURI = "sdrangel.channeltx.modrtty";
const char* const RttyMod::m_channelId = "RTTYMod"; const char* const RttyMod::m_channelId = "RTTYMod";
@ -151,9 +150,9 @@ bool RttyMod::handleMessage(const Message& cmd)
return true; 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); m_basebandSource->getInputMessageQueue()->push(msg);
return true; return true;
@ -209,6 +208,13 @@ void RttyMod::applySettings(const RttyModSettings& settings, bool force)
<< " m_channelMute: " << settings.m_channelMute << " m_channelMute: " << settings.m_channelMute
<< " m_repeat: " << settings.m_repeat << " m_repeat: " << settings.m_repeat
<< " m_repeatCount: " << settings.m_repeatCount << " 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_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIAddress: " << settings.m_reverseAPIPort << " m_reverseAPIAddress: " << settings.m_reverseAPIPort
@ -254,10 +260,6 @@ void RttyMod::applySettings(const RttyModSettings& settings, bool force)
reverseAPIKeys.append("lpfTaps"); reverseAPIKeys.append("lpfTaps");
} }
if ((settings.m_bbNoise != m_settings.m_bbNoise) || force) {
reverseAPIKeys.append("bbNoise");
}
if ((settings.m_rfNoise != m_settings.m_rfNoise) || force) { if ((settings.m_rfNoise != m_settings.m_rfNoise) || force) {
reverseAPIKeys.append("rfNoise"); reverseAPIKeys.append("rfNoise");
} }
@ -274,6 +276,30 @@ void RttyMod::applySettings(const RttyModSettings& settings, bool force)
reverseAPIKeys.append("symbolSpan"); 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) { if ((settings.m_udpEnabled != m_settings.m_udpEnabled) || force) {
reverseAPIKeys.append("udpEnabled"); reverseAPIKeys.append("udpEnabled");
} }
@ -450,14 +476,11 @@ void RttyMod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("lpfTaps")) { if (channelSettingsKeys.contains("lpfTaps")) {
settings.m_lpfTaps = response.getRttyModSettings()->getLpfTaps(); settings.m_lpfTaps = response.getRttyModSettings()->getLpfTaps();
} }
if (channelSettingsKeys.contains("bbNoise")) {
settings.m_bbNoise = response.getRttyModSettings()->getBbNoise() != 0;
}
if (channelSettingsKeys.contains("rfNoise")) { if (channelSettingsKeys.contains("rfNoise")) {
settings.m_rfNoise = response.getRttyModSettings()->getRfNoise() != 0; settings.m_rfNoise = response.getRttyModSettings()->getRfNoise() != 0;
} }
if (channelSettingsKeys.contains("text")) { if (channelSettingsKeys.contains("text")) {
settings.m_text = *response.getRttyModSettings()->getData(); settings.m_text = *response.getRttyModSettings()->getText();
} }
if (channelSettingsKeys.contains("beta")) { if (channelSettingsKeys.contains("beta")) {
settings.m_beta = response.getRttyModSettings()->getBeta(); settings.m_beta = response.getRttyModSettings()->getBeta();
@ -465,6 +488,24 @@ void RttyMod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("symbolSpan")) { if (channelSettingsKeys.contains("symbolSpan")) {
settings.m_symbolSpan = response.getRttyModSettings()->getSymbolSpan(); 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")) { if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getRttyModSettings()->getRgbColor(); settings.m_rgbColor = response.getRttyModSettings()->getRgbColor();
} }
@ -531,10 +572,10 @@ int RttyMod::webapiActionsPost(
if (swgRttyModActions->getTx() != 0) if (swgRttyModActions->getTx() != 0)
{ {
if (channelActionsKeys.contains("payload") if (channelActionsKeys.contains("payload")
&& (swgRttyModActions->getPayload()->getData())) && (swgRttyModActions->getPayload()->getText()))
{ {
MsgTXPacketData *msg = MsgTXPacketData::create( MsgTXText *msg = MsgTXText::create(
*swgRttyModActions->getPayload()->getData() *swgRttyModActions->getPayload()->getText()
); );
m_basebandSource->getInputMessageQueue()->push(msg); m_basebandSource->getInputMessageQueue()->push(msg);
} }
@ -548,19 +589,19 @@ int RttyMod::webapiActionsPost(
} }
else else
{ {
errorMessage = "Packet must contain tx action"; errorMessage = "Must contain tx action";
return 400; return 400;
} }
} }
else else
{ {
errorMessage = "Unknown action"; errorMessage = "Unknown RTTYMod action";
return 400; return 400;
} }
} }
else else
{ {
errorMessage = "Missing RttyModActions in query"; errorMessage = "Missing RTTYModActions in query";
return 400; return 400;
} }
return 0; return 0;
@ -577,18 +618,26 @@ void RttyMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respo
response.getRttyModSettings()->setRepeat(settings.m_repeat ? 1 : 0); response.getRttyModSettings()->setRepeat(settings.m_repeat ? 1 : 0);
response.getRttyModSettings()->setRepeatCount(settings.m_repeatCount); response.getRttyModSettings()->setRepeatCount(settings.m_repeatCount);
response.getRttyModSettings()->setLpfTaps(settings.m_lpfTaps); response.getRttyModSettings()->setLpfTaps(settings.m_lpfTaps);
response.getRttyModSettings()->setBbNoise(settings.m_bbNoise ? 1 : 0);
response.getRttyModSettings()->setRfNoise(settings.m_rfNoise ? 1 : 0); response.getRttyModSettings()->setRfNoise(settings.m_rfNoise ? 1 : 0);
if (response.getRttyModSettings()->getData()) { if (response.getRttyModSettings()->getText()) {
*response.getRttyModSettings()->getData() = settings.m_text; *response.getRttyModSettings()->getText() = settings.m_text;
} else { } 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()->setPulseShaping(settings.m_pulseShaping ? 1 : 0);
response.getRttyModSettings()->setBeta(settings.m_beta); response.getRttyModSettings()->setBeta(settings.m_beta);
response.getRttyModSettings()->setSymbolSpan(settings.m_symbolSpan); 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()->setUdpEnabled(settings.m_udpEnabled);
response.getRttyModSettings()->setUdpAddress(new QString(settings.m_udpAddress)); response.getRttyModSettings()->setUdpAddress(new QString(settings.m_udpAddress));
response.getRttyModSettings()->setUdpPort(settings.m_udpPort); response.getRttyModSettings()->setUdpPort(settings.m_udpPort);
@ -741,14 +790,11 @@ void RttyMod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("lpfTaps")) { if (channelSettingsKeys.contains("lpfTaps")) {
swgRttyModSettings->setLpfTaps(settings.m_lpfTaps); swgRttyModSettings->setLpfTaps(settings.m_lpfTaps);
} }
if (channelSettingsKeys.contains("bbNoise")) {
swgRttyModSettings->setBbNoise(settings.m_bbNoise ? 1 : 0);
}
if (channelSettingsKeys.contains("rfNoise")) { if (channelSettingsKeys.contains("rfNoise")) {
swgRttyModSettings->setRfNoise(settings.m_rfNoise ? 1 : 0); swgRttyModSettings->setRfNoise(settings.m_rfNoise ? 1 : 0);
} }
if (channelSettingsKeys.contains("text")) { if (channelSettingsKeys.contains("text")) {
swgRttyModSettings->setData(new QString(settings.m_text)); swgRttyModSettings->setText(new QString(settings.m_text));
} }
if (channelSettingsKeys.contains("beta")) { if (channelSettingsKeys.contains("beta")) {
swgRttyModSettings->setBeta(settings.m_beta); swgRttyModSettings->setBeta(settings.m_beta);
@ -756,6 +802,24 @@ void RttyMod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("symbolSpan")) { if (channelSettingsKeys.contains("symbolSpan")) {
swgRttyModSettings->setSymbolSpan(settings.m_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) { if (channelSettingsKeys.contains("rgbColor") || force) {
swgRttyModSettings->setRgbColor(settings.m_rgbColor); 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)) 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(); qCritical() << "RttyMod::openUDP: Failed to bind to port " << settings.m_udpAddress << ":" << settings.m_udpPort << ". Error: " << m_udpSocket->error();
else 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); connect(m_udpSocket, &QUdpSocket::readyRead, this, &RttyMod::udpRx);
} }
@ -857,7 +921,7 @@ void RttyMod::udpRx()
while (m_udpSocket->hasPendingDatagrams()) while (m_udpSocket->hasPendingDatagrams())
{ {
QNetworkDatagram datagram = m_udpSocket->receiveDatagram(); QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
MsgTXPacketBytes *msg = MsgTXPacketBytes::create(datagram.data()); MsgTXText *msg = MsgTXText::create(QString(datagram.data()));
m_basebandSource->getInputMessageQueue()->push(msg); m_basebandSource->getInputMessageQueue()->push(msg);
} }
} }

View File

@ -102,40 +102,22 @@ public:
{ } { }
}; };
class MsgTXPacketBytes : public Message { class MsgTXText : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
static MsgTXPacketBytes* create(QByteArray data) { static MsgTXText* create(QString text)
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)
{ {
return new MsgTXPacketData(data); return new MsgTXText(text);
} }
QString m_data; QString m_text;
private: private:
MsgTXPacketData(QString data) : MsgTXText(QString text) :
Message(), 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)) else if (RttyMod::MsgTx::match(cmd))
{ {
qDebug() << "RttyModBaseband::handleMessage: MsgTx"; qDebug() << "RttyModBaseband::handleMessage: MsgTx";
m_source.addTXPacket(m_settings.m_text); m_source.addTXText(m_settings.m_text);
return true; return true;
} }
else if (RttyMod::MsgTXPacketBytes::match(cmd)) else if (RttyMod::MsgTXText::match(cmd))
{ {
RttyMod::MsgTXPacketBytes& tx = (RttyMod::MsgTXPacketBytes&) cmd; RttyMod::MsgTXText& tx = (RttyMod::MsgTXText&) cmd;
m_source.addTXPacket(tx.m_data); m_source.addTXText(tx.m_text);
return true;
}
else if (RttyMod::MsgTXPacketData::match(cmd))
{
RttyMod::MsgTXPacketData& tx = (RttyMod::MsgTXPacketData&) cmd;
m_source.addTXPacket(tx.m_data);
return true; return true;
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -29,10 +29,10 @@
RttyModSource::RttyModSource() : RttyModSource::RttyModSource() :
m_channelSampleRate(48000), m_channelSampleRate(48000),
m_channelFrequencyOffset(0), m_channelFrequencyOffset(0),
m_spectrumRate(8000), m_spectrumRate(2000),
m_audioPhase(0.0f),
m_fmPhase(0.0), m_fmPhase(0.0),
m_spectrumSink(nullptr), m_spectrumSink(nullptr),
m_specSampleBufferIndex(0),
m_magsq(0.0), m_magsq(0.0),
m_levelCalcCount(0), m_levelCalcCount(0),
m_peakLevel(0.0f), m_peakLevel(0.0f),
@ -48,6 +48,7 @@ RttyModSource::RttyModSource() :
m_demodBuffer.resize(1<<12); m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0; m_demodBufferFill = 0;
m_specSampleBuffer.resize(m_specSampleBufferSize);
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorConsumed = false; m_interpolatorConsumed = false;
m_interpolatorDistance = (Real)m_channelSampleRate / (Real)m_spectrumRate; 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); sample.m_imag = (FixReal) (ci.imag() * SDR_TX_SCALEF);
} }
void RttyModSource::sampleToSpectrum(Real sample) void RttyModSource::sampleToSpectrum(Complex sample)
{ {
if (m_spectrumSink) if (m_spectrumSink)
{ {
Complex out; Complex out;
Complex in; if (m_interpolator.decimate(&m_interpolatorDistanceRemain, sample, &out))
in.real(sample);
in.imag(0.0f);
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, in, &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; 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 // Encode a character at a time, so we get a TxReport after each character
QString s = m_textToTransmit.left(1); QString s = m_textToTransmit.left(1);
m_textToTransmit = m_textToTransmit.mid(1); m_textToTransmit = m_textToTransmit.mid(1);
encodePacket(s); encodeText(s);
} }
else else
{ {
// Transmit "diddle" // Transmit "diddle"
encodePacket(">"); encodeText(">");
} }
initTX(); initTX();
} }
@ -148,30 +150,20 @@ void RttyModSource::modulateSample()
m_sampleIdx = 0; m_sampleIdx = 0;
} }
if (!m_settings.m_bbNoise) // FSK
if (m_settings.m_pulseShaping)
{ {
// FSK if (m_sampleIdx == 1) {
if (m_settings.m_pulseShaping) audioMod = m_pulseShape.filter(m_bit ? 1.0f : -1.0f);
{ } else {
if (m_sampleIdx == 1) { audioMod = m_pulseShape.filter(0.0f);
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;
} }
} }
else 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 // FM
m_fmPhase += m_phaseSensitivity * audioMod * (m_settings.m_spaceHigh ? -1.0f : 1.0f); m_fmPhase += m_phaseSensitivity * audioMod * (m_settings.m_spaceHigh ? -1.0f : 1.0f);
// Keep phase in range -pi,pi // Keep phase in range -pi,pi
@ -196,6 +188,9 @@ void RttyModSource::modulateSample()
// Apply low pass filter to limit RF BW // Apply low pass filter to limit RF BW
m_modSample = m_lowpass.filter(m_modSample); m_modSample = m_lowpass.filter(m_modSample);
// Display in spectrum analyser
sampleToSpectrum(m_modSample);
Real s = std::real(m_modSample); Real s = std::real(m_modSample);
calculateLevel(s); calculateLevel(s);
@ -245,7 +240,12 @@ void RttyModSource::calculateLevel(Real& sample)
void RttyModSource::applySettings(const RttyModSettings& settings, bool force) 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) 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; 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_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 // 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_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); 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_channelFrequencyOffset = channelFrequencyOffset;
m_samplesPerSymbol = m_channelSampleRate / m_settings.m_baud; m_samplesPerSymbol = m_channelSampleRate / m_settings.m_baud;
qDebug() << "m_samplesPerSymbol: " << 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 // 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; 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; m_bit = 0;
} }
void RttyModSource::addTXPacket(QString data) void RttyModSource::addTXText(QString text)
{ {
int count = m_settings.m_repeat ? m_settings.m_repeatCount : 1; int count = m_settings.m_repeat ? m_settings.m_repeatCount : 1;
for (int i = 0; i < count; i++) { 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) void RttyModSource::encodeText(const QString& text)
{
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)
{ {
// RTTY encoding // RTTY encoding
m_byteIdx = 0; m_byteIdx = 0;

View File

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

View File

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

View File

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