mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 10:05:46 -05:00
Merge branch 'rttymod' of https://github.com/srcejon/sdrangel into rttymod
This commit is contained in:
commit
2f5f2672d0
1
.gitignore
vendored
1
.gitignore
vendored
@ -43,3 +43,4 @@ obj-x86_64-linux-gnu/*
|
|||||||
|
|
||||||
/rescuesdriq/vendor/
|
/rescuesdriq/vendor/
|
||||||
/rescuesdriq/Godeps/
|
/rescuesdriq/Godeps/
|
||||||
|
/.vs
|
||||||
|
14
CHANGELOG
14
CHANGELOG
@ -1,3 +1,17 @@
|
|||||||
|
sdrangel (7.15.4-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Fix Mac compilation. PR #1786
|
||||||
|
* Add support for plugin presets. PR #1789
|
||||||
|
* Map feature updates. PR #1778
|
||||||
|
* Fix RTLSDR E4000 gain and bandwidth settings. Add tuner type to GUI. PR #1790
|
||||||
|
* Add support for RTLSDRBlog V4 with HF upsampler. PR #1790
|
||||||
|
* Update RTLSDR driver to include RTLSDRBlog V4 support. PR #1790
|
||||||
|
* Add rotator az/el and offset to table. PR #1791
|
||||||
|
* Optmize redrawing of charts in Star Tracker. PR #1791
|
||||||
|
* Initialise PhaseDiscriminators state, to avoid outputting huge values. Fix #1794. PR #1794
|
||||||
|
|
||||||
|
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sat, 02 Sep 2023 19:12:12 +0200
|
||||||
|
|
||||||
sdrangel (7.15.3-1) unstable; urgency=medium
|
sdrangel (7.15.3-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Rotator Controller: Add additional gamepad calibration and functionality. PR #1761
|
* Rotator Controller: Add additional gamepad calibration and functionality. PR #1761
|
||||||
|
@ -16,7 +16,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||||||
# configure version
|
# configure version
|
||||||
set(sdrangel_VERSION_MAJOR "7")
|
set(sdrangel_VERSION_MAJOR "7")
|
||||||
set(sdrangel_VERSION_MINOR "15")
|
set(sdrangel_VERSION_MINOR "15")
|
||||||
set(sdrangel_VERSION_PATCH "3")
|
set(sdrangel_VERSION_PATCH "4")
|
||||||
set(sdrangel_VERSION_SUFFIX "")
|
set(sdrangel_VERSION_SUFFIX "")
|
||||||
|
|
||||||
# SDRAngel cmake options
|
# SDRAngel cmake options
|
||||||
|
@ -1,56 +1,94 @@
|
|||||||
{
|
{
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"configurePresets": [
|
"configurePresets": [
|
||||||
{
|
{
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"binaryDir": "build-default",
|
"binaryDir": "build-default",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"DEBUG_OUTPUT": "ON",
|
"DEBUG_OUTPUT": "ON",
|
||||||
"AIRSPYHF_DIR": "/opt/install/libairspyhf",
|
"AIRSPYHF_DIR": "/opt/install/libairspyhf",
|
||||||
"AIRSPY_DIR": "/opt/install/libairspy",
|
"AIRSPY_DIR": "/opt/install/libairspy",
|
||||||
"APT_DIR": "/opt/install/aptdec",
|
"APT_DIR": "/opt/install/aptdec",
|
||||||
"BLADERF_DIR": "/opt/install/libbladeRF",
|
"BLADERF_DIR": "/opt/install/libbladeRF",
|
||||||
"CM256CC_DIR": "/opt/install/cm256cc",
|
"CM256CC_DIR": "/opt/install/cm256cc",
|
||||||
"CODEC2_DIR": "/opt/install/codec2",
|
"CODEC2_DIR": "/opt/install/codec2",
|
||||||
"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",
|
"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",
|
||||||
"MBE_DIR": "/opt/install/mbelib",
|
"MBE_DIR": "/opt/install/mbelib",
|
||||||
"MIRISDR_DIR": "/opt/install/libmirisdr",
|
"MIRISDR_DIR": "/opt/install/libmirisdr",
|
||||||
"PERSEUS_DIR": "/opt/install/libperseus",
|
"PERSEUS_DIR": "/opt/install/libperseus",
|
||||||
"RTLSDR_DIR": "/opt/install/librtlsdr",
|
"RTLSDR_DIR": "/opt/install/librtlsdr",
|
||||||
"SERIALDV_DIR": "/opt/install/serialdv",
|
"SERIALDV_DIR": "/opt/install/serialdv",
|
||||||
"SGP4_DIR": "/opt/install/sgp4",
|
"SGP4_DIR": "/opt/install/sgp4",
|
||||||
"SOAPYSDR_DIR": "/opt/install/SoapySDR",
|
"SOAPYSDR_DIR": "/opt/install/SoapySDR",
|
||||||
"UHD_DIR": "/opt/install/uhd",
|
"UHD_DIR": "/opt/install/uhd",
|
||||||
"XTRX_DIR": "/opt/install/xtrx-images",
|
"XTRX_DIR": "/opt/install/xtrx-images",
|
||||||
"CMAKE_INSTALL_PREFIX": "/opt/install/sdrangel"
|
"CMAKE_INSTALL_PREFIX": "/opt/install/sdrangel"
|
||||||
},
|
|
||||||
"warnings": {
|
|
||||||
"dev": false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
"warnings": {
|
||||||
"name": "default-qt6",
|
"dev": false
|
||||||
"inherits": "default",
|
},
|
||||||
"binaryDir": "build-qt6",
|
"vendor": {
|
||||||
"cacheVariables": {
|
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||||
"ENABLE_QT6": "ON"
|
"hostOS": [ "Linux" ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Don't inherit from "default", as we don't want UHD_DIR etc set
|
||||||
|
"name": "default-windows",
|
||||||
|
"binaryDir": "c:/users/jon/source/repos/sdrangel/build",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
|
"DEBUG_OUTPUT": "ON",
|
||||||
|
"RX_SAMPLE_24BIT": "ON",
|
||||||
|
"DARCH_OPT": "SSE4_1",
|
||||||
|
"HIDE_CONSOLE": "OFF",
|
||||||
|
"ENABLE_AIRSPY": "ON",
|
||||||
|
"ENABLE_BLADERF": "OFF",
|
||||||
|
"ENABLE_HACKRF": "OFF",
|
||||||
|
"ENABLE_IIO": "OFF",
|
||||||
|
"ENABLE_MIRISDR": "OFF",
|
||||||
|
"ENABLE_PERSEUS": "OFF",
|
||||||
|
"ENABLE_XTRX": "OFF",
|
||||||
|
"BUILD_SERVER": "OFF",
|
||||||
|
"CMAKE_PREFIX_PATH": "C:/Qt/5.15.2/msvc2019_64;C:/Applications/boost_1_81_0"
|
||||||
|
},
|
||||||
|
"warnings": {
|
||||||
|
"dev": false
|
||||||
|
},
|
||||||
|
"vendor": {
|
||||||
|
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||||
|
"hostOS": [ "Windows" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "default-qt6",
|
||||||
|
"inherits": "default",
|
||||||
|
"binaryDir": "build-qt6",
|
||||||
|
"cacheVariables": {
|
||||||
|
"ENABLE_QT6": "ON"
|
||||||
|
}
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"buildPresets": [
|
"buildPresets": [
|
||||||
{
|
{
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"configurePreset": "default"
|
"configurePreset": "default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "default-qt6",
|
"name": "default-windows",
|
||||||
"configurePreset": "default-qt6"
|
"configurePreset": "default-windows"
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
"name": "default-qt6",
|
||||||
|
"configurePreset": "default-qt6"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
14
debian/changelog
vendored
14
debian/changelog
vendored
@ -1,3 +1,17 @@
|
|||||||
|
sdrangel (7.15.4-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Fix Mac compilation. PR #1786
|
||||||
|
* Add support for plugin presets. PR #1789
|
||||||
|
* Map feature updates. PR #1778
|
||||||
|
* Fix RTLSDR E4000 gain and bandwidth settings. Add tuner type to GUI. PR #1790
|
||||||
|
* Add support for RTLSDRBlog V4 with HF upsampler. PR #1790
|
||||||
|
* Update RTLSDR driver to include RTLSDRBlog V4 support. PR #1790
|
||||||
|
* Add rotator az/el and offset to table. PR #1791
|
||||||
|
* Optmize redrawing of charts in Star Tracker. PR #1791
|
||||||
|
* Initialise PhaseDiscriminators state, to avoid outputting huge values. Fix #1794. PR #1794
|
||||||
|
|
||||||
|
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sat, 02 Sep 2023 19:12:12 +0200
|
||||||
|
|
||||||
sdrangel (7.15.3-1) unstable; urgency=medium
|
sdrangel (7.15.3-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Rotator Controller: Add additional gamepad calibration and functionality. PR #1761
|
* Rotator Controller: Add additional gamepad calibration and functionality. PR #1761
|
||||||
|
@ -227,6 +227,8 @@ void DSCDemodSink::receiveBit(bool bit)
|
|||||||
m_dscDecoder.init(m_phasingPatterns[i].m_offset);
|
m_dscDecoder.init(m_phasingPatterns[i].m_offset);
|
||||||
m_gotSOP = true;
|
m_gotSOP = true;
|
||||||
m_bitCount = 0;
|
m_bitCount = 0;
|
||||||
|
m_rssiMagSqSum = 0.0;
|
||||||
|
m_rssiMagSqCount = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,6 +329,8 @@ void NavtexDemodSink::receiveBit(bool bit)
|
|||||||
m_gotSOP = true;
|
m_gotSOP = true;
|
||||||
m_bitCount = 0;
|
m_bitCount = 0;
|
||||||
m_sitorBDecoder.init();
|
m_sitorBDecoder.init();
|
||||||
|
m_rssiMagSqSum = 0.0;
|
||||||
|
m_rssiMagSqCount = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -79,7 +79,12 @@ Specifies whether bits are transmitted least-significant-bit first (LSB) or most
|
|||||||
|
|
||||||
<h3>14: Mark/Space Frequency</h3>
|
<h3>14: Mark/Space Frequency</h3>
|
||||||
|
|
||||||
When unchecked, the mark frequency is the higher frequency, when checked the space frequency is higher.
|
When unchecked, the mark frequency is the higher RF frequency, when checked the space frequency is higher.
|
||||||
|
|
||||||
|
This should be unchecked when transmitter is using LSB AFSK and checked for USB AFSK and DWD
|
||||||
|
[1](https://www.dwd.de/EN/specialusers/shipping/broadcast_en/brodcast_rtty_1_052014.pdf?__blob=publicationFile&v=1)
|
||||||
|
[2](https://www.dwd.de/EN/specialusers/shipping/broadcast_en/broadcast_rtty_2_052014.pdf?__blob=publicationFile&v=1)
|
||||||
|
shipping weather broadcasts.
|
||||||
|
|
||||||
<h3>15: Suppress CR LF</h3>
|
<h3>15: Suppress CR LF</h3>
|
||||||
|
|
||||||
@ -101,3 +106,4 @@ Click to specify the name of the .txt file which received characters are logged
|
|||||||
|
|
||||||
The received text area shows characters as they are received.
|
The received text area shows characters as they are received.
|
||||||
|
|
||||||
|
Holding the cursor over an acronym may show a tooltip with the decoded acronym.
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
#include "util/db.h"
|
#include "util/db.h"
|
||||||
|
#include "util/rtty.h"
|
||||||
#include "gui/basicchannelsettingsdialog.h"
|
#include "gui/basicchannelsettingsdialog.h"
|
||||||
#include "gui/devicestreamselectiondialog.h"
|
#include "gui/devicestreamselectiondialog.h"
|
||||||
#include "dsp/dspengine.h"
|
#include "dsp/dspengine.h"
|
||||||
@ -482,6 +483,8 @@ RttyDemodGUI::RttyDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
|||||||
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
|
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
|
||||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
|
||||||
|
ui->text->addAcronyms(Rtty::m_acronyms);
|
||||||
|
|
||||||
ui->scopeContainer->setVisible(false);
|
ui->scopeContainer->setVisible(false);
|
||||||
|
|
||||||
// Hide developer only settings
|
// Hide developer only settings
|
||||||
|
@ -916,7 +916,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="text">
|
<widget class="AcronymView" name="text">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Received text</string>
|
<string>Received text</string>
|
||||||
</property>
|
</property>
|
||||||
@ -1293,6 +1293,12 @@
|
|||||||
<header>gui/glscopegui.h</header>
|
<header>gui/glscopegui.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>AcronymView</class>
|
||||||
|
<extends>QTextEdit</extends>
|
||||||
|
<header>gui/acronymview.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>deltaFrequency</tabstop>
|
<tabstop>deltaFrequency</tabstop>
|
||||||
|
@ -154,8 +154,8 @@ void RttyDemodSink::processOneSample(Complex &ci)
|
|||||||
m_expIdx = (m_expIdx + 1) % m_expLength;
|
m_expIdx = (m_expIdx + 1) % m_expLength;
|
||||||
//Complex exp = m_exp[m_sampleIdx];
|
//Complex exp = m_exp[m_sampleIdx];
|
||||||
//qDebug() << "IQ " << real(ci) << imag(ci);
|
//qDebug() << "IQ " << real(ci) << imag(ci);
|
||||||
Complex corr1 = ci * exp;
|
Complex corr1 = ci * std::conj(exp); // Conj is high/mark freq (as for matched filter, we need to time reverse and take conjugate)
|
||||||
Complex corr2 = ci * std::conj(exp);
|
Complex corr2 = ci * exp; // Low/space freq
|
||||||
|
|
||||||
// Filter
|
// Filter
|
||||||
Real abs1, abs2;
|
Real abs1, abs2;
|
||||||
@ -238,6 +238,8 @@ void RttyDemodSink::processOneSample(Complex &ci)
|
|||||||
m_clockCount = 0;
|
m_clockCount = 0;
|
||||||
m_clock = false;
|
m_clock = false;
|
||||||
m_cycleCount = 0;
|
m_cycleCount = 0;
|
||||||
|
m_rssiMagSqSum = 0.0;
|
||||||
|
m_rssiMagSqCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -349,7 +349,7 @@ void PacketModSource::applySettings(const PacketModSettings& settings, bool forc
|
|||||||
<< " symbolSpan: " << settings.m_symbolSpan
|
<< " symbolSpan: " << settings.m_symbolSpan
|
||||||
<< " channelSampleRate:" << m_channelSampleRate
|
<< " channelSampleRate:" << m_channelSampleRate
|
||||||
<< " baud:" << settings.m_baud;
|
<< " baud:" << settings.m_baud;
|
||||||
m_pulseShape.create(settings.m_beta, m_settings.m_symbolSpan, m_channelSampleRate/settings.m_baud);
|
m_pulseShape.create(settings.m_beta, settings.m_symbolSpan, m_channelSampleRate/settings.m_baud);
|
||||||
}
|
}
|
||||||
if ((settings.m_polynomial != m_settings.m_polynomial) || force)
|
if ((settings.m_polynomial != m_settings.m_polynomial) || force)
|
||||||
m_scrambler.setPolynomial(settings.m_polynomial);
|
m_scrambler.setPolynomial(settings.m_polynomial);
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
<h2>Introduction</h2>
|
<h2>Introduction</h2>
|
||||||
|
|
||||||
This plugin can be used to transmit RTTY encoded text.
|
This plugin can be used to modulate RTTY (Radioteletype) encoded text.
|
||||||
|
RTTY uses BFSK (Binary Frequency Shift Keying), where transmission of data alternates between two frequencies,
|
||||||
|
the mark frequency and the space frequency. The RTTY Modulator should be centered in between these frequencies.
|
||||||
|
The baud rate, frequency shift (difference between mark and space frequencies), filter bandwidth and baudot character set are configurable.
|
||||||
|
|
||||||
<h2>Interface</h2>
|
<h2>Interface</h2>
|
||||||
|
|
||||||
@ -64,7 +67,14 @@ UDP port number to receive text to be transmitted on.
|
|||||||
|
|
||||||
<h3>13: Baudot Character Set</h3>
|
<h3>13: Baudot Character Set</h3>
|
||||||
|
|
||||||
Specifies the Baudot character set used to encode the text to transmit.
|
Specifies the Baudot character set used to encode the text to transmit. The following character sets are supported:
|
||||||
|
|
||||||
|
* ITA 2
|
||||||
|
* UK
|
||||||
|
* European
|
||||||
|
* US
|
||||||
|
* Russian
|
||||||
|
* Murray
|
||||||
|
|
||||||
<h3>14: Bit Ordering</h3>
|
<h3>14: Bit Ordering</h3>
|
||||||
|
|
||||||
@ -90,11 +100,26 @@ Press to clear the transmitted text.
|
|||||||
|
|
||||||
Enter text to transmit. Pressing return will transmit the text and clear this field. Press the arrow to display and select a list of pre-defined text or previously transmitted text to enter in to the field.
|
Enter text to transmit. Pressing return will transmit the text and clear this field. Press the arrow to display and select a list of pre-defined text or previously transmitted text to enter in to the field.
|
||||||
|
|
||||||
|
The list of pre-defined text can be customised via the Transmit Settings dialog (20).
|
||||||
|
|
||||||
<h3>20: TX</h3>
|
<h3>20: TX</h3>
|
||||||
|
|
||||||
Press to transmits the current text. The text field will not be cleared.
|
Press to transmit the current text. The text field will not be cleared.
|
||||||
|
|
||||||
Right click to open a dialog to adjust additional transmitter settings.
|
Right click to open a dialog to adjust additional Transmit Settings, including the list of pre-defined text.
|
||||||
|
|
||||||
|
Predefined text supports the following variable substitutions:
|
||||||
|
|
||||||
|
* ${callsign} - Gets replaced with the station name from Preferences > My Position
|
||||||
|
* ${location} = Gets replaced with the Maidenhead locator for the position specified under Preferences > My Position
|
||||||
|
|
||||||
|
The substitutions are applied when the Transmit Settings dialog is closed.
|
||||||
|
|
||||||
|
<h3>21: Transmitted Text</h3>
|
||||||
|
|
||||||
|
The trasnmitted text area shows characters as they are transmitted.
|
||||||
|
|
||||||
|
Holding the cursor over an acronym may show a tooltip with the decoded acronym.
|
||||||
|
|
||||||
<h2>API</h2>
|
<h2>API</h2>
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
#include "util/db.h"
|
#include "util/db.h"
|
||||||
|
#include "util/rtty.h"
|
||||||
#include "util/maidenhead.h"
|
#include "util/maidenhead.h"
|
||||||
#include "gui/glspectrum.h"
|
#include "gui/glspectrum.h"
|
||||||
#include "gui/crightclickenabler.h"
|
#include "gui/crightclickenabler.h"
|
||||||
@ -476,6 +477,8 @@ RttyModGUI::RttyModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
|
|||||||
m_settings.setChannelMarker(&m_channelMarker);
|
m_settings.setChannelMarker(&m_channelMarker);
|
||||||
m_settings.setRollupState(&m_rollupState);
|
m_settings.setRollupState(&m_rollupState);
|
||||||
|
|
||||||
|
ui->transmittedText->addAcronyms(Rtty::m_acronyms);
|
||||||
|
|
||||||
ui->spectrumContainer->setVisible(false);
|
ui->spectrumContainer->setVisible(false);
|
||||||
|
|
||||||
displaySettings();
|
displaySettings();
|
||||||
|
@ -751,7 +751,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_2">
|
<spacer name="horizontalSpacerSettings">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
@ -854,11 +854,7 @@
|
|||||||
<number>3</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="transmittedText">
|
<widget class="AcronymView" name="transmittedText"/>
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@ -960,6 +956,12 @@
|
|||||||
<header>gui/levelmeter.h</header>
|
<header>gui/levelmeter.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>AcronymView</class>
|
||||||
|
<extends>QTextEdit</extends>
|
||||||
|
<header>gui/acronymview.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>deltaFrequency</tabstop>
|
<tabstop>deltaFrequency</tabstop>
|
||||||
|
@ -57,7 +57,7 @@ void RttyModSettings::resetToDefaults()
|
|||||||
"UR 599 QTH IS ${location}",
|
"UR 599 QTH IS ${location}",
|
||||||
"TU DE ${callsign} CQ"
|
"TU DE ${callsign} CQ"
|
||||||
});
|
});
|
||||||
m_rgbColor = QColor(0, 105, 2).rgb();
|
m_rgbColor = QColor(180, 205, 130).rgb();
|
||||||
m_title = "RTTY Modulator";
|
m_title = "RTTY Modulator";
|
||||||
m_streamIndex = 0;
|
m_streamIndex = 0;
|
||||||
m_useReverseAPI = false;
|
m_useReverseAPI = false;
|
||||||
@ -66,7 +66,7 @@ void RttyModSettings::resetToDefaults()
|
|||||||
m_reverseAPIDeviceIndex = 0;
|
m_reverseAPIDeviceIndex = 0;
|
||||||
m_reverseAPIChannelIndex = 0;
|
m_reverseAPIChannelIndex = 0;
|
||||||
m_pulseShaping = false;
|
m_pulseShaping = false;
|
||||||
m_beta = 0.5f;
|
m_beta = 1.0f;
|
||||||
m_symbolSpan = 6;
|
m_symbolSpan = 6;
|
||||||
m_udpEnabled = false;
|
m_udpEnabled = false;
|
||||||
m_udpAddress = "127.0.0.1";
|
m_udpAddress = "127.0.0.1";
|
||||||
@ -200,7 +200,7 @@ bool RttyModSettings::deserialize(const QByteArray& data)
|
|||||||
d.readU32(39, &utmp, 0);
|
d.readU32(39, &utmp, 0);
|
||||||
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
d.readBool(46, &m_pulseShaping, false);
|
d.readBool(46, &m_pulseShaping, false);
|
||||||
d.readReal(47, &m_beta, 0.5f);
|
d.readReal(47, &m_beta, 1.0f);
|
||||||
d.readS32(48, &m_symbolSpan, 6);
|
d.readS32(48, &m_symbolSpan, 6);
|
||||||
d.readBool(51, &m_udpEnabled);
|
d.readBool(51, &m_udpEnabled);
|
||||||
d.readString(52, &m_udpAddress, "127.0.0.1");
|
d.readString(52, &m_udpAddress, "127.0.0.1");
|
||||||
|
@ -43,7 +43,7 @@ RttyModSource::RttyModSource() :
|
|||||||
{
|
{
|
||||||
m_bits.append(0);
|
m_bits.append(0);
|
||||||
m_lowpass.create(301, m_channelSampleRate, 400.0 / 2.0);
|
m_lowpass.create(301, m_channelSampleRate, 400.0 / 2.0);
|
||||||
m_pulseShape.create(0.5, 6, m_channelSampleRate/45.45);
|
m_pulseShape.create(0.5, 6, m_channelSampleRate / 45.45, true);
|
||||||
|
|
||||||
m_demodBuffer.resize(1<<12);
|
m_demodBuffer.resize(1<<12);
|
||||||
m_demodBufferFill = 0;
|
m_demodBufferFill = 0;
|
||||||
@ -121,7 +121,7 @@ void RttyModSource::sampleToSpectrum(Complex sample)
|
|||||||
|
|
||||||
void RttyModSource::modulateSample()
|
void RttyModSource::modulateSample()
|
||||||
{
|
{
|
||||||
Real audioMod;
|
Real mod;
|
||||||
|
|
||||||
if (m_sampleIdx == 0)
|
if (m_sampleIdx == 0)
|
||||||
{
|
{
|
||||||
@ -154,18 +154,18 @@ void RttyModSource::modulateSample()
|
|||||||
if (m_settings.m_pulseShaping)
|
if (m_settings.m_pulseShaping)
|
||||||
{
|
{
|
||||||
if (m_sampleIdx == 1) {
|
if (m_sampleIdx == 1) {
|
||||||
audioMod = m_pulseShape.filter(m_bit ? 1.0f : -1.0f);
|
mod = m_pulseShape.filter(m_bit ? 1.0f : -1.0f);
|
||||||
} else {
|
} else {
|
||||||
audioMod = m_pulseShape.filter(0.0f);
|
mod = m_pulseShape.filter(0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
audioMod = m_bit ? 1.0f : -1.0f;
|
mod = m_bit ? 1.0f : -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
m_fmPhase += m_phaseSensitivity * audioMod * (m_settings.m_spaceHigh ? -1.0f : 1.0f);
|
m_fmPhase += m_phaseSensitivity * mod * (m_settings.m_spaceHigh ? -1.0f : 1.0f);
|
||||||
// Keep phase in range -pi,pi
|
// Keep phase in range -pi,pi
|
||||||
if (m_fmPhase > M_PI) {
|
if (m_fmPhase > M_PI) {
|
||||||
m_fmPhase -= 2.0f * M_PI;
|
m_fmPhase -= 2.0f * M_PI;
|
||||||
@ -194,7 +194,8 @@ void RttyModSource::modulateSample()
|
|||||||
Real s = std::real(m_modSample);
|
Real s = std::real(m_modSample);
|
||||||
calculateLevel(s);
|
calculateLevel(s);
|
||||||
|
|
||||||
m_demodBuffer[m_demodBufferFill] = audioMod * std::numeric_limits<int16_t>::max();
|
// Send to demod analyser
|
||||||
|
m_demodBuffer[m_demodBufferFill] = mod * std::numeric_limits<int16_t>::max();
|
||||||
++m_demodBufferFill;
|
++m_demodBufferFill;
|
||||||
|
|
||||||
if (m_demodBufferFill >= m_demodBuffer.size())
|
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||||
@ -258,7 +259,7 @@ void RttyModSource::applySettings(const RttyModSettings& settings, bool force)
|
|||||||
<< " symbolSpan: " << settings.m_symbolSpan
|
<< " symbolSpan: " << settings.m_symbolSpan
|
||||||
<< " channelSampleRate:" << m_channelSampleRate
|
<< " channelSampleRate:" << m_channelSampleRate
|
||||||
<< " baud:" << settings.m_baud;
|
<< " baud:" << settings.m_baud;
|
||||||
m_pulseShape.create(settings.m_beta, m_settings.m_symbolSpan, m_channelSampleRate/settings.m_baud);
|
m_pulseShape.create(settings.m_beta, settings.m_symbolSpan, m_channelSampleRate/settings.m_baud, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_characterSet != m_settings.m_characterSet) || force) {
|
if ((settings.m_characterSet != m_settings.m_characterSet) || force) {
|
||||||
@ -302,7 +303,7 @@ void RttyModSource::applyChannelSettings(int channelSampleRate, int channelFrequ
|
|||||||
<< " symbolSpan: " << m_settings.m_symbolSpan
|
<< " symbolSpan: " << m_settings.m_symbolSpan
|
||||||
<< " channelSampleRate:" << m_channelSampleRate
|
<< " channelSampleRate:" << m_channelSampleRate
|
||||||
<< " baud:" << m_settings.m_baud;
|
<< " baud:" << m_settings.m_baud;
|
||||||
m_pulseShape.create(m_settings.m_beta, m_settings.m_symbolSpan, channelSampleRate/m_settings.m_baud);
|
m_pulseShape.create(m_settings.m_beta, m_settings.m_symbolSpan, channelSampleRate/m_settings.m_baud, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_channelSampleRate != channelSampleRate) || force)
|
if ((m_channelSampleRate != channelSampleRate) || force)
|
||||||
|
@ -38,6 +38,7 @@ const QStringList DemodAnalyzerSettings::m_channelTypes = {
|
|||||||
QStringLiteral("PacketDemod"),
|
QStringLiteral("PacketDemod"),
|
||||||
QStringLiteral("PacketMod"),
|
QStringLiteral("PacketMod"),
|
||||||
QStringLiteral("RadiosondeDemod"),
|
QStringLiteral("RadiosondeDemod"),
|
||||||
|
QStringLiteral("RTTYMod"),
|
||||||
QStringLiteral("SSBDemod"),
|
QStringLiteral("SSBDemod"),
|
||||||
QStringLiteral("SSBMod"),
|
QStringLiteral("SSBMod"),
|
||||||
QStringLiteral("WFMDemod"),
|
QStringLiteral("WFMDemod"),
|
||||||
@ -60,6 +61,7 @@ const QStringList DemodAnalyzerSettings::m_channelURIs = {
|
|||||||
QStringLiteral("sdrangel.channel.packetdemod"),
|
QStringLiteral("sdrangel.channel.packetdemod"),
|
||||||
QStringLiteral("sdrangel.channeltx.modpacket"),
|
QStringLiteral("sdrangel.channeltx.modpacket"),
|
||||||
QStringLiteral("sdrangel.channel.radiosondedemod"),
|
QStringLiteral("sdrangel.channel.radiosondedemod"),
|
||||||
|
QStringLiteral("sdrangel.channeltx.modrtty"),
|
||||||
QStringLiteral("sdrangel.channel.ssbdemod"),
|
QStringLiteral("sdrangel.channel.ssbdemod"),
|
||||||
QStringLiteral("sdrangel.channeltx.modssb"),
|
QStringLiteral("sdrangel.channeltx.modssb"),
|
||||||
QStringLiteral("sdrangel.channel.wfmdemod"),
|
QStringLiteral("sdrangel.channel.wfmdemod"),
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
const PluginDescriptor GS232ControllerPlugin::m_pluginDescriptor = {
|
const PluginDescriptor GS232ControllerPlugin::m_pluginDescriptor = {
|
||||||
GS232Controller::m_featureId,
|
GS232Controller::m_featureId,
|
||||||
QStringLiteral("Rotator Controller"),
|
QStringLiteral("Rotator Controller"),
|
||||||
QStringLiteral("7.15.3"),
|
QStringLiteral("7.15.4"),
|
||||||
QStringLiteral("(c) Jon Beniston, M7RCE"),
|
QStringLiteral("(c) Jon Beniston, M7RCE"),
|
||||||
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
const PluginDescriptor MapPlugin::m_pluginDescriptor = {
|
const PluginDescriptor MapPlugin::m_pluginDescriptor = {
|
||||||
Map::m_featureId,
|
Map::m_featureId,
|
||||||
QStringLiteral("Map"),
|
QStringLiteral("Map"),
|
||||||
QStringLiteral("7.15.3"),
|
QStringLiteral("7.15.4"),
|
||||||
QStringLiteral("(c) Jon Beniston, M7RCE"),
|
QStringLiteral("(c) Jon Beniston, M7RCE"),
|
||||||
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
const PluginDescriptor StarTrackerPlugin::m_pluginDescriptor = {
|
const PluginDescriptor StarTrackerPlugin::m_pluginDescriptor = {
|
||||||
StarTracker::m_featureId,
|
StarTracker::m_featureId,
|
||||||
QStringLiteral("Star Tracker"),
|
QStringLiteral("Star Tracker"),
|
||||||
QStringLiteral("7.14.1"),
|
QStringLiteral("7.15.4"),
|
||||||
QStringLiteral("(c) Jon Beniston, M7RCE"),
|
QStringLiteral("(c) Jon Beniston, M7RCE"),
|
||||||
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
const PluginDescriptor RTLSDRPlugin::m_pluginDescriptor = {
|
const PluginDescriptor RTLSDRPlugin::m_pluginDescriptor = {
|
||||||
QStringLiteral("RTLSDR"),
|
QStringLiteral("RTLSDR"),
|
||||||
QStringLiteral("RTL-SDR Input"),
|
QStringLiteral("RTL-SDR Input"),
|
||||||
QStringLiteral("7.8.3"),
|
QStringLiteral("7.15.4"),
|
||||||
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
|
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
|
||||||
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -259,6 +259,7 @@ set(sdrbase_SOURCES
|
|||||||
util/simpleserializer.cpp
|
util/simpleserializer.cpp
|
||||||
util/serialutil.cpp
|
util/serialutil.cpp
|
||||||
#util/spinlock.cpp
|
#util/spinlock.cpp
|
||||||
|
util/rtty.cpp
|
||||||
util/uid.cpp
|
util/uid.cpp
|
||||||
util/units.cpp
|
util/units.cpp
|
||||||
util/timeutil.cpp
|
util/timeutil.cpp
|
||||||
@ -491,6 +492,7 @@ set(sdrbase_HEADERS
|
|||||||
util/profiler.h
|
util/profiler.h
|
||||||
util/radiosonde.h
|
util/radiosonde.h
|
||||||
util/rtpsink.h
|
util/rtpsink.h
|
||||||
|
util/rtty.h
|
||||||
util/syncmessenger.h
|
util/syncmessenger.h
|
||||||
util/samplesourceserializer.h
|
util/samplesourceserializer.h
|
||||||
util/simpleserializer.h
|
util/simpleserializer.h
|
||||||
|
@ -89,18 +89,38 @@ public:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Calculate maximum output of filter, assuming upsampled bipolar input E.g. [1 0 0 -1 0 0..]
|
// Calculate maximum output of filter, assuming upsampled bipolar input E.g. [1 0 0 -1 0 0..]
|
||||||
// This doesn't necessarily include the centre tap, so we try each offset
|
// This doesn't necessarily include the centre tap, as ISI there should be zero,
|
||||||
double maxGain = 0.0;
|
// it's often at the midpoint between two symbols. However, depending on beta,
|
||||||
for (i = 0; i < samplesPerSymbol; i++)
|
// the input that produces the worst case can vary, so we currently try them all
|
||||||
|
double maxGain = 0;
|
||||||
|
for (int input = 0; input < (1 << symbolSpan); input++)
|
||||||
{
|
{
|
||||||
double g = 0.0;
|
double maxV = 0;
|
||||||
for (j = 0; j < (int)m_taps.size() - 1; j += samplesPerSymbol)
|
for(int i = 0; i < nTaps; i++) {
|
||||||
g += std::fabs(2.0 * m_taps[j]);
|
m_samples[i] = 0;
|
||||||
if ((i & 1) == 0)
|
}
|
||||||
g += std::fabs(m_taps[j]);
|
for (int i = 0; i < symbolSpan; i++)
|
||||||
if (g > maxGain)
|
{
|
||||||
maxGain = g;
|
Type sym = (input >> i) & 1 ? 1 : -1;
|
||||||
|
for (int j = 0; j < samplesPerSymbol; j++)
|
||||||
|
{
|
||||||
|
Type out;
|
||||||
|
if (j == 1) {
|
||||||
|
out = filter(sym);
|
||||||
|
} else {
|
||||||
|
out = filter(0);
|
||||||
|
}
|
||||||
|
double outAbs = abs(out);
|
||||||
|
if (outAbs > maxV) {
|
||||||
|
maxV = outAbs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxV > maxGain) {
|
||||||
|
maxGain = maxV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale up so maximum out is 1
|
// Scale up so maximum out is 1
|
||||||
for(i = 0; i < (int)m_taps.size(); i++)
|
for(i = 0; i < (int)m_taps.size(); i++)
|
||||||
m_taps[i] /= maxGain;
|
m_taps[i] /= maxGain;
|
||||||
|
@ -81,8 +81,8 @@ const QStringList Baudot::m_usFigure = {
|
|||||||
|
|
||||||
const QStringList Baudot::m_russianLetter = {
|
const QStringList Baudot::m_russianLetter = {
|
||||||
"\0", "Е", "\n", "А", " ", "С", "И", "У",
|
"\0", "Е", "\n", "А", " ", "С", "И", "У",
|
||||||
"\r", "Д", "П", "Й", "Н", "Ф", "Ц", "К",
|
"\r", "Д", "Р", "Й", "Ч", "Ф", "Ц", "К",
|
||||||
"Т", "З", "Л", "В", "Х", "Ы", "P", "Я",
|
"Т", "З", "Л", "В", "Х", "Ы", "П", "Я",
|
||||||
"О", "Б", "Г", "<", "М", "Ь", "Ж", ">"
|
"О", "Б", "Г", "<", "М", "Ь", "Ж", ">"
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -206,36 +206,37 @@ void BaudotEncoder::setCharacterSet(Baudot::CharacterSet characterSet)
|
|||||||
switch (m_characterSet)
|
switch (m_characterSet)
|
||||||
{
|
{
|
||||||
case Baudot::ITA2:
|
case Baudot::ITA2:
|
||||||
m_letters = Baudot::m_ita2Letter;
|
m_chars[LETTERS] = Baudot::m_ita2Letter;
|
||||||
m_figures = Baudot::m_ita2Figure;
|
m_chars[FIGURES] = Baudot::m_ita2Figure;
|
||||||
break;
|
break;
|
||||||
case Baudot::UK:
|
case Baudot::UK:
|
||||||
m_letters = Baudot::m_ukLetter;
|
m_chars[LETTERS] = Baudot::m_ukLetter;
|
||||||
m_figures = Baudot::m_ukFigure;
|
m_chars[FIGURES] = Baudot::m_ukFigure;
|
||||||
break;
|
break;
|
||||||
case Baudot::EUROPEAN:
|
case Baudot::EUROPEAN:
|
||||||
m_letters = Baudot::m_europeanLetter;
|
m_chars[LETTERS] = Baudot::m_europeanLetter;
|
||||||
m_figures = Baudot::m_europeanFigure;
|
m_chars[FIGURES] = Baudot::m_europeanFigure;
|
||||||
break;
|
break;
|
||||||
case Baudot::US:
|
case Baudot::US:
|
||||||
m_letters = Baudot::m_usLetter;
|
m_chars[LETTERS] = Baudot::m_usLetter;
|
||||||
m_figures = Baudot::m_usFigure;
|
m_chars[FIGURES] = Baudot::m_usFigure;
|
||||||
break;
|
break;
|
||||||
case Baudot::RUSSIAN:
|
case Baudot::RUSSIAN:
|
||||||
m_letters = Baudot::m_russianLetter;
|
m_chars[LETTERS] = Baudot::m_ita2Letter;
|
||||||
m_figures = Baudot::m_russianFigure;
|
m_chars[FIGURES] = Baudot::m_russianFigure;
|
||||||
break;
|
break;
|
||||||
case Baudot::MURRAY:
|
case Baudot::MURRAY:
|
||||||
m_letters = Baudot::m_murrayLetter;
|
m_chars[LETTERS] = Baudot::m_murrayLetter;
|
||||||
m_figures = Baudot::m_murrayFigure;
|
m_chars[FIGURES] = Baudot::m_murrayFigure;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qDebug() << "BaudotEncoder::BaudotEncoder: Unsupported character set " << m_characterSet;
|
qDebug() << "BaudotEncoder::BaudotEncoder: Unsupported character set " << m_characterSet;
|
||||||
m_letters = Baudot::m_ita2Letter;
|
m_chars[LETTERS] = Baudot::m_ita2Letter;
|
||||||
m_figures = Baudot::m_ita2Figure;
|
m_chars[FIGURES] = Baudot::m_ita2Figure;
|
||||||
m_characterSet = Baudot::ITA2;
|
m_characterSet = Baudot::ITA2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
m_chars[(int)CYRILLIC] = Baudot::m_russianLetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaudotEncoder::setUnshiftOnSpace(bool unshiftOnSpace)
|
void BaudotEncoder::setUnshiftOnSpace(bool unshiftOnSpace)
|
||||||
@ -262,14 +263,11 @@ void BaudotEncoder::setStopBits(int stopBits)
|
|||||||
|
|
||||||
void BaudotEncoder::init()
|
void BaudotEncoder::init()
|
||||||
{
|
{
|
||||||
m_figure = false;
|
m_page = LETTERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaudotEncoder::encode(QChar c, unsigned &bits, unsigned int &bitCount)
|
bool BaudotEncoder::encode(QChar c, unsigned &bits, unsigned int &bitCount)
|
||||||
{
|
{
|
||||||
unsigned int code;
|
|
||||||
const unsigned int codeLen = 5;
|
|
||||||
|
|
||||||
bits = 0;
|
bits = 0;
|
||||||
bitCount = 0;
|
bitCount = 0;
|
||||||
|
|
||||||
@ -277,50 +275,63 @@ bool BaudotEncoder::encode(QChar c, unsigned &bits, unsigned int &bitCount)
|
|||||||
c = c.toUpper();
|
c = c.toUpper();
|
||||||
QString s(c);
|
QString s(c);
|
||||||
|
|
||||||
// We could create reverse look-up tables to speed this up, but it's only 200 baud...
|
if (s == '>')
|
||||||
if (m_letters.contains(s))
|
|
||||||
{
|
{
|
||||||
if (m_figure)
|
addCode(bits, bitCount, m_chars[m_page].indexOf(s));
|
||||||
{
|
m_page = LETTERS;
|
||||||
// Switch to letters
|
|
||||||
addStartBits(bits, bitCount);
|
|
||||||
code = reverseBits(m_letters.indexOf(">"), codeLen);
|
|
||||||
addBits(bits, bitCount, code, codeLen);
|
|
||||||
addStopBits(bits, bitCount);
|
|
||||||
m_figure = false;
|
|
||||||
}
|
|
||||||
addStartBits(bits, bitCount);
|
|
||||||
code = reverseBits(m_letters.indexOf(s), codeLen);
|
|
||||||
addBits(bits, bitCount, code, codeLen);
|
|
||||||
addStopBits(bits, bitCount);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (m_figures.contains(s))
|
else if (s == '<')
|
||||||
{
|
{
|
||||||
if (!m_figure)
|
addCode(bits, bitCount, m_chars[m_page].indexOf(s));
|
||||||
{
|
m_page = FIGURES;
|
||||||
// Switch to figures
|
return true;
|
||||||
addStartBits(bits, bitCount);
|
}
|
||||||
code = reverseBits(m_letters.indexOf("<"), codeLen);
|
else if ((m_characterSet == Baudot::RUSSIAN) && (s == '\0'))
|
||||||
addBits(bits, bitCount, code, codeLen);
|
{
|
||||||
addStopBits(bits, bitCount);
|
addCode(bits, bitCount, m_chars[m_page].indexOf(s));
|
||||||
m_figure = true;
|
m_page = CYRILLIC;
|
||||||
}
|
return true;
|
||||||
addStartBits(bits, bitCount);
|
}
|
||||||
code = reverseBits(m_figures.indexOf(s), codeLen);
|
|
||||||
addBits(bits, bitCount, code, codeLen);
|
// We could create reverse look-up tables to speed this up, but it's only 200 baud...
|
||||||
addStopBits(bits, bitCount);
|
|
||||||
if ((s == " ") && m_unshiftOnSpace) {
|
// Is character in current page? If so, use that, as it avoids switching
|
||||||
m_figure = false;
|
if (m_chars[m_page].contains(s))
|
||||||
}
|
{
|
||||||
|
addCode(bits, bitCount, m_chars[m_page].indexOf(s));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "BaudotEncoder::encode: Can't encode" << c;
|
// Look for character in other pages
|
||||||
return false;
|
const QString switchPage[] = { ">", "<", "\0" };
|
||||||
|
|
||||||
|
for (int page = m_page == LETTERS ? 1 : 0; page < (m_characterSet == Baudot::RUSSIAN) ? 3 : 2; page++)
|
||||||
|
{
|
||||||
|
if (m_chars[page].contains(s))
|
||||||
|
{
|
||||||
|
// Switch to page
|
||||||
|
addCode(bits, bitCount, m_chars[m_page].indexOf(switchPage[page]));
|
||||||
|
m_page = (BaudotEncoder::Page)page;
|
||||||
|
|
||||||
|
addCode(bits, bitCount, m_chars[m_page].indexOf(s));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaudotEncoder::addCode(unsigned& bits, unsigned int& bitCount, unsigned int code) const
|
||||||
|
{
|
||||||
|
const unsigned int codeLen = 5;
|
||||||
|
|
||||||
|
addStartBits(bits, bitCount);
|
||||||
|
code = reverseBits(code, codeLen);
|
||||||
|
addBits(bits, bitCount, code, codeLen);
|
||||||
|
addStopBits(bits, bitCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaudotEncoder::addStartBits(unsigned& bits, unsigned int& bitCount) const
|
void BaudotEncoder::addStartBits(unsigned& bits, unsigned int& bitCount) const
|
||||||
|
@ -88,6 +88,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void addCode(unsigned& bits, unsigned int& bitCount, unsigned int code) const;
|
||||||
void addStartBits(unsigned int& bits, unsigned int& bitCount) const;
|
void addStartBits(unsigned int& bits, unsigned int& bitCount) const;
|
||||||
void addStopBits(unsigned int& bits, unsigned int& bitCount) const;
|
void addStopBits(unsigned int& bits, unsigned int& bitCount) const;
|
||||||
void addBits(unsigned int& bits, unsigned int& bitCount, int data, int count) const;
|
void addBits(unsigned int& bits, unsigned int& bitCount, int data, int count) const;
|
||||||
@ -96,9 +97,12 @@ private:
|
|||||||
|
|
||||||
Baudot::CharacterSet m_characterSet;
|
Baudot::CharacterSet m_characterSet;
|
||||||
bool m_unshiftOnSpace;
|
bool m_unshiftOnSpace;
|
||||||
QStringList m_letters;
|
QStringList m_chars[3];
|
||||||
QStringList m_figures;
|
enum Page {
|
||||||
bool m_figure;
|
LETTERS,
|
||||||
|
FIGURES,
|
||||||
|
CYRILLIC
|
||||||
|
} m_page;
|
||||||
bool m_msbFirst;
|
bool m_msbFirst;
|
||||||
int m_startBits;
|
int m_startBits;
|
||||||
int m_stopBits;
|
int m_stopBits;
|
||||||
|
290
sdrbase/util/rtty.cpp
Normal file
290
sdrbase/util/rtty.cpp
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// 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 "util/rtty.h"
|
||||||
|
|
||||||
|
// From http://www.ct2fzi.net/abreviations/abreviations.html
|
||||||
|
const QHash<QString, QString> Rtty::m_acronyms = {
|
||||||
|
{"AA", "After All"},
|
||||||
|
{"AB", "All Before"},
|
||||||
|
{"ABT", "About"},
|
||||||
|
{"ACK", "Acknowledgement"},
|
||||||
|
{"ADEE", "Addressee"},
|
||||||
|
{"ADR", "Address"},
|
||||||
|
{"AF", "Audio Frequency"},
|
||||||
|
{"AGN", "Again"},
|
||||||
|
{"AM", "Amplitude Modulation"},
|
||||||
|
{"AMU", "Antenna Matching Unit"},
|
||||||
|
{"ANS", "Answer"},
|
||||||
|
{"ANT", "Antenna"},
|
||||||
|
{"ARQ", "Automatic Repeat Request"},
|
||||||
|
{"ATU", "Antenna Tuning Unit"},
|
||||||
|
{"B4", "Before"},
|
||||||
|
{"BCN", "Beacon"},
|
||||||
|
{"BCNU", "Be Seeing You"},
|
||||||
|
{"BD", "Bad"},
|
||||||
|
{"BK", "Break"},
|
||||||
|
{"BN", "Been"},
|
||||||
|
{"BTH", "Both"},
|
||||||
|
{"BTR", "Better"},
|
||||||
|
{"BTW", "By The Way"},
|
||||||
|
{"BTU", "Back To You"},
|
||||||
|
{"C", "Correct"},
|
||||||
|
{"CBA", "Callbook Address"},
|
||||||
|
{"CFM", "Confirm"},
|
||||||
|
{"CK", "Check"},
|
||||||
|
{"CKT", "Circuit"},
|
||||||
|
{"CL", "Closing Down"},
|
||||||
|
{"CLBK", "Callbook"},
|
||||||
|
{"CLD", "Called"},
|
||||||
|
{"CLG", "Calling"},
|
||||||
|
{"CMG", "Coming"},
|
||||||
|
{"CNT", "Can't"},
|
||||||
|
{"COMP", "Computer"},
|
||||||
|
{"CONDX", "Conditions"},
|
||||||
|
{"COZ", "Because"},
|
||||||
|
{"CPI", "Copy"},
|
||||||
|
{"CQ", "General Call"},
|
||||||
|
{"CRD", "Card"},
|
||||||
|
{"CS", "Callsign"},
|
||||||
|
{"CTCSS", "Continuous Tone Coded Squelch System"},
|
||||||
|
{"CU", "See You"},
|
||||||
|
{"CUAGN", "See You Again"},
|
||||||
|
{"CUD", "Could"},
|
||||||
|
{"CUL", "See You Later"},
|
||||||
|
{"CUM", "Come"},
|
||||||
|
{"CUZ", "Because"},
|
||||||
|
{"CW", "Continuous Wave / Morse"},
|
||||||
|
{"DA", "Day"},
|
||||||
|
{"DE", "From"},
|
||||||
|
{"DF", "Direction Finding"},
|
||||||
|
{"DIFF", "Difference"},
|
||||||
|
{"DLD", "Delivered"},
|
||||||
|
{"DLVD", "Delivered"},
|
||||||
|
{"DN", "Down"},
|
||||||
|
{"DR", "Dear"},
|
||||||
|
{"DSB", "Double Side Band"},
|
||||||
|
{"DSP", "Digital Signal Processing"},
|
||||||
|
{"DSW", "Goodbye (Russian)"},
|
||||||
|
{"DWN", "Down"},
|
||||||
|
{"DX", "Distance"},
|
||||||
|
{"EL", "Element"},
|
||||||
|
{"EME", "Earth-Moon-Earth"},
|
||||||
|
{"ENUF", "Enough"},
|
||||||
|
{"ES", "And"},
|
||||||
|
{"EU", "Europe"},
|
||||||
|
{"EVE", "Evening"},
|
||||||
|
{"FB", "Fine Business"},
|
||||||
|
{"FER", "For"},
|
||||||
|
{"FIO", "For Information Only"},
|
||||||
|
{"FM", "Frequency Modulation"},
|
||||||
|
{"FQ", "Frequency"},
|
||||||
|
{"FREQ", "Frequency"},
|
||||||
|
{"FSD", "Full Scale Deflection"},
|
||||||
|
{"FSK", "Frequency Shift Keying"},
|
||||||
|
{"FWD", "Forward"},
|
||||||
|
{"FWIW", "For What It's Worth"},
|
||||||
|
{"FYI", "For Your Information"},
|
||||||
|
{"GA", "Good Afternoon"},
|
||||||
|
{"GB", "Good Bye"},
|
||||||
|
{"GD", "Good Day"},
|
||||||
|
{"GE", "Good Evening"},
|
||||||
|
{"GESS", "Guess"},
|
||||||
|
{"GG", "Going"},
|
||||||
|
{"GLD", "Glad"},
|
||||||
|
{"GM", "Good Morning"},
|
||||||
|
{"GMT", "Greenwich Mean Time"},
|
||||||
|
{"GN", "Good Night"},
|
||||||
|
{"GND", "Ground"},
|
||||||
|
{"GP", "Ground Plane"},
|
||||||
|
{"GPS", "Global Positioning System"},
|
||||||
|
{"GS", "Green Stamp"},
|
||||||
|
{"GUD", "Good"},
|
||||||
|
{"GV", "Give"},
|
||||||
|
{"GVG", "Giving"},
|
||||||
|
{"HAGD", "Have A Good Day"},
|
||||||
|
{"HAGWE", "Have A Good Weekend"},
|
||||||
|
{"HF", "High Frequency"},
|
||||||
|
{"HI", "High"},
|
||||||
|
{"HPE", "Hope"},
|
||||||
|
{"HQ", "Headquarters"},
|
||||||
|
{"HR", "Here / Hour"},
|
||||||
|
{"HRD", "Heard"},
|
||||||
|
{"HV", "Have"},
|
||||||
|
{"HVG", "Having"},
|
||||||
|
{"HVY", "Heavy"},
|
||||||
|
{"HW", "How"},
|
||||||
|
{"IMHO", "In My Humble Opinion"},
|
||||||
|
{"IMI", "Say again"},
|
||||||
|
{"K", "Over"},
|
||||||
|
{"KN", "Over"},
|
||||||
|
{"LF", "Low Frequency"},
|
||||||
|
{"LNG", "Long"},
|
||||||
|
{"LP", "Long Path"},
|
||||||
|
{"LSB", "Lower Sideband"},
|
||||||
|
{"LSN", "Listen"},
|
||||||
|
{"LTR", "Later"},
|
||||||
|
{"LV", "Leave"},
|
||||||
|
{"LVG", "Leaving"},
|
||||||
|
{"LW", "Long Wire"},
|
||||||
|
{"MGR", "Manager"},
|
||||||
|
{"MI", "My"},
|
||||||
|
{"MNI", "Many"},
|
||||||
|
{"MOM", "Moment"},
|
||||||
|
{"MS", "Meteor Scatter"},
|
||||||
|
{"MSG", "Message"},
|
||||||
|
{"N", "No"},
|
||||||
|
{"NCS", "Net Control Station"},
|
||||||
|
{"ND", "Nothing Doing"},
|
||||||
|
{"NM", "No More"},
|
||||||
|
{"NR", "Near / Number"},
|
||||||
|
{"NW", "Now"},
|
||||||
|
{"OB", "Old Boy"},
|
||||||
|
{"OC", "Old Chap"},
|
||||||
|
{"OM", "Old Man"},
|
||||||
|
{"OP", "Operator"},
|
||||||
|
{"OPR", "Operator"},
|
||||||
|
{"OT", "Old Timer"},
|
||||||
|
{"OW", "Old Woman"},
|
||||||
|
{"PA", "Power Amplifier"},
|
||||||
|
{"PBL", "Preamble"},
|
||||||
|
{"PKG", "Package"},
|
||||||
|
{"POV", "Point Of View"},
|
||||||
|
{"PSE", "Please"},
|
||||||
|
{"PSK", "Phase Shift Keying"},
|
||||||
|
{"PT", "Point"},
|
||||||
|
{"PTT", "Push To Talk"},
|
||||||
|
{"PWR", "Power"},
|
||||||
|
{"PX", "Prefix"},
|
||||||
|
{"QRA", "Address"},
|
||||||
|
{"QRG", "Frequency"},
|
||||||
|
{"QRK", "Readability"},
|
||||||
|
{"QRL", "Busy"},
|
||||||
|
{"QRM", "Interference"},
|
||||||
|
{"QRN", "Noise"},
|
||||||
|
{"QRO", "High Power"},
|
||||||
|
{"QRP", "Low Power"},
|
||||||
|
{"QRQ", "Send Faster"},
|
||||||
|
{"QRS", "Send Slower"},
|
||||||
|
{"QRSS", "Send Very Slowly"},
|
||||||
|
{"QRT", "Stop Sending"},
|
||||||
|
{"QRU", "Nothing Further To Say"},
|
||||||
|
{"QRV", "Ready"},
|
||||||
|
{"QRX", "Wait"},
|
||||||
|
{"QRZ", "Who Is Calling Me"},
|
||||||
|
{"QSA", "Signal Strength"},
|
||||||
|
{"QSB", "Fading"},
|
||||||
|
{"QSK", "Break-in"},
|
||||||
|
{"QSL", "All Received OK"},
|
||||||
|
{"QSLL", "I Will Send A QSL Card"},
|
||||||
|
{"QSO", "Contact"},
|
||||||
|
{"QSP", "Relay A Message"},
|
||||||
|
{"QSX", "Listening On Frequency"},
|
||||||
|
{"QSY", "Change Frequency"},
|
||||||
|
{"QTH", "Location"},
|
||||||
|
{"R", "Received OK"},
|
||||||
|
{"RC", "Ragchew"},
|
||||||
|
{"RCD", "Recieved"},
|
||||||
|
{"RCVR", "Receiver"},
|
||||||
|
{"RE", "Regarding"},
|
||||||
|
{"REF", "Reference"},
|
||||||
|
{"RF", "Radio Frequency"},
|
||||||
|
{"RFI", "Radio Frequency Interference"},
|
||||||
|
{"RPT", "Repeat / Report"},
|
||||||
|
{"RST", "Signal Report"},
|
||||||
|
{"RTTY", "Radio Teletype"},
|
||||||
|
{"RX", "Receive"},
|
||||||
|
{"SA", "Say"},
|
||||||
|
{"SDR", "Software Defined Radio"},
|
||||||
|
{"SEZ", "Says"},
|
||||||
|
{"SGD", "Signed"},
|
||||||
|
{"SHUD", "Should"},
|
||||||
|
{"SIG", "Signal"},
|
||||||
|
{"SK", "End Of Work"},
|
||||||
|
{"SKED", "Schedule"},
|
||||||
|
{"SN", "Soon"},
|
||||||
|
{"SP", "Short Path"},
|
||||||
|
{"SRI", "Sorry"},
|
||||||
|
{"SSB", "Single Sideband"},
|
||||||
|
{"STN", "Station"},
|
||||||
|
{"SUM", "Some"},
|
||||||
|
{"SVC", "Service"},
|
||||||
|
{"SWR", "Standing Wave Ratio"},
|
||||||
|
{"TFC", "Traffic"},
|
||||||
|
{"TIA", "Thanks In Advance"},
|
||||||
|
{"TKS", "Thanks"},
|
||||||
|
{"TMW", "Tomorrow"},
|
||||||
|
{"TNC", "Terminal Node Controller"},
|
||||||
|
{"TNX", "Thanks"},
|
||||||
|
{"TR", "Transmit"},
|
||||||
|
{"T/R", "Transmit/Receive"},
|
||||||
|
{"TRBL", "Trouble"},
|
||||||
|
{"TRF", "Tuned Radio Frequency"},
|
||||||
|
{"TRIX", "Tricks"},
|
||||||
|
{"TRX", "Transceiver"},
|
||||||
|
{"TT", "That"},
|
||||||
|
{"TTS", "That Is"},
|
||||||
|
{"TU", "Thank You"},
|
||||||
|
{"TVI", "Television Interference"},
|
||||||
|
{"TX", "Transmit"},
|
||||||
|
{"TXT", "Text"},
|
||||||
|
{"U", "You"},
|
||||||
|
{"UHF", "Ultra High Frequency"},
|
||||||
|
{"UNLIS", "Unlicensed"},
|
||||||
|
{"UR", "Your"},
|
||||||
|
{"URS", "Yours"},
|
||||||
|
{"UTC", "Coordinated Universal Time"},
|
||||||
|
{"V", "Volts"},
|
||||||
|
{"VHF", "Very High Frequency"},
|
||||||
|
{"VE", "Understood"},
|
||||||
|
{"VERT", "Vertical"},
|
||||||
|
{"VFB", "Very Fine Business"},
|
||||||
|
{"VFO", "Variable Frequency Oscillator"},
|
||||||
|
{"VLF", "Very Low Frequency"},
|
||||||
|
{"VOX", "Voice Operated"},
|
||||||
|
{"VSB", "Vestigial Sideband"},
|
||||||
|
{"VSWR", "Voltage Standing Wave Ratio"},
|
||||||
|
{"VY", "Very"},
|
||||||
|
{"W", "Watts"},
|
||||||
|
{"WA", "Word After"},
|
||||||
|
{"WAT", "What"},
|
||||||
|
{"WATSA", "What Say"},
|
||||||
|
{"WB", "Word Before"},
|
||||||
|
{"WD", "Word"},
|
||||||
|
{"WDS", "Words"},
|
||||||
|
{"WID", "With"},
|
||||||
|
{"WKD", "Worked"},
|
||||||
|
{"WKG", "Working"},
|
||||||
|
{"WL", "Will"},
|
||||||
|
{"WPM", "Words Per Minute"},
|
||||||
|
{"WRD", "Word"},
|
||||||
|
{"WRK", "Work"},
|
||||||
|
{"WUD", "Would"},
|
||||||
|
{"WX", "Weather"},
|
||||||
|
{"XCVR", "Transceiver"},
|
||||||
|
{"XMTR", "Transmitter"},
|
||||||
|
{"XTAL", "Crystal"},
|
||||||
|
{"YF", "Wife"},
|
||||||
|
{"YL", "Young Lady"},
|
||||||
|
{"YR", "Year"},
|
||||||
|
{"Z", "Zulu Time"},
|
||||||
|
{"30", "I Have Nothing More to Send"},
|
||||||
|
{"33", "Fondest Regards"},
|
||||||
|
{"55", "Best Success"},
|
||||||
|
{"73", "Best Wishes"},
|
||||||
|
{"88", "Love And Kisses"},
|
||||||
|
};
|
31
sdrbase/util/rtty.h
Normal file
31
sdrbase/util/rtty.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// 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_UTIL_RTTY_H
|
||||||
|
#define INCLUDE_UTIL_RTTY_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
class SDRBASE_API Rtty
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const QHash<QString, QString> m_acronyms;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* INCLUDE_UTIL_RTTY_H */
|
@ -7,6 +7,7 @@ set(CMAKE_AUTOUIC OFF)
|
|||||||
set(sdrgui_SOURCES
|
set(sdrgui_SOURCES
|
||||||
mainwindow.cpp
|
mainwindow.cpp
|
||||||
gui/aboutdialog.cpp
|
gui/aboutdialog.cpp
|
||||||
|
gui/acronymview.cpp
|
||||||
gui/addpresetdialog.cpp
|
gui/addpresetdialog.cpp
|
||||||
gui/audiodialog.cpp
|
gui/audiodialog.cpp
|
||||||
gui/audioselectdialog.cpp
|
gui/audioselectdialog.cpp
|
||||||
@ -127,6 +128,7 @@ set(sdrgui_HEADERS
|
|||||||
gui/aboutdialog.h
|
gui/aboutdialog.h
|
||||||
gui/accessiblevaluedial.h
|
gui/accessiblevaluedial.h
|
||||||
gui/accessiblevaluedialz.h
|
gui/accessiblevaluedialz.h
|
||||||
|
gui/acronymview.h
|
||||||
gui/addpresetdialog.h
|
gui/addpresetdialog.h
|
||||||
gui/audiodialog.h
|
gui/audiodialog.h
|
||||||
gui/audioselectdialog.h
|
gui/audioselectdialog.h
|
||||||
|
68
sdrgui/gui/acronymview.cpp
Normal file
68
sdrgui/gui/acronymview.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// 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 <QEvent>
|
||||||
|
#include <QHelpEvent>
|
||||||
|
#include <QToolTip>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "acronymview.h"
|
||||||
|
|
||||||
|
AcronymView::AcronymView(QWidget* parent) :
|
||||||
|
QPlainTextEdit(parent)
|
||||||
|
{
|
||||||
|
setMouseTracking(true);
|
||||||
|
setReadOnly(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AcronymView::event(QEvent* event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::ToolTip)
|
||||||
|
{
|
||||||
|
QHelpEvent* helpEvent = static_cast<QHelpEvent*>(event);
|
||||||
|
QTextCursor cursor = cursorForPosition(helpEvent->pos());
|
||||||
|
cursor.select(QTextCursor::WordUnderCursor);
|
||||||
|
QString text = cursor.selectedText();
|
||||||
|
// Remove trailing digits from METAR
|
||||||
|
while (text.size() > 0 && text.right(1)[0].isDigit()) {
|
||||||
|
text = text.left(text.size() - 1);
|
||||||
|
}
|
||||||
|
if (!text.isEmpty() && m_acronym.contains(text))
|
||||||
|
{
|
||||||
|
QToolTip::showText(helpEvent->globalPos(), QString("%1 - %2").arg(text).arg(m_acronym.value(text)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!text.isEmpty()) {
|
||||||
|
qDebug() << "AcronymView::event: No tooltip for " << text;
|
||||||
|
}
|
||||||
|
QToolTip::hideText();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QPlainTextEdit::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcronymView::addAcronym(const QString& acronym, const QString& explanation)
|
||||||
|
{
|
||||||
|
m_acronym.insert(acronym, explanation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcronymView::addAcronyms(const QHash<QString, QString>& acronyms)
|
||||||
|
{
|
||||||
|
m_acronym.insert(acronyms);
|
||||||
|
}
|
41
sdrgui/gui/acronymview.h
Normal file
41
sdrgui/gui/acronymview.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// 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_GUI_ACRONYMVIEW_H
|
||||||
|
#define INCLUDE_GUI_ACRONYMVIEW_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
// Displays text like a QPlainTextEdit, but adds tooltips for acronyms in the text
|
||||||
|
class SDRGUI_API AcronymView : public QPlainTextEdit {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QHash<QString, QString> m_acronym;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
AcronymView(QWidget* parent = nullptr);
|
||||||
|
bool event(QEvent* event);
|
||||||
|
void addAcronym(const QString& acronym, const QString& explanation);
|
||||||
|
void addAcronyms(const QHash<QString, QString>& acronyms);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_GUI_ACRONYMVIEW_H
|
Loading…
Reference in New Issue
Block a user