diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3fe16e6..83b7a22e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,14 +1,39 @@
-**unreleased**
+**1.1.x - unreleased**
+- Reworked most graphical elements as SVGs for faster loadtimes and crispier display on hi-dpi displays
+- Updated pipelines to match changes in digiham
+- Changed D-Star and NXDN integrations to use new decoders from digiham
+- Added D-Star and NXDN metadata display
+
+**1.0.0**
- Introduced `squelch_auto_margin` config option that allows configuring the auto squelch level
- Removed `port` configuration option; `rtltcp_compat` takes the port number with the new connectors
-- Added support for new WSJT-X modes FST4 and FST4W (only available with WSJT-X 2.3)
+- Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X 2.3) and Q65 (only avilable with
+ WSJT-X 2.4)
- Added support for demodulating M17 digital voice signals using m17-cxx-demod
- New reporting infrastructure, allowing WSPR and FST4W spots to be sent to wsprnet.org
- Add some basic filtering capabilities to the map
+- New arguments to the `openwebrx` command-line to facilitate the administration of users (try `openwebrx admin`)
+- Default bandwidth changes:
+ - "WFM" changed to 150kHz
+ - "Packet" (APRS) changed to 12.5kHz
+- Configuration rework:
+ - New: fully web-based configuration interface
+ - System configuration parameters have been moved to a new, separate `openwebrx.conf` file
+ - Remaining parameters are now editable in the web configuration
+ - Existing `config_webrx.py` files will still be read, but changes made in the web configuration will be written to
+ a new storage system
+ - Added upload of avatar and panorama image via web configuration
- New devices supported:
- - HPSDR devices (Hermes Lite 2)
+ - HPSDR devices (Hermes Lite 2) thanks to @jancona
- BBRF103 / RX666 / RX888 devices supported by libsddc
- - Devices using the EB200 protocol
+ - R&S devices using the EB200 or Ammos protocols
+
+**0.20.3**
+- Fix a compatibility issue with python versions <= 3.6
+
+**0.20.2**
+- Fix a security problem that allowed arbitrary commands to be executed on the receiver
+ ([See github issue #215](https://github.com/jketterl/openwebrx/issues/215))
**0.20.1**
- Remove broken OSM map fallback
diff --git a/README.md b/README.md
index 9d6ccfa2..95171481 100644
--- a/README.md
+++ b/README.md
@@ -13,8 +13,7 @@ It has the following features:
- it works in Google Chrome, Chromium and Mozilla Firefox
- supports a wide range of [SDR hardware](https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices)
- Multiple SDR devices can be used simultaneously
-- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag)
-- [dsd](https://github.com/f4exb/dsdcc) based demodulators (D-Star, NXDN)
+- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag, D-Star, NXDN)
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
FST4W)
- [direwolf](https://github.com/wb2osz/direwolf) based demodulation of APRS packets
diff --git a/bands.json b/bands.json
index ad7cc8c1..02bb7036 100644
--- a/bands.json
+++ b/bands.json
@@ -6,7 +6,8 @@
"frequencies": {
"fst4": 136000,
"fst4w": 136000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "630m",
@@ -15,7 +16,8 @@
"frequencies": {
"fst4": 474200,
"fst4w": 474200
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "160m",
@@ -30,7 +32,8 @@
"js8": 1842000,
"fst4": 1839000,
"fst4w": 1836800
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "80m",
@@ -44,7 +47,8 @@
"jt9": 3572000,
"ft4": [3568000, 3575000],
"js8": 3578000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "60m",
@@ -53,7 +57,8 @@
"frequencies": {
"ft8": 5357000,
"wspr": 5364700
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "40m",
@@ -67,7 +72,8 @@
"jt9": 7078000,
"ft4": 7047500,
"js8": 7078000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "30m",
@@ -81,7 +87,8 @@
"jt9": 10140000,
"ft4": 10140000,
"js8": 10130000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "20m",
@@ -95,7 +102,8 @@
"jt9": 14078000,
"ft4": 14080000,
"js8": 14078000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "17m",
@@ -109,7 +117,8 @@
"jt9": 18104000,
"ft4": 18104000,
"js8": 18104000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "15m",
@@ -123,7 +132,8 @@
"jt9": 21078000,
"ft4": 21140000,
"js8": 21078000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "12m",
@@ -137,7 +147,8 @@
"jt9": 24919000,
"ft4": 24919000,
"js8": 24922000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "10m",
@@ -151,7 +162,8 @@
"jt9": 28078000,
"ft4": 28180000,
"js8": 28078000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "6m",
@@ -164,8 +176,10 @@
"jt65": 50310000,
"jt9": 50312000,
"ft4": 50318000,
- "js8": 50318000
- }
+ "js8": 50318000,
+ "q65": [50211000, 50275000]
+ },
+ "tags": ["hamradio"]
},
{
"name": "4m",
@@ -173,7 +187,8 @@
"upper_bound": 70200000,
"frequencies": {
"wspr": 70091000
- }
+ },
+ "tags": ["hamradio"]
},
{
"name": "2m",
@@ -184,110 +199,169 @@
"ft8": 144174000,
"ft4": 144170000,
"jt65": 144120000,
- "packet": 144800000
- }
+ "packet": 144800000,
+ "q65": 144116000
+ },
+ "tags": ["hamradio"]
},
{
"name": "70cm",
"lower_bound": 430000000,
"upper_bound": 440000000,
"frequencies": {
- "pocsag": 439987500
- }
+ "pocsag": 439987500,
+ "q65": 432065000
+ },
+ "tags": ["hamradio"]
},
{
"name": "23cm",
"lower_bound": 1240000000,
- "upper_bound": 1300000000
+ "upper_bound": 1300000000,
+ "frequencies": {
+ "q65": 1296065000
+ },
+ "tags": ["hamradio"]
},
{
"name": "13cm",
"lower_bound": 2320000000,
- "upper_bound": 2450000000
+ "upper_bound": 2450000000,
+ "frequencies": {
+ "q65": [2301065000, 2304065000, 2320065000]
+ },
+ "tags": ["hamradio"]
},
{
"name": "9cm",
"lower_bound": 3400000000,
- "upper_bound": 3475000000
+ "upper_bound": 3475000000,
+ "frequencies": {
+ "q65": 3400065000
+ },
+ "tags": ["hamradio"]
},
{
"name": "6cm",
"lower_bound": 5650000000,
- "upper_bound": 5850000000
+ "upper_bound": 5850000000,
+ "frequencies": {
+ "q65": 5760200000
+ },
+ "tags": ["hamradio"]
},
{
"name": "3cm",
"lower_bound": 10000000000,
- "upper_bound": 10500000000
+ "upper_bound": 10500000000,
+ "frequencies": {
+ "q65": 10368200000
+ },
+ "tags": ["hamradio"]
},
{
"name": "120m Broadcast",
"lower_bound": 2300000,
- "upper_bound": 2495000
+ "upper_bound": 2495000,
+ "tags": ["broadcast"]
},
{
"name": "90m Broadcast",
"lower_bound": 3200000,
- "upper_bound": 3400000
+ "upper_bound": 3400000,
+ "tags": ["broadcast"]
},
{
"name": "75m Broadcast",
"lower_bound": 3900000,
- "upper_bound": 4000000
+ "upper_bound": 4000000,
+ "tags": ["broadcast"]
},
{
"name": "60m Broadcast",
"lower_bound": 4750000,
- "upper_bound": 4995000
+ "upper_bound": 4995000,
+ "tags": ["broadcast"]
},
{
"name": "49m Broadcast",
"lower_bound": 5900000,
- "upper_bound": 6200000
+ "upper_bound": 6200000,
+ "tags": ["broadcast"]
},
{
"name": "41m Broadcast",
"lower_bound": 7200000,
- "upper_bound": 7450000
+ "upper_bound": 7450000,
+ "tags": ["broadcast"]
},
{
"name": "31m Broadcast",
"lower_bound": 9400000,
- "upper_bound": 9900000
+ "upper_bound": 9900000,
+ "tags": ["broadcast"]
},
{
"name": "25m Broadcast",
"lower_bound": 11600000,
- "upper_bound": 12100000
+ "upper_bound": 12100000,
+ "tags": ["broadcast"]
},
{
"name": "22m Broadcast",
"lower_bound": 13570000,
- "upper_bound": 13870000
+ "upper_bound": 13870000,
+ "tags": ["broadcast"]
},
{
"name": "19m Broadcast",
"lower_bound": 15100000,
- "upper_bound": 15830000
+ "upper_bound": 15830000,
+ "tags": ["broadcast"]
},
{
"name": "16m Broadcast",
"lower_bound": 17480000,
- "upper_bound": 17900000
+ "upper_bound": 17900000,
+ "tags": ["broadcast"]
},
{
"name": "15m Broadcast",
"lower_bound": 18900000,
- "upper_bound": 19020000
+ "upper_bound": 19020000,
+ "tags": ["broadcast"]
},
{
"name": "13m Broadcast",
"lower_bound": 21450000,
- "upper_bound": 21850000
+ "upper_bound": 21850000,
+ "tags": ["broadcast"]
},
{
"name": "11m Broadcast",
"lower_bound": 25670000,
- "upper_bound": 26100000
+ "upper_bound": 26100000,
+ "tags": ["broadcast"]
+ },
+ {
+ "name": "FM Broadcast",
+ "lower_bound": 87500000,
+ "upper_bound": 108000000,
+ "tags": ["broadcast"]
+ },
+ {
+ "name": "11m CB",
+ "lower_bound": 26965000,
+ "upper_bound": 27405000,
+ "frequencies": {
+ "js8": 27245000
+ },
+ "tags": ["public"]
+ },
+ {
+ "name": "PMR446",
+ "lower_bound": 446000000,
+ "upper_bound": 446200000,
+ "tags": ["public"]
}
]
\ No newline at end of file
diff --git a/bookmarks.json b/bookmarks.json
deleted file mode 100644
index dec818b2..00000000
--- a/bookmarks.json
+++ /dev/null
@@ -1,217 +0,0 @@
-[
- {
- "name": "DB0ZU",
- "frequency": 145725000,
- "modulation": "nfm"
- },
- {
- "name": "DB0ZM",
- "frequency": 145750000,
- "modulation": "nfm"
- },
- {
- "name": "DM0ULR",
- "frequency": 145787500,
- "modulation": "nfm"
- },
- {
- "name": "DB0EL",
- "frequency": 439275000,
- "modulation": "nfm"
- },
- {
- "name": "DB0NJ",
- "frequency": 438775000,
- "modulation": "nfm"
- },
- {
- "name": "DB0NJ",
- "frequency": 439437500,
- "modulation": "dmr"
- },
- {
- "name": "DB0UFO",
- "frequency": 438312500,
- "modulation": "dmr"
- },
- {
- "name": "DB0PV",
- "frequency": 438525000,
- "modulation": "ysf"
- },
- {
- "name": "DB0BZA",
- "frequency": 438412500,
- "modulation": "ysf"
- },
- {
- "name": "DB0OSH",
- "frequency": 438250000,
- "modulation": "ysf"
- },
- {
- "name": "DB0ULR",
- "frequency": 439325000,
- "modulation": "nfm"
- },
- {
- "name": "DB0ZU",
- "frequency": 438850000,
- "modulation": "nfm"
- },
- {
- "name": "DB0ISW",
- "frequency": 438650000,
- "modulation": "nfm"
- },
- {
- "name": "Radio DARC",
- "frequency": 6070000,
- "modulation": "am"
- },
- {
- "name": "DB0TVM",
- "frequency": 439575000,
- "modulation": "dstar"
- },
- {
- "name": "DB0TVM",
- "frequency": 439800000,
- "modulation": "dmr"
- },
- {
- "name": "DB0TR",
- "frequency": 438700000,
- "modulation": "nfm"
- },
- {
- "name": "DB0PME",
- "frequency": 439825000,
- "modulation": "dmr"
- },
- {
- "name": "DB0HKN",
- "frequency": 438300000,
- "modulation": "dmr"
- },
- {
- "name": "OE2XHM",
- "frequency": 438825000,
- "modulation": "nfm"
- },
- {
- "name": "DM0WW",
- "frequency": 438962500,
- "modulation": "dmr"
- },
- {
- "name": "OE7XXR",
- "frequency": 438200000,
- "modulation": "dstar"
- },
- {
- "name": "OE2XZR",
- "frequency": 439000000,
- "modulation": "dstar"
- },
- {
- "name": "DB0OAL",
- "frequency": 439912500,
- "modulation": "dmr"
- },
- {
- "name": "DB0AAT",
- "frequency": 439550000,
- "modulation": "dmr"
- },
- {
- "name": "DB0FSG",
- "frequency": 439937500,
- "modulation": "dmr"
- },
- {
- "name": "DB0ULR",
- "frequency": 145575000,
- "modulation": "nfm"
- },
- {
- "name": "DB0RDH",
- "frequency": 145737500,
- "modulation": "dstar"
- },
- {
- "name": "DM0GAP",
- "frequency": 145612500,
- "modulation": "nfm"
- },
- {
- "name": "DB0XF",
- "frequency": 145600000,
- "modulation": "nfm"
- },
- {
- "name": "DB0TOL",
- "frequency": 145712500,
- "modulation": "nfm"
- },
- {
- "name": "DB0TTB",
- "frequency": 439587500,
- "modulation": "dmr"
- },
- {
- "name": "DB0TRS",
- "frequency": 439125000,
- "modulation": "nfm"
- },
- {
- "name": "DB0OAL",
- "frequency": 438937500,
- "modulation": "nfm"
- },
- {
- "name": "DM0ULR",
- "frequency": 439337500,
- "modulation": "nxdn"
- },
- {
- "name": "DB0MIR",
- "frequency": 439300000,
- "modulation": "nfm"
- },
- {
- "name": "DB0PM",
- "frequency": 439075000,
- "modulation": "nfm"
- },
- {
- "name": "DB0CP",
- "frequency": 439025000,
- "modulation": "nfm"
- },
- {
- "name": "OE7XGR",
- "frequency": 438925000,
- "modulation": "dmr"
- },
- {
- "name": "DB0TOL",
- "frequency": 438725000,
- "modulation": "nfm"
- },
- {
- "name": "DB0OAL",
- "frequency": 438325000,
- "modulation": "dstar"
- },
- {
- "name": "DB0ROL",
- "frequency": 439237500,
- "modulation": "nfm"
- },
- {
- "name": "DB0ABX",
- "frequency": 439137500,
- "modulation": "nfm"
- }
-]
diff --git a/config_webrx.py b/config_webrx.py
index b5f17026..4d61fbd4 100644
--- a/config_webrx.py
+++ b/config_webrx.py
@@ -32,32 +32,45 @@ config_webrx: configuration options for OpenWebRX
and use them for running your web service with OpenWebRX.)
"""
+"""
+DEPRECATION notice
+
+As of OpenWebRX 0.21, the configuration system has been completely overhauled.
+The configuration of OpenWebRX should now be done in the new web-based
+configuration interface exclusively.
+
+Existing configurations can still be used, but their values will be migrated
+to the new storage infrastructure as soon as the web configuration is used to
+edit them.
+
+The new configuration storage is not intended to be edited manually.
+"""
+
# configuration version. please only modify if you're able to perform the associated migration steps.
-version = 3
+version = 7
# NOTE: you can find additional information about configuring OpenWebRX in the Wiki:
# https://github.com/jketterl/openwebrx/wiki/Configuration-guide
# ==== Server settings ====
-web_port = 8073
-max_clients = 20
+#max_clients = 20
# ==== Web GUI configuration ====
-receiver_name = "[Callsign]"
-receiver_location = "Budapest, Hungary"
-receiver_asl = 200
-receiver_admin = "example@example.com"
-receiver_gps = {"lat": 47.000000, "lon": 19.000000}
-photo_title = "Panorama of Budapest from Schönherz Zoltán Dormitory"
+#receiver_name = "[Callsign]"
+#receiver_location = "Budapest, Hungary"
+#receiver_asl = 200
+#receiver_admin = "example@example.com"
+#receiver_gps = {"lat": 47.000000, "lon": 19.000000}
+#photo_title = "Panorama of Budapest from Schönherz Zoltán Dormitory"
# photo_desc allows you to put pretty much any HTML you like into the receiver description.
# The lines below should give you some examples of what's possible.
-photo_desc = """
-You can add your own background photo and receiver information.
-Receiver is operated by: Receiver Operator
-Device: Receiver Device
-Antenna: Receiver Antenna
-Website: http://localhost
-"""
+#photo_desc = """
+#You can add your own background photo and receiver information.
+#Receiver is operated by: Receiver Operator
+#Device: Receiver Device
+#Antenna: Receiver Antenna
+#Website: http://localhost
+#"""
# ==== Public receiver listings ====
# You can publish your receiver on online receiver directories, like https://www.receiverbook.de
@@ -65,7 +78,7 @@ Website: http://localhost
# Please note that you not share your receiver keys publicly since anyone that obtains your receiver key can take over
# your public listing.
# Your receiver keys should be placed into this array:
-receiver_keys = []
+#receiver_keys = []
# If you list your receiver on multiple sites, you can place all your keys into the array above, or you can append
# keys to the arraylike this:
# receiver_keys += ["my-receiver-key"]
@@ -73,30 +86,29 @@ receiver_keys = []
# If you're not sure, simply copy & paste the code you received from your listing site below this line:
# ==== DSP/RX settings ====
-fft_fps = 9
-fft_size = 4096 # Should be power of 2
-fft_voverlap_factor = (
- 0.3 # If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram.
-)
+#fft_fps = 9
+#fft_size = 4096 # Should be power of 2
+#fft_voverlap_factor = (
+# 0.3 # If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram.
+#)
-audio_compression = "adpcm" # valid values: "adpcm", "none"
-fft_compression = "adpcm" # valid values: "adpcm", "none"
+#audio_compression = "adpcm" # valid values: "adpcm", "none"
+#fft_compression = "adpcm" # valid values: "adpcm", "none"
# Tau setting for WFM (broadcast FM) deemphasis\
# Quote from wikipedia https://en.wikipedia.org/wiki/FM_broadcasting#Pre-emphasis_and_de-emphasis
# "In most of the world a 50 µs time constant is used. In the Americas and South Korea, 75 µs is used"
# Enable one of the following lines, depending on your location:
# wfm_deemphasis_tau = 75e-6 # for US and South Korea
-wfm_deemphasis_tau = 50e-6 # for the rest of the world
+#wfm_deemphasis_tau = 50e-6 # for the rest of the world
-digimodes_enable = True # Decoding digimodes come with higher CPU usage.
-digimodes_fft_size = 2048
+#digimodes_fft_size = 2048
# determines the quality, and thus the cpu usage, for the ambe codec used by digital voice modes
# if you're running on a Raspi (up to 3B+) you'll want to leave this on 1
-digital_voice_unvoiced_quality = 1
+#digital_voice_unvoiced_quality = 1
# enables lookup of DMR ids using the radioid api
-digital_voice_dmr_id_lookup = True
+#digital_voice_dmr_id_lookup = True
"""
Note: if you experience audio underruns while CPU usage is 100%, you can:
@@ -116,232 +128,230 @@ Note: if you experience audio underruns while CPU usage is 100%, you can:
# Currently supported types of sdr receivers:
# "rtl_sdr", "rtl_sdr_soapy", "sdrplay", "hackrf", "airspy", "airspyhf", "fifi_sdr",
-# "perseussdr", "lime_sdr", "pluto_sdr", "soapy_remote", "hpsdr", "red_pitaya", "uhd",
-# "radioberry", "fcdpp", "rtl_tcp", "sddc", "eb200"
+# "perseussdr", "lime_sdr", "pluto_sdr", "soapy_remote", "hpsdr", "uhd",
+# "radioberry", "fcdpp", "rtl_tcp", "sddc", "runds"
# For more details on specific types, please checkout the wiki:
# https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices
-sdrs = {
- "rtlsdr": {
- "name": "RTL-SDR USB Stick",
- "type": "rtl_sdr",
- "ppm": 0,
- # you can change this if you use an upconverter. formula is:
- # center_freq + lfo_offset = actual frequency on the sdr
- # "lfo_offset": 0,
- "profiles": {
- "70cm": {
- "name": "70cm Relais",
- "center_freq": 438800000,
- "rf_gain": 29,
- "samp_rate": 2400000,
- "start_freq": 439275000,
- "start_mod": "nfm",
- },
- "2m": {
- "name": "2m komplett",
- "center_freq": 145000000,
- "rf_gain": 29,
- "samp_rate": 2048000,
- "start_freq": 145725000,
- "start_mod": "nfm",
- },
- },
- },
- "airspy": {
- "name": "Airspy HF+",
- "type": "airspyhf",
- "ppm": 0,
- "rf_gain": "auto",
- "profiles": {
- "20m": {
- "name": "20m",
- "center_freq": 14150000,
- "samp_rate": 384000,
- "start_freq": 14070000,
- "start_mod": "usb",
- },
- "30m": {
- "name": "30m",
- "center_freq": 10125000,
- "samp_rate": 192000,
- "start_freq": 10142000,
- "start_mod": "usb",
- },
- "40m": {
- "name": "40m",
- "center_freq": 7100000,
- "samp_rate": 256000,
- "start_freq": 7070000,
- "start_mod": "lsb",
- },
- "80m": {
- "name": "80m",
- "center_freq": 3650000,
- "samp_rate": 384000,
- "start_freq": 3570000,
- "start_mod": "lsb",
- },
- "49m": {
- "name": "49m Broadcast",
- "center_freq": 6050000,
- "samp_rate": 384000,
- "start_freq": 6070000,
- "start_mod": "am",
- },
- },
- },
- "sdrplay": {
- "name": "SDRPlay RSP2",
- "type": "sdrplay",
- "ppm": 0,
- "antenna": "Antenna A",
- "profiles": {
- "20m": {
- "name": "20m",
- "center_freq": 14150000,
- "rf_gain": 0,
- "samp_rate": 500000,
- "start_freq": 14070000,
- "start_mod": "usb",
- },
- "30m": {
- "name": "30m",
- "center_freq": 10125000,
- "rf_gain": 0,
- "samp_rate": 250000,
- "start_freq": 10142000,
- "start_mod": "usb",
- },
- "40m": {
- "name": "40m",
- "center_freq": 7100000,
- "rf_gain": 0,
- "samp_rate": 500000,
- "start_freq": 7070000,
- "start_mod": "lsb",
- },
- "80m": {
- "name": "80m",
- "center_freq": 3650000,
- "rf_gain": 0,
- "samp_rate": 500000,
- "start_freq": 3570000,
- "start_mod": "lsb",
- },
- "49m": {
- "name": "49m Broadcast",
- "center_freq": 6000000,
- "rf_gain": 0,
- "samp_rate": 500000,
- "start_freq": 6070000,
- "start_mod": "am",
- },
- },
- },
-}
+#sdrs = {
+# "rtlsdr": {
+# "name": "RTL-SDR USB Stick",
+# "type": "rtl_sdr",
+# "ppm": 0,
+# # you can change this if you use an upconverter. formula is:
+# # center_freq + lfo_offset = actual frequency on the sdr
+# # "lfo_offset": 0,
+# "profiles": {
+# "70cm": {
+# "name": "70cm Relais",
+# "center_freq": 438800000,
+# "rf_gain": 29,
+# "samp_rate": 2400000,
+# "start_freq": 439275000,
+# "start_mod": "nfm",
+# },
+# "2m": {
+# "name": "2m komplett",
+# "center_freq": 145000000,
+# "rf_gain": 29,
+# "samp_rate": 2048000,
+# "start_freq": 145725000,
+# "start_mod": "nfm",
+# },
+# },
+# },
+# "airspy": {
+# "name": "Airspy HF+",
+# "type": "airspyhf",
+# "ppm": 0,
+# "rf_gain": "auto",
+# "profiles": {
+# "20m": {
+# "name": "20m",
+# "center_freq": 14150000,
+# "samp_rate": 384000,
+# "start_freq": 14070000,
+# "start_mod": "usb",
+# },
+# "30m": {
+# "name": "30m",
+# "center_freq": 10125000,
+# "samp_rate": 192000,
+# "start_freq": 10142000,
+# "start_mod": "usb",
+# },
+# "40m": {
+# "name": "40m",
+# "center_freq": 7100000,
+# "samp_rate": 256000,
+# "start_freq": 7070000,
+# "start_mod": "lsb",
+# },
+# "80m": {
+# "name": "80m",
+# "center_freq": 3650000,
+# "samp_rate": 384000,
+# "start_freq": 3570000,
+# "start_mod": "lsb",
+# },
+# "49m": {
+# "name": "49m Broadcast",
+# "center_freq": 6050000,
+# "samp_rate": 384000,
+# "start_freq": 6070000,
+# "start_mod": "am",
+# },
+# },
+# },
+# "sdrplay": {
+# "name": "SDRPlay RSP2",
+# "type": "sdrplay",
+# "ppm": 0,
+# "antenna": "Antenna A",
+# "profiles": {
+# "20m": {
+# "name": "20m",
+# "center_freq": 14150000,
+# "rf_gain": 0,
+# "samp_rate": 500000,
+# "start_freq": 14070000,
+# "start_mod": "usb",
+# },
+# "30m": {
+# "name": "30m",
+# "center_freq": 10125000,
+# "rf_gain": 0,
+# "samp_rate": 250000,
+# "start_freq": 10142000,
+# "start_mod": "usb",
+# },
+# "40m": {
+# "name": "40m",
+# "center_freq": 7100000,
+# "rf_gain": 0,
+# "samp_rate": 500000,
+# "start_freq": 7070000,
+# "start_mod": "lsb",
+# },
+# "80m": {
+# "name": "80m",
+# "center_freq": 3650000,
+# "rf_gain": 0,
+# "samp_rate": 500000,
+# "start_freq": 3570000,
+# "start_mod": "lsb",
+# },
+# "49m": {
+# "name": "49m Broadcast",
+# "center_freq": 6000000,
+# "rf_gain": 0,
+# "samp_rate": 500000,
+# "start_freq": 6070000,
+# "start_mod": "am",
+# },
+# },
+# },
+#}
# ==== Color themes ====
### google turbo colormap (see: https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html)
-waterfall_colors = [0x30123b, 0x311542, 0x33184a, 0x341b51, 0x351e58, 0x36215f, 0x372466, 0x38266c, 0x392973, 0x3a2c79, 0x3b2f80, 0x3c3286, 0x3d358b, 0x3e3891, 0x3e3a97, 0x3f3d9c, 0x4040a2, 0x4043a7, 0x4146ac, 0x4248b1, 0x424bb6, 0x434eba, 0x4351bf, 0x4453c3, 0x4456c7, 0x4559cb, 0x455bcf, 0x455ed3, 0x4561d7, 0x4663da, 0x4666dd, 0x4669e1, 0x466be4, 0x466ee7, 0x4671e9, 0x4673ec, 0x4676ee, 0x4678f1, 0x467bf3, 0x467df5, 0x4680f7, 0x4682f9, 0x4685fa, 0x4587fc, 0x458afd, 0x448cfe, 0x448ffe, 0x4391ff, 0x4294ff, 0x4196ff, 0x3f99ff, 0x3e9bff, 0x3d9efe, 0x3ba1fd, 0x3aa3fd, 0x38a6fb, 0x36a8fa, 0x35abf9, 0x33adf7, 0x31b0f6, 0x2fb2f4, 0x2db5f2, 0x2cb7f0, 0x2ab9ee, 0x28bcec, 0x26beea, 0x25c0e7, 0x23c3e5, 0x21c5e2, 0x20c7e0, 0x1fc9dd, 0x1dccdb, 0x1cced8, 0x1bd0d5, 0x1ad2d3, 0x19d4d0, 0x18d6cd, 0x18d8cb, 0x18dac8, 0x17dbc5, 0x17ddc3, 0x17dfc0, 0x18e0be, 0x18e2bb, 0x19e3b9, 0x1ae5b7, 0x1be6b4, 0x1de8b2, 0x1ee9af, 0x20eaad, 0x22ecaa, 0x24eda7, 0x27eea4, 0x29efa1, 0x2cf09e, 0x2ff19b, 0x32f298, 0x35f394, 0x38f491, 0x3cf58e, 0x3ff68b, 0x43f787, 0x46f884, 0x4af980, 0x4efa7d, 0x51fa79, 0x55fb76, 0x59fc73, 0x5dfc6f, 0x61fd6c, 0x65fd69, 0x69fe65, 0x6dfe62, 0x71fe5f, 0x75ff5c, 0x79ff59, 0x7dff56, 0x80ff53, 0x84ff50, 0x88ff4e, 0x8bff4b, 0x8fff49, 0x92ff46, 0x96ff44, 0x99ff42, 0x9cfe40, 0x9ffe3e, 0xa2fd3d, 0xa4fd3b, 0xa7fc3a, 0xaafc39, 0xacfb38, 0xaffa37, 0xb1f936, 0xb4f835, 0xb7f835, 0xb9f634, 0xbcf534, 0xbff434, 0xc1f334, 0xc4f233, 0xc6f033, 0xc9ef34, 0xcbee34, 0xceec34, 0xd0eb34, 0xd2e934, 0xd5e835, 0xd7e635, 0xd9e435, 0xdbe236, 0xdde136, 0xe0df37, 0xe2dd37, 0xe4db38, 0xe6d938, 0xe7d738, 0xe9d539, 0xebd339, 0xedd139, 0xeecf3a, 0xf0cd3a, 0xf1cb3a, 0xf3c93a, 0xf4c73a, 0xf5c53a, 0xf7c33a, 0xf8c13a, 0xf9bf39, 0xfabd39, 0xfaba38, 0xfbb838, 0xfcb637, 0xfcb436, 0xfdb135, 0xfdaf35, 0xfeac34, 0xfea933, 0xfea732, 0xfea431, 0xffa12f, 0xff9e2e, 0xff9c2d, 0xff992c, 0xfe962b, 0xfe932a, 0xfe9028, 0xfe8d27, 0xfd8a26, 0xfd8724, 0xfc8423, 0xfc8122, 0xfb7e20, 0xfb7b1f, 0xfa781e, 0xf9751c, 0xf8721b, 0xf86f1a, 0xf76c19, 0xf66917, 0xf56616, 0xf46315, 0xf36014, 0xf25d13, 0xf05b11, 0xef5810, 0xee550f, 0xed530e, 0xeb500e, 0xea4e0d, 0xe94b0c, 0xe7490b, 0xe6470a, 0xe4450a, 0xe34209, 0xe14009, 0xdf3e08, 0xde3c07, 0xdc3a07, 0xda3806, 0xd83606, 0xd63405, 0xd43205, 0xd23105, 0xd02f04, 0xce2d04, 0xcc2b03, 0xca2903, 0xc82803, 0xc62602, 0xc32402, 0xc12302, 0xbf2102, 0xbc1f01, 0xba1e01, 0xb71c01, 0xb41b01, 0xb21901, 0xaf1801, 0xac1601, 0xaa1501, 0xa71401, 0xa41201, 0xa11101, 0x9e1001, 0x9b0f01, 0x980d01, 0x950c01, 0x920b01, 0x8e0a01, 0x8b0901, 0x880801, 0x850701, 0x810602, 0x7e0502, 0x7a0402]
+#waterfall_scheme = "GoogleTurboWaterfall"
### original theme by teejez:
-#waterfall_colors = [0x000000, 0x0000FF, 0x00FFFF, 0x00FF00, 0xFFFF00, 0xFF0000, 0xFF00FF, 0xFFFFFF]
+#waterfall_scheme = "TeejeezWaterfall"
### old theme by HA7ILM:
-#waterfall_colors = [0x000000, 0x2e6893, 0x69a5d0, 0x214b69, 0x9dc4e0, 0xfff775, 0xff8a8a, 0xb20000]
-# waterfall_min_level = -115 #in dB
-# waterfall_max_level = 0
-# waterfall_auto_level_margin = {"min": 20, "max": 30}
+#waterfall_scheme = "Ha7ilmWaterfall"
##For the old colors, you might also want to set [fft_voverlap_factor] to 0.
-waterfall_min_level = -88 # in dB
-waterfall_max_level = -20
-waterfall_auto_level_margin = {"min": 3, "max": 10, "min_range": 50}
+### custom waterfall schemes can be configured like this:
+#waterfall_scheme = "CustomWaterfall"
+#waterfall_colors = [0x0000FF, 0x00FF00, 0xFF0000]
+
+### Waterfall calibration
+#waterfall_levels = {"min": -88, "max": -20} # in dB
+
+#waterfall_auto_levels = {"min": 3, "max": 10}
+#waterfall_auto_min_range = 50
# Note: When the auto waterfall level button is clicked, the following happens:
-# [waterfall_min_level] = [current_min_power_level] - [waterfall_auto_level_margin["min"]]
-# [waterfall_max_level] = [current_max_power_level] + [waterfall_auto_level_margin["max"]]
+# [waterfall_levels.min] = [current_min_power_level] - [waterfall_auto_levels["min"]]
+# [waterfall_levels.max] = [current_max_power_level] + [waterfall_auto_levels["max"]]
#
-# ___|________________________________________|____________________________________|________________________________________|___> signal power
-# \_waterfall_auto_level_margin["min"]_/ |__ current_min_power_level | \_waterfall_auto_level_margin["max"]_/
-# current_max_power_level __|
+# ___|__________________________________|____________________________________|__________________________________|___> signal power
+# \_waterfall_auto_levels["min"]_/ |__ current_min_power_level | \_waterfall_auto_levels["max"]_/
+# current_max_power_level __|
# This setting allows you to modify the precision of the frequency displays in OpenWebRX.
-# Set this to the number of digits you would like to see:
-frequency_display_precision = 4
+# Set this to exponent of 10 to select the most precise digit in Hz you'd like to see
+# examples:
+# a value of 2 selects 10^2 = 100Hz tuning precision (default):
+#tuning_precision = 2
+# a value of 1 selects 10^1 = 10Hz tuning precision:
+#tuning_precision = 1
# This setting tells the auto-squelch the offset to add to the current signal level to use as the new squelch level.
# Lowering this setting will give you a more sensitive squelch, but it may also cause unwanted squelch openings when
# using the auto squelch.
-squelch_auto_margin = 10 # in dB
+#squelch_auto_margin = 10 # in dB
-# === Experimental settings ===
-# Warning! The settings below are very experimental.
-csdr_dynamic_bufsize = False # This allows you to change the buffering mode of csdr.
-csdr_print_bufsizes = False # This prints the buffer sizes used for csdr processes.
-csdr_through = False # Setting this True will print out how much data is going into the DSP chains.
-
-nmux_memory = 50 # in megabytes. This sets the approximate size of the circular buffer used by nmux.
-
-google_maps_api_key = ""
+#google_maps_api_key = ""
# how long should positions be visible on the map?
# they will start fading out after half of that
# in seconds; default: 2 hours
-map_position_retention_time = 2 * 60 * 60
+#map_position_retention_time = 2 * 60 * 60
# decoder queue configuration
# due to the nature of some operating modes (ft8, ft8, jt9, jt65, wspr and js8), the data is recorded for a given amount
# of time (6 seconds up to 2 minutes) and decoded at the end. this can lead to very high peak loads.
# to mitigate this, the recordings will be queued and processed in sequence.
# the number of workers will limit the total amount of work (one worker will losely occupy one cpu / thread)
-decoding_queue_workers = 2
+#decoding_queue_workers = 2
# the maximum queue length will cause decodes to be dumped if the workers cannot keep up
# if you are running background services, make sure this number is high enough to accept the task influx during peaks
# i.e. this should be higher than the number of decoding services running at the same time
-decoding_queue_length = 10
+#decoding_queue_length = 10
# wsjt decoding depth will allow more results, but will also consume more cpu
-wsjt_decoding_depth = 3
+#wsjt_decoding_depth = 3
# can also be set for each mode separately
# jt65 seems to be somewhat prone to erroneous decodes, this setting handles that to some extent
-wsjt_decoding_depths = {"jt65": 1}
+#wsjt_decoding_depths = {"jt65": 1}
# FST4 can be transmitted in different intervals. This setting determines which intervals will be decoded.
# available values (in seconds): 15, 30, 60, 120, 300, 900, 1800
-fst4_enabled_intervals = [15, 30]
+#fst4_enabled_intervals = [15, 30]
# FST4W can be transmitted in different intervals. This setting determines which intervals will be decoded.
# available values (in seconds): 120, 300, 900, 1800
-fst4w_enabled_intervals = [120, 300]
+#fst4w_enabled_intervals = [120, 300]
+
+# Q65 allows many combinations of intervals and submodes. This setting determines which combinations will be decoded.
+# Please use the mode letter followed by the decode interval in seconds to specify the combinations. For example:
+#q65_enabled_combinations = ["A30", "E120", "C60"]
# JS8 comes in different speeds: normal, slow, fast, turbo. This setting controls which ones are enabled.
-js8_enabled_profiles = ["normal", "slow"]
+#js8_enabled_profiles = ["normal", "slow"]
# JS8 decoding depth; higher value will get more results, but will also consume more cpu
-js8_decoding_depth = 3
-
-temporary_directory = "/tmp"
+#js8_decoding_depth = 3
# Enable background service for decoding digital data. You can find more information at:
# https://github.com/jketterl/openwebrx/wiki/Background-decoding
-services_enabled = False
-services_decoders = ["ft8", "ft4", "wspr", "packet"]
+#services_enabled = False
+#services_decoders = ["ft8", "ft4", "wspr", "packet"]
# === aprs igate settings ===
# If you want to share your APRS decodes with the aprs network, configure these settings accordingly.
# Make sure that you have set services_enabled to true and customize services_decoders to your needs.
-aprs_callsign = "N0CALL"
-aprs_igate_enabled = False
-aprs_igate_server = "euro.aprs2.net"
-aprs_igate_password = ""
+#aprs_callsign = "N0CALL"
+#aprs_igate_enabled = False
+#aprs_igate_server = "euro.aprs2.net"
+#aprs_igate_password = ""
# beacon uses the receiver_gps setting, so if you enable this, make sure the location is correct there
-aprs_igate_beacon = False
-
-# path to the aprs symbols repository (get it here: https://github.com/hessu/aprs-symbols)
-aprs_symbols_path = "/usr/share/aprs-symbols/png"
+#aprs_igate_beacon = False
# Uncomment the following to customize gateway beacon details reported to the aprs network
# Plese see Dire Wolf's documentation on PBEACON configuration for complete details:
@@ -367,18 +377,13 @@ aprs_symbols_path = "/usr/share/aprs-symbols/png"
# === PSK Reporter settings ===
# enable this if you want to upload all ft8, ft4 etc spots to pskreporter.info
# this also uses the receiver_gps setting from above, so make sure it contains a correct locator
-pskreporter_enabled = False
-pskreporter_callsign = "N0CALL"
+#pskreporter_enabled = False
+#pskreporter_callsign = "N0CALL"
# optional antenna information, uncomment to enable
#pskreporter_antenna_information = "Dipole"
# === WSPRNet reporting settings
# enable this if you want to upload WSPR spots to wsprnet.ort
# in addition to these settings also make sure that receiver_gps contains your correct location
-wsprnet_enabled = False
-wsprnet_callsign = "N0CALL"
-
-# === Web admin settings ===
-# this feature is experimental at the moment. it should not be enabled on shared receivers since it allows remote
-# changes to the receiver settings. enable for testing in controlled environment only.
-# webadmin_enabled = False
+#wsprnet_enabled = False
+#wsprnet_callsign = "N0CALL"
diff --git a/csdr/csdr.py b/csdr/__init__.py
similarity index 83%
rename from csdr/csdr.py
rename to csdr/__init__.py
index 25b4fc18..aeb67e32 100644
--- a/csdr/csdr.py
+++ b/csdr/__init__.py
@@ -28,10 +28,10 @@ import threading
import math
from functools import partial
-from owrx.kiss import KissClient, DirewolfConfig
-from owrx.wsjt import Ft8Profile, WsprProfile, Jt9Profile, Jt65Profile, Ft4Profile, Fst4Profile, Fst4wProfile
-from owrx.js8 import Js8Profiles
-from owrx.audio import AudioChopper
+from csdr.output import Output
+
+from owrx.kiss import KissClient, DirewolfConfig, DirewolfConfigSubscriber
+from owrx.audio.chopper import AudioChopper
from csdr.pipe import Pipe
@@ -40,40 +40,8 @@ import logging
logger = logging.getLogger(__name__)
-class output(object):
- def send_output(self, t, read_fn):
- if not self.supports_type(t):
- # TODO rewrite the output mechanism in a way that avoids producing unnecessary data
- logger.warning("dumping output of type %s since it is not supported.", t)
- threading.Thread(target=self.pump(read_fn, lambda x: None), name="csdr_pump_thread").start()
- return
- self.receive_output(t, read_fn)
-
- def receive_output(self, t, read_fn):
- pass
-
- def pump(self, read, write):
- def copy():
- run = True
- while run:
- data = None
- try:
- data = read()
- except ValueError:
- pass
- if data is None or (isinstance(data, bytes) and len(data) == 0):
- run = False
- else:
- write(data)
-
- return copy
-
- def supports_type(self, t):
- return True
-
-
-class dsp(object):
- def __init__(self, output):
+class Dsp(DirewolfConfigSubscriber):
+ def __init__(self, output: Output):
self.pycsdr_enabled = True
self.pycsdr_chain = None
self.buffer = None
@@ -98,9 +66,6 @@ class dsp(object):
self.decimation = None
self.last_decimation = None
self.nc_port = None
- self.csdr_dynamic_bufsize = False
- self.csdr_print_bufsizes = False
- self.csdr_through = False
self.squelch_level = -150
self.fft_averages = 50
self.wfm_deemphasis_tau = 50e-6
@@ -124,6 +89,7 @@ class dsp(object):
self.secondary_pipe_names = {"secondary_shift_pipe": Pipe.WRITE}
self.secondary_offset_freq = 1000
self.unvoiced_quality = 1
+ self.codecserver = None
self.modification_lock = threading.Lock()
self.output = output
@@ -133,7 +99,7 @@ class dsp(object):
self.is_service = False
self.direwolf_config = None
- self.direwolf_port = None
+ self.direwolf_config_path = None
self.process = None
def setBuffer(self, buffer):
@@ -150,10 +116,6 @@ class dsp(object):
def chain(self, which):
chain = ["nc -v 127.0.0.1 {nc_port}"]
- if self.csdr_dynamic_bufsize:
- chain += ["csdr setbuf {start_bufsize}"]
- if self.csdr_through:
- chain += ["csdr through"]
chain += ["csdr shift_addfast_cc --fifo {shift_pipe}"]
if self.decimation > 1:
chain += ["csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING"]
@@ -199,43 +161,43 @@ class dsp(object):
elif self.isDigitalVoice(which):
chain += ["csdr fmdemod_quadri_cf"]
chain += last_decimation_block
- # dsd modes
- if which in ["dstar", "nxdn"]:
- chain += ["dc_block", "csdr limit_ff", "csdr convert_f_s16"]
- if which == "dstar":
- chain += ["dsd -fd -i - -o - -u {unvoiced_quality} -g -1 "]
- elif which == "nxdn":
- chain += ["dsd -fi -i - -o - -u {unvoiced_quality} -g -1 "]
- chain += [
- "digitalvoice_filter",
- "CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
- "sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
- ]
+ chain += ["dc_block"]
# m17
- elif which == "m17":
+ if which == "m17":
chain += [
"csdr limit_ff",
"csdr convert_f_s16",
"m17-demod",
- "CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
- "sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
]
- # digiham modes
else:
- chain += ["dc_block", "rrc_filter", "gfsk_demodulator"]
- if which == "dmr":
+ # digiham modes
+ if which == "dstar":
chain += [
- "dmr_decoder --fifo {meta_pipe} --control-fifo {dmr_control_pipe}",
- "mbe_synthesizer -f -u {unvoiced_quality}",
+ "fsk_demodulator -s 10",
+ "dstar_decoder --fifo {meta_pipe}",
+ "mbe_synthesizer -d {codecserver_arg}",
]
- elif which == "ysf":
- chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y -f -u {unvoiced_quality}"]
- max_gain = 0.005
- chain += [
- "digitalvoice_filter -f",
- "CSDR_FIXED_BUFSIZE=32 csdr agc_ff --max 0.005 --initial 0.0005",
- "sox -t raw -r 8000 -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
- ]
+ elif which == "nxdn":
+ chain += [
+ "rrc_filter --narrow",
+ "gfsk_demodulator --samples 20",
+ "nxdn_decoder --fifo {meta_pipe}",
+ "mbe_synthesizer {codecserver_arg}",
+ ]
+ else:
+ chain += ["rrc_filter", "gfsk_demodulator"]
+ if which == "dmr":
+ chain += [
+ "dmr_decoder --fifo {meta_pipe} --control-fifo {dmr_control_pipe}",
+ "mbe_synthesizer {codecserver_arg}",
+ ]
+ elif which == "ysf":
+ chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y {codecserver_arg}"]
+ chain += ["digitalvoice_filter"]
+ chain += [
+ "CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
+ "sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
+ ]
elif which == "am":
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
chain += last_decimation_block
@@ -377,14 +339,10 @@ class dsp(object):
if_samp_rate=self.if_samp_rate(),
last_decimation=self.last_decimation,
audio_rate=self.get_audio_rate(),
- direwolf_config=self.direwolf_config,
+ direwolf_config=self.direwolf_config_path,
)
logger.debug("secondary command (demod) = %s", secondary_command_demod)
- my_env = os.environ.copy()
- # if self.csdr_dynamic_bufsize: my_env["CSDR_DYNAMIC_BUFSIZE_ON"]="1";
- if self.csdr_print_bufsizes:
- my_env["CSDR_PRINT_BUFSIZES"] = "1"
if self.output.supports_type("secondary_fft"):
secondary_command_fft = " | ".join(self.secondary_chain("fft"))
secondary_command_fft = secondary_command_fft.format(
@@ -397,7 +355,7 @@ class dsp(object):
logger.debug("secondary command (fft) = %s", secondary_command_fft)
self.secondary_process_fft = subprocess.Popen(
- secondary_command_fft, stdout=subprocess.PIPE, shell=True, start_new_session=True, env=my_env
+ secondary_command_fft, stdout=subprocess.PIPE, shell=True, start_new_session=True
)
self.output.send_output(
"secondary_fft",
@@ -409,38 +367,18 @@ class dsp(object):
# it would block if not read. by piping it to devnull, we avoid a potential pitfall here.
secondary_output = subprocess.DEVNULL if self.isPacket() else subprocess.PIPE
self.secondary_process_demod = subprocess.Popen(
- secondary_command_demod, stdout=secondary_output, shell=True, start_new_session=True, env=my_env
+ secondary_command_demod, stdout=secondary_output, shell=True, start_new_session=True
)
self.secondary_processes_running = True
- if self.isWsjtMode():
- smd = self.get_secondary_demodulator()
- chopper_profiles = None
- if smd == "ft8":
- chopper_profiles = [Ft8Profile()]
- elif smd == "wspr":
- chopper_profiles = [WsprProfile()]
- elif smd == "jt65":
- chopper_profiles = [Jt65Profile()]
- elif smd == "jt9":
- chopper_profiles = [Jt9Profile()]
- elif smd == "ft4":
- chopper_profiles = [Ft4Profile()]
- elif smd == "fst4":
- chopper_profiles = Fst4Profile.getEnabledProfiles()
- elif smd == "fst4w":
- chopper_profiles = Fst4wProfile.getEnabledProfiles()
- if chopper_profiles is not None and len(chopper_profiles):
- chopper = AudioChopper(self, self.secondary_process_demod.stdout, *chopper_profiles)
- chopper.start()
- self.output.send_output("wsjt_demod", chopper.read)
- elif self.isJs8():
- chopper = AudioChopper(self, self.secondary_process_demod.stdout, *Js8Profiles.getEnabledProfiles())
- chopper.start()
- self.output.send_output("js8_demod", chopper.read)
+ if self.isWsjtMode() or self.isJs8():
+ chopper = AudioChopper(self, self.get_secondary_demodulator())
+ chopper.send_output("audio", self.secondary_process_demod.stdout.read)
+ output_type = "js8_demod" if self.isJs8() else "wsjt_demod"
+ self.output.send_output(output_type, chopper.read)
elif self.isPacket():
# we best get the ax25 packets from the kiss socket
- kiss = KissClient(self.direwolf_port)
+ kiss = KissClient(self.direwolf_config.getPort())
self.output.send_output("packet_demod", kiss.read)
elif self.isPocsag():
self.output.send_output("pocsag_demod", self.secondary_process_demod.stdout.readline)
@@ -487,11 +425,16 @@ class dsp(object):
return self.secondary_demodulator
def set_secondary_fft_size(self, secondary_fft_size):
- # to change this, restart is required
+ if self.secondary_fft_size == secondary_fft_size:
+ return
self.secondary_fft_size = secondary_fft_size
+ self.restart()
def set_audio_compression(self, what):
+ if self.audio_compression == what:
+ return
self.audio_compression = what
+ self.restart()
def get_audio_bytes_to_read(self):
# desired latency: 5ms
@@ -506,6 +449,7 @@ class dsp(object):
if self.fft_compression == what:
return
self.fft_compression = what
+ self.restart()
def get_secondary_fft_bytes_to_read(self):
if self.fft_compression == "none":
@@ -528,6 +472,8 @@ class dsp(object):
(self.decimation, self.last_decimation) = self.get_decimation(self.samp_rate, self.get_audio_rate())
def get_decimation(self, input_rate, output_rate):
+ if output_rate <= 0:
+ raise ValueError("invalid output rate: {rate}".format(rate=output_rate))
decimation = 1
target_rate = output_rate
# wideband fm has a much higher frequency deviation (75kHz).
@@ -571,7 +517,7 @@ class dsp(object):
def isWsjtMode(self, demodulator=None):
if demodulator is None:
demodulator = self.get_secondary_demodulator()
- return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w"]
+ return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]
def isJs8(self, demodulator=None):
if demodulator is None:
@@ -665,7 +611,7 @@ class dsp(object):
# no squelch required on digital voice modes
actual_squelch = (
-150
- if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV()
+ if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV() or self.isDrm()
else self.squelch_level
)
if self.running:
@@ -678,6 +624,15 @@ class dsp(object):
def get_unvoiced_quality(self):
return self.unvoiced_quality
+ def set_codecserver(self, s):
+ if self.codecserver == s:
+ return
+ self.codecserver = s
+ self.restart()
+
+ def get_codecserver_arg(self):
+ return "-s {}".format(self.codecserver) if self.codecserver else ""
+
def set_dmr_filter(self, filter):
if self.has_pipe("dmr_control_pipe"):
self.pipes["dmr_control_pipe"].write("{0}\n".format(filter))
@@ -718,27 +673,34 @@ class dsp(object):
def try_create_configs(self, command):
if "{direwolf_config}" in command:
- self.direwolf_config = "{tmp_dir}/openwebrx_direwolf_{myid}.conf".format(
+ self.direwolf_config_path = "{tmp_dir}/openwebrx_direwolf_{myid}.conf".format(
tmp_dir=self.temporary_directory, myid=id(self)
)
- self.direwolf_port = KissClient.getFreePort()
- file = open(self.direwolf_config, "w")
- file.write(DirewolfConfig().getConfig(self.direwolf_port, self.is_service))
+ self.direwolf_config = DirewolfConfig()
+ self.direwolf_config.wire(self)
+ file = open(self.direwolf_config_path, "w")
+ file.write(self.direwolf_config.getConfig(self.is_service))
file.close()
else:
self.direwolf_config = None
- self.direwolf_port = None
+ self.direwolf_config_path = None
def try_delete_configs(self):
- if self.direwolf_config:
+ if self.direwolf_config is not None:
+ self.direwolf_config.unwire(self)
+ self.direwolf_config = None
+ if self.direwolf_config_path is not None:
try:
- os.unlink(self.direwolf_config)
+ os.unlink(self.direwolf_config_path)
except FileNotFoundError:
# result suits our expectations. fine :)
pass
except Exception:
logger.exception("try_delete_configs()")
- self.direwolf_config = None
+ self.direwolf_config_path = None
+
+ def onConfigChanged(self):
+ self.restart()
def start(self):
with self.modification_lock:
@@ -781,19 +743,15 @@ class dsp(object):
output_rate=self.get_output_rate(),
smeter_report_every=int(self.if_samp_rate() / 6000),
unvoiced_quality=self.get_unvoiced_quality(),
+ codecserver_arg=self.get_codecserver_arg(),
audio_rate=self.get_audio_rate(),
wfm_deemphasis_tau=self.wfm_deemphasis_tau,
)
logger.debug("Command = %s", command)
- my_env = os.environ.copy()
- if self.csdr_dynamic_bufsize:
- my_env["CSDR_DYNAMIC_BUFSIZE_ON"] = "1"
- if self.csdr_print_bufsizes:
- my_env["CSDR_PRINT_BUFSIZES"] = "1"
out = subprocess.PIPE if self.output.supports_type("audio") else subprocess.DEVNULL
- self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True, env=my_env)
+ self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True)
def watch_thread():
rc = self.process.wait()
@@ -837,10 +795,6 @@ class dsp(object):
self.output.send_output("meta", read_meta)
- if self.csdr_dynamic_bufsize:
- self.process.stdout.read(8) # dummy read to skip bufsize & preamble
- logger.debug("Note: CSDR_DYNAMIC_BUFSIZE_ON = 1")
-
def stop(self):
with self.modification_lock:
self.running = False
@@ -859,6 +813,7 @@ class dsp(object):
self.stop_secondary_demodulator()
self.try_delete_pipes(self.pipe_names)
+ self.try_delete_configs()
def restart(self):
if not self.running:
diff --git a/csdr/output.py b/csdr/output.py
new file mode 100644
index 00000000..5fef242d
--- /dev/null
+++ b/csdr/output.py
@@ -0,0 +1,36 @@
+import threading
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class Output(object):
+ def send_output(self, t, read_fn):
+ if not self.supports_type(t):
+ # TODO rewrite the output mechanism in a way that avoids producing unnecessary data
+ logger.warning("dumping output of type %s since it is not supported.", t)
+ threading.Thread(target=self.pump(read_fn, lambda x: None), name="csdr_pump_thread").start()
+ return
+ self.receive_output(t, read_fn)
+
+ def receive_output(self, t, read_fn):
+ pass
+
+ def pump(self, read, write):
+ def copy():
+ run = True
+ while run:
+ data = None
+ try:
+ data = read()
+ except ValueError:
+ pass
+ if data is None or (isinstance(data, bytes) and len(data) == 0):
+ run = False
+ else:
+ write(data)
+
+ return copy
+
+ def supports_type(self, t):
+ return True
diff --git a/debian/changelog b/debian/changelog
index e1972360..f5684bc9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,21 +1,60 @@
-openwebrx (0.21.0) UNRELEASED; urgency=low
+openwebrx (1.1.0) UNRELEASED; urgency=low
+
+ * Reworked most graphical elements as SVGs for faster loadtimes and crispier
+ display on hi-dpi displays
+ * Updated pipelines to match changes in digiham
+ * Changed D-Star and NXDN integrations to use new decoder from digiham
+ * Added D-Star and NXDN metadata display
+
+ -- Jakob Ketterl Sun, 09 May 2021 14:05:00 +0000
+
+openwebrx (1.0.0) buster hirsute; urgency=low
* Introduced `squelch_auto_margin` config option that allows configuring the
auto squelch level
* Removed `port` configuration option; `rtltcp_compat` takes the port number
with the new connectors
- * Added support for new WSJT-X modes FST4 and FST4W (only available with
- WSJT-X 2.3)
+ * Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X
+ 2.3) and Q65 (only available with WSJT-X 2.4)
* Added support for demodulating M17 digital voice signals using
m17-cxx-demod
* New reporting infrastructure, allowing WSPR and FST4W spots to be sent to
wsprnet.org
* Add some basic filtering capabilities to the map
+ * New arguments to the `openwebrx` command-line to facilitate the
+ administration of users (try `openwebrx admin`)
+ * New command-line tool `openwebrx-admin` that facilitates the
+ administration of users
+ * Default bandwidth changes:
+ - "WFM" changed to 150kHz
+ - "Packet" (APRS) changed to 12.5kHz
+ * Configuration rework:
+ - New: fully web-based configuration interface
+ - System configuration parameters have been moved to a new, separate
+ `openwebrx.conf` file
+ - Remaining parameters are now editable in the web configuration
+ - Existing `config_webrx.py` files will still be read, but changes made in
+ the web configuration will be written to a new storage system
+ - Added upload of avatar and panorama image via web configuration
* New devices supported:
- - HPSDR devices (Hermes Lite 2) (`"type": "hpsdr"`)
- - BBRF103 / RX666 / RX888 devices supported by libsddc (`"type": "sddc"`)
- - Devices using the EB200 protocol (`"type": "eb200"`)
+ - HPSDR devices (Hermes Lite 2) thanks to @jancona
+ - BBRF103 / RX666 / RX888 devices supported by libsddc
+ - R&S devices using the EB200 or Ammos protocols
- -- Jakob Ketterl Sun, 11 Oct 2020 21:12:00 +0000
+ -- Jakob Ketterl Thu, 06 May 2021 17:22:00 +0000
+
+openwebrx (0.20.3) buster focal; urgency=low
+
+ * Fix a compatibility issue with python versions <= 3.6
+
+ -- Jakob Ketterl Tue, 26 Jan 2021 15:28:00 +0000
+
+openwebrx (0.20.2) buster focal; urgency=high
+
+ * Fix a security problem that allowed arbitrary commands to be executed on
+ the receiver (See github issue #215:
+ https://github.com/jketterl/openwebrx/issues/215)
+
+ -- Jakob Ketterl Sun, 24 Jan 2021 22:50:00 +0000
openwebrx (0.20.1) buster focal; urgency=low
diff --git a/debian/control b/debian/control
index 6654e6af..6b274bac 100644
--- a/debian/control
+++ b/debian/control
@@ -10,7 +10,7 @@ Vcs-Git: https://github.com/jketterl/openwebrx.git
Package: openwebrx
Architecture: all
-Depends: adduser, python3 (>= 3.5), python3-pkg-resources, csdr (>= 0.17), netcat, owrx-connector (>= 0.4), soapysdr-tools, python3-js8py (>= 0.1), ${python3:Depends}, ${misc:Depends}
-Recommends: digiham (>= 0.3), dsd (>= 1.7), sox, direwolf (>= 1.4), wsjtx, eb200-connector, hpsdrconnector, aprs-symbols, m17-demod
+Depends: adduser, python3 (>= 3.5), python3-pkg-resources, csdr (>= 0.17), netcat, owrx-connector (>= 0.5), soapysdr-tools, python3-js8py (>= 0.1), ${python3:Depends}, ${misc:Depends}
+Recommends: digiham (>= 0.5), sox, direwolf (>= 1.4), wsjtx, runds-connector (>= 0.2), hpsdrconnector, aprs-symbols, m17-demod, js8call
Description: multi-user web sdr
- Open source, multi-user SDR receiver with a web interface
\ No newline at end of file
+ Open source, multi-user SDR receiver with a web interface
diff --git a/debian/openwebrx.config b/debian/openwebrx.config
new file mode 100755
index 00000000..9a193930
--- /dev/null
+++ b/debian/openwebrx.config
@@ -0,0 +1,8 @@
+#!/bin/sh -e
+. /usr/share/debconf/confmodule
+
+db_get openwebrx/admin_user_configured
+if [ "${1:-}" = "reconfigure" ] || [ "${RET}" != true ]; then
+ db_input high openwebrx/admin_user_password || true
+ db_go
+fi
diff --git a/debian/openwebrx.dirs b/debian/openwebrx.dirs
new file mode 100644
index 00000000..c87b1b22
--- /dev/null
+++ b/debian/openwebrx.dirs
@@ -0,0 +1 @@
+/etc/openwebrx/openwebrx.conf.d
\ No newline at end of file
diff --git a/debian/openwebrx.install b/debian/openwebrx.install
index 84b1f9ce..8db93442 100644
--- a/debian/openwebrx.install
+++ b/debian/openwebrx.install
@@ -1,5 +1,3 @@
-config_webrx.py etc/openwebrx/
bands.json etc/openwebrx/
-bookmarks.json etc/openwebrx/
-users.json etc/openwebrx/
+openwebrx.conf etc/openwebrx/
systemd/openwebrx.service lib/systemd/system/
\ No newline at end of file
diff --git a/debian/openwebrx.postinst b/debian/openwebrx.postinst
new file mode 100755
index 00000000..935a0fe6
--- /dev/null
+++ b/debian/openwebrx.postinst
@@ -0,0 +1,59 @@
+#!/bin/bash
+. /usr/share/debconf/confmodule
+
+set -euo pipefail
+
+OWRX_USER="openwebrx"
+OWRX_DATADIR="/var/lib/openwebrx"
+OWRX_USERS_FILE="${OWRX_DATADIR}/users.json"
+OWRX_SETTINGS_FILE="${OWRX_DATADIR}/settings.json"
+OWRX_BOOKMARKS_FILE="${OWRX_DATADIR}/bookmarks.json"
+
+case "$1" in
+ configure|reconfigure)
+ adduser --system --group --no-create-home --home /nonexistent --quiet "${OWRX_USER}"
+ usermod -aG plugdev "${OWRX_USER}"
+
+ # create OpenWebRX data directory and set the correct permissions
+ if [ ! -d "${OWRX_DATADIR}" ] && [ ! -L "${OWRX_DATADIR}" ]; then mkdir "${OWRX_DATADIR}"; fi
+ chown "${OWRX_USER}". ${OWRX_DATADIR}
+
+ # create empty config files now to avoid permission problems later
+ if [ ! -e "${OWRX_USERS_FILE}" ]; then
+ echo "[]" > "${OWRX_USERS_FILE}"
+ chown "${OWRX_USER}". "${OWRX_USERS_FILE}"
+ chmod 0600 "${OWRX_USERS_FILE}"
+ fi
+
+ if [ ! -e "${OWRX_SETTINGS_FILE}" ]; then
+ echo "{}" > "${OWRX_SETTINGS_FILE}"
+ chown "${OWRX_USER}". "${OWRX_SETTINGS_FILE}"
+ fi
+
+ if [ ! -e "${OWRX_BOOKMARKS_FILE}" ]; then
+ touch "${OWRX_BOOKMARKS_FILE}"
+ chown "${OWRX_USER}". "${OWRX_BOOKMARKS_FILE}"
+ fi
+
+ db_get openwebrx/admin_user_password
+ if [ ! -z "${RET}" ]; then
+ if ! openwebrx admin --silent hasuser admin; then
+ # create initial openwebrx user
+ OWRX_PASSWORD="${RET}" openwebrx admin --noninteractive adduser admin
+ else
+ # change existing user's password
+ OWRX_PASSWORD="${RET}" openwebrx admin --noninteractive resetpassword admin
+ fi
+ fi
+ # remove password from debconf database
+ db_unregister openwebrx/admin_user_password
+ # set a marker that admin is configured to avoid future questions
+ db_set openwebrx/admin_user_configured true
+ ;;
+ *)
+ echo "postinst called with unknown argument '$1'" 1>&2
+ exit 1
+ ;;
+esac
+
+#DEBHELPER#
diff --git a/debian/openwebrx.postrm b/debian/openwebrx.postrm
new file mode 100755
index 00000000..9260b8ec
--- /dev/null
+++ b/debian/openwebrx.postrm
@@ -0,0 +1,8 @@
+#!/bin/sh -e
+
+if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
+ . /usr/share/debconf/confmodule
+ db_purge
+fi
+
+#DEBHELPER#
diff --git a/debian/openwebrx.templates b/debian/openwebrx.templates
new file mode 100644
index 00000000..8ef7e846
--- /dev/null
+++ b/debian/openwebrx.templates
@@ -0,0 +1,23 @@
+Template: openwebrx/admin_user_password
+Type: password
+Description: OpenWebRX "admin" user password:
+ The system can create a user for the OpenWebRX web configuration interface for
+ you. Using this user, you will be able to log into the "settings" area of
+ OpenWebRX to configure your receiver conveniently through your browser.
+ .
+ The name of the created user will be "admin".
+ .
+ If you do not wish to create a web admin user right now, you can leave this
+ empty for now. You can return to this prompt at a later time by running the
+ command "sudo dpkg-reconfigure openwebrx".
+ .
+ You can also use the "openwebrx admin" command to create, delete or manage
+ existing users. More information is available in by running the command
+ "openwebrx admin --help".
+
+Template: openwebrx/admin_user_configured
+Type: boolean
+Default: false
+Description: OpenWebRX "admin" user previously configured?
+ Marker used internally by the config scripts to remember if an admin user has
+ been created.
\ No newline at end of file
diff --git a/debian/postinst b/debian/postinst
deleted file mode 100755
index 423db2c8..00000000
--- a/debian/postinst
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-set -euxo pipefail
-
-adduser --system --group --no-create-home --home /nonexistent --quiet openwebrx
-usermod -aG plugdev openwebrx
-
-#DEBHELPER#
diff --git a/docker.sh b/docker.sh
index 1583af69..c2bfe7f1 100755
--- a/docker.sh
+++ b/docker.sh
@@ -2,10 +2,10 @@
set -euo pipefail
ARCH=$(uname -m)
-IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-redpitaya openwebrx-rtltcp openwebrx-eb200 openwebrx-hpsdr openwebrx-full openwebrx"
+IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-rtltcp openwebrx-runds openwebrx-hpsdr openwebrx-full openwebrx"
ALL_ARCHS="x86_64 armv7l aarch64"
TAG=${TAG:-"latest"}
-ARCHTAG="$TAG-$ARCH"
+ARCHTAG="${TAG}-${ARCH}"
usage () {
echo "Usage: ${0} [command]"
@@ -36,7 +36,7 @@ build () {
push () {
for image in ${IMAGES}; do
- docker push jketterl/$image:$ARCHTAG
+ docker push jketterl/${image}:${ARCHTAG}
done
}
@@ -45,11 +45,11 @@ manifest () {
# there's no docker manifest rm command, and the create --amend does not work, so we have to clean up manually
rm -rf "${HOME}/.docker/manifests/docker.io_jketterl_${image}-${TAG}"
IMAGE_LIST=""
- for a in $ALL_ARCHS; do
- IMAGE_LIST="$IMAGE_LIST jketterl/$image:$TAG-$a"
+ for a in ${ALL_ARCHS}; do
+ IMAGE_LIST="${IMAGE_LIST} jketterl/${image}:${TAG}-${a}"
done
- docker manifest create jketterl/$image:$TAG $IMAGE_LIST
- docker manifest push --purge jketterl/$image:$TAG
+ docker manifest create jketterl/${image}:${TAG} ${IMAGE_LIST}
+ docker manifest push --purge jketterl/${image}:${TAG}
done
}
diff --git a/docker/Dockerfiles/Dockerfile-base b/docker/Dockerfiles/Dockerfile-base
index c338dc0f..6fd184f5 100644
--- a/docker/Dockerfiles/Dockerfile-base
+++ b/docker/Dockerfiles/Dockerfile-base
@@ -13,12 +13,16 @@ COPY docker/scripts/install-owrx-tools.sh /
RUN /install-owrx-tools.sh && \
rm /install-owrx-tools.sh
+COPY docker/files/services/codecserver /etc/services.d/codecserver
+
ENTRYPOINT ["/init"]
WORKDIR /opt/openwebrx
VOLUME /etc/openwebrx
+VOLUME /var/lib/openwebrx
-CMD [ "/opt/openwebrx/docker/scripts/run.sh" ]
+ENV S6_CMD_ARG0="/opt/openwebrx/docker/scripts/run.sh"
+CMD []
EXPOSE 8073
diff --git a/docker/Dockerfiles/Dockerfile-full b/docker/Dockerfiles/Dockerfile-full
index b68d18ac..cecf45a4 100644
--- a/docker/Dockerfiles/Dockerfile-full
+++ b/docker/Dockerfiles/Dockerfile-full
@@ -18,10 +18,9 @@ RUN /install-dependencies-rtlsdr.sh &&\
/install-dependencies-fcdpp.sh &&\
/install-dependencies-radioberry.sh &&\
/install-dependencies-uhd.sh &&\
- /install-dependencies-redpitaya.sh &&\
/install-dependencies-hpsdr.sh &&\
/install-connectors.sh &&\
- /install-dependencies-eb200.sh &&\
+ /install-dependencies-runds.sh &&\
rm /install-dependencies-*.sh &&\
rm /install-lib.*.patch && \
rm /install-connectors.sh
diff --git a/docker/Dockerfiles/Dockerfile-redpitaya b/docker/Dockerfiles/Dockerfile-redpitaya
deleted file mode 100644
index 7d389aaa..00000000
--- a/docker/Dockerfiles/Dockerfile-redpitaya
+++ /dev/null
@@ -1,8 +0,0 @@
-ARG ARCHTAG
-FROM openwebrx-soapysdr-base:$ARCHTAG
-
-COPY docker/scripts/install-dependencies-redpitaya.sh /
-RUN /install-dependencies-redpitaya.sh &&\
- rm /install-dependencies-redpitaya.sh
-
-COPY . /opt/openwebrx
diff --git a/docker/Dockerfiles/Dockerfile-eb200 b/docker/Dockerfiles/Dockerfile-runds
similarity index 57%
rename from docker/Dockerfiles/Dockerfile-eb200
rename to docker/Dockerfiles/Dockerfile-runds
index f2f5181f..2a087e1f 100644
--- a/docker/Dockerfiles/Dockerfile-eb200
+++ b/docker/Dockerfiles/Dockerfile-runds
@@ -2,11 +2,11 @@ ARG ARCHTAG
FROM openwebrx-base:$ARCHTAG
COPY docker/scripts/install-connectors.sh \
- docker/scripts/install-dependencies-eb200.sh /
+ docker/scripts/install-dependencies-runds.sh /
RUN /install-connectors.sh &&\
rm /install-connectors.sh && \
- /install-dependencies-eb200.sh && \
- rm /install-dependencies-eb200.sh
+ /install-dependencies-runds.sh && \
+ rm /install-dependencies-runds.sh
COPY . /opt/openwebrx
diff --git a/docker/env b/docker/env
deleted file mode 100644
index f38dacdb..00000000
--- a/docker/env
+++ /dev/null
@@ -1,5 +0,0 @@
-ARCH=$(uname -m)
-IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-redpitaya openwebrx-rtltcp openwebrx-full openwebrx"
-ALL_ARCHS="x86_64 armv7l aarch64"
-TAG=${TAG:-"latest"}
-ARCHTAG="$TAG-$ARCH"
diff --git a/docker/files/services/codecserver/run b/docker/files/services/codecserver/run
new file mode 100755
index 00000000..43c8212c
--- /dev/null
+++ b/docker/files/services/codecserver/run
@@ -0,0 +1,2 @@
+#!/usr/bin/execlineb -P
+/usr/local/bin/codecserver
\ No newline at end of file
diff --git a/docker/files/wsjtx/wsjtx-hamlib.patch b/docker/files/wsjtx/wsjtx-hamlib.patch
index 09a8a882..47f37d93 100644
--- a/docker/files/wsjtx/wsjtx-hamlib.patch
+++ b/docker/files/wsjtx/wsjtx-hamlib.patch
@@ -1,18 +1,17 @@
---- CMakeLists.txt.orig 2020-07-21 20:59:55.982026645 +0200
-+++ CMakeLists.txt 2020-07-21 21:01:25.444836112 +0200
-@@ -80,24 +80,6 @@
+--- CMakeLists.txt.orig 2021-03-30 15:28:36.956587995 +0200
++++ CMakeLists.txt 2021-03-30 15:29:45.719326832 +0200
+@@ -106,24 +106,6 @@
- include (ExternalProject)
--
--#
+ #
-# build and install hamlib locally so it can be referenced by the
-# WSJT-X build
-#
-ExternalProject_Add (hamlib
- GIT_REPOSITORY ${hamlib_repo}
- GIT_TAG ${hamlib_TAG}
-- URL ${CMAKE_CURRENT_SOURCE_DIR}/src/${__hamlib_upstream}
+- GIT_SHALLOW False
+- URL ${CMAKE_CURRENT_SOURCE_DIR}/src/${__hamlib_upstream}.tar.gz
- URL_HASH MD5=${hamlib_md5sum}
- #UPDATE_COMMAND ${CMAKE_COMMAND} -E env "[ -f ./bootstrap ] && ./bootstrap"
- PATCH_COMMAND ${PATCH_EXECUTABLE} -p1 -N < ${CMAKE_CURRENT_SOURCE_DIR}/hamlib.patch
@@ -22,10 +21,11 @@
- STEP_TARGETS update install
- )
-
- #
+-#
# custom target to make a hamlib source tarball
#
-@@ -136,7 +118,6 @@
+ add_custom_target (hamlib_sources
+@@ -161,7 +143,6 @@
# build and optionally install WSJT-X using the hamlib package built
# above
#
@@ -33,11 +33,18 @@
ExternalProject_Add (wsjtx
GIT_REPOSITORY ${wsjtx_repo}
GIT_TAG ${WSJTX_TAG}
-@@ -160,7 +141,6 @@
+@@ -186,14 +167,8 @@
DEPENDEES build
)
-set_target_properties (hamlib PROPERTIES EXCLUDE_FROM_ALL 1)
set_target_properties (wsjtx PROPERTIES EXCLUDE_FROM_ALL 1)
- add_dependencies (wsjtx-configure hamlib-install)
+-add_dependencies (wsjtx-configure hamlib-install)
+-add_dependencies (wsjtx-build hamlib-install)
+-add_dependencies (wsjtx-install hamlib-install)
+-add_dependencies (wsjtx-package hamlib-install)
+-
+ # export traditional targets
+ add_custom_target (build ALL DEPENDS wsjtx-build)
+ add_custom_target (install DEPENDS wsjtx-install)
diff --git a/docker/files/wsjtx/wsjtx.patch b/docker/files/wsjtx/wsjtx.patch
index 59ac6b71..61ef53e3 100644
--- a/docker/files/wsjtx/wsjtx.patch
+++ b/docker/files/wsjtx/wsjtx.patch
@@ -1,6 +1,6 @@
diff -ur wsjtx-orig/CMake/Modules/Findhamlib.cmake wsjtx/CMake/Modules/Findhamlib.cmake
---- wsjtx-orig/CMake/Modules/Findhamlib.cmake 2020-07-21 21:10:43.124810140 +0200
-+++ wsjtx/CMake/Modules/Findhamlib.cmake 2020-07-21 21:11:03.368019114 +0200
+--- wsjtx-orig/CMake/Modules/Findhamlib.cmake 2021-05-31 18:56:20.657682124 +0200
++++ wsjtx/CMake/Modules/Findhamlib.cmake 2021-05-31 18:57:03.963994898 +0200
@@ -85,4 +85,4 @@
# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to
# TRUE if all listed variables are TRUE
@@ -8,9 +8,93 @@ diff -ur wsjtx-orig/CMake/Modules/Findhamlib.cmake wsjtx/CMake/Modules/Findhamli
-find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES hamlib_LIBRARY_DIRS)
+find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES)
diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
---- wsjtx-orig/CMakeLists.txt 2020-07-21 21:10:43.124810140 +0200
-+++ wsjtx/CMakeLists.txt 2020-07-21 22:14:04.454639589 +0200
-@@ -871,7 +871,7 @@
+--- wsjtx-orig/CMakeLists.txt 2021-05-31 18:56:20.657682124 +0200
++++ wsjtx/CMakeLists.txt 2021-05-31 19:08:02.768474060 +0200
+@@ -122,7 +122,7 @@
+ option (WSJT_QDEBUG_TO_FILE "Redirect Qt debuging messages to a trace file.")
+ option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients." ON)
+ option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
+-option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
++option (WSJT_GENERATE_DOCS "Generate documentation files.")
+ option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
+ option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
+ option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
+@@ -169,74 +169,7 @@
+ )
+
+ set (wsjt_qt_CXXSRCS
+- qt_helpers.cpp
+- widgets/MessageBox.cpp
+- MetaDataRegistry.cpp
+- Network/NetworkServerLookup.cpp
+ revision_utils.cpp
+- L10nLoader.cpp
+- WFPalette.cpp
+- Radio.cpp
+- RadioMetaType.cpp
+- NonInheritingProcess.cpp
+- models/IARURegions.cpp
+- models/Bands.cpp
+- models/Modes.cpp
+- models/FrequencyList.cpp
+- models/StationList.cpp
+- widgets/FrequencyLineEdit.cpp
+- widgets/FrequencyDeltaLineEdit.cpp
+- item_delegates/CandidateKeyFilter.cpp
+- item_delegates/ForeignKeyDelegate.cpp
+- validators/LiveFrequencyValidator.cpp
+- GetUserId.cpp
+- Audio/AudioDevice.cpp
+- Transceiver/Transceiver.cpp
+- Transceiver/TransceiverBase.cpp
+- Transceiver/EmulateSplitTransceiver.cpp
+- Transceiver/TransceiverFactory.cpp
+- Transceiver/PollingTransceiver.cpp
+- Transceiver/HamlibTransceiver.cpp
+- Transceiver/HRDTransceiver.cpp
+- Transceiver/DXLabSuiteCommanderTransceiver.cpp
+- Network/NetworkMessage.cpp
+- Network/MessageClient.cpp
+- widgets/LettersSpinBox.cpp
+- widgets/HintedSpinBox.cpp
+- widgets/RestrictedSpinBox.cpp
+- widgets/HelpTextWindow.cpp
+- SampleDownloader.cpp
+- SampleDownloader/DirectoryDelegate.cpp
+- SampleDownloader/Directory.cpp
+- SampleDownloader/FileNode.cpp
+- SampleDownloader/RemoteFile.cpp
+- DisplayManual.cpp
+- MultiSettings.cpp
+- validators/MaidenheadLocatorValidator.cpp
+- validators/CallsignValidator.cpp
+- widgets/SplashScreen.cpp
+- EqualizationToolsDialog.cpp
+- widgets/DoubleClickablePushButton.cpp
+- widgets/DoubleClickableRadioButton.cpp
+- Network/LotWUsers.cpp
+- models/DecodeHighlightingModel.cpp
+- widgets/DecodeHighlightingListView.cpp
+- models/FoxLog.cpp
+- widgets/AbstractLogWindow.cpp
+- widgets/FoxLogWindow.cpp
+- widgets/CabrilloLogWindow.cpp
+- item_delegates/CallsignDelegate.cpp
+- item_delegates/MaidenheadLocatorDelegate.cpp
+- item_delegates/FrequencyDelegate.cpp
+- item_delegates/FrequencyDeltaDelegate.cpp
+- item_delegates/SQLiteDateTimeDelegate.cpp
+- models/CabrilloLog.cpp
+- logbook/AD1CCty.cpp
+- logbook/WorkedBefore.cpp
+- logbook/Multiplier.cpp
+- Network/NetworkAccessManager.cpp
+- widgets/LazyFillComboBox.cpp
+- widgets/CheckableItemComboBox.cpp
+ )
+
+ set (wsjt_qtmm_CXXSRCS
+@@ -857,7 +790,7 @@
#
# libhamlib setup
#
@@ -19,31 +103,47 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
find_package (hamlib 3 REQUIRED)
find_program (RIGCTL_EXE rigctl)
find_program (RIGCTLD_EXE rigctld)
-@@ -1348,53 +1348,10 @@
+@@ -895,9 +828,6 @@
+ if (WSJT_GENERATE_DOCS)
+ add_subdirectory (doc)
+ endif (WSJT_GENERATE_DOCS)
+-if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests)
+- add_subdirectory (tests)
+-endif ()
- endif(WSJT_BUILD_UTILS)
+ #
+ # Library building setup
+@@ -1380,60 +1310,6 @@
+ target_link_libraries (jt9 wsjt_fort wsjt_cxx fort_qt)
+ endif (${OPENMP_FOUND} OR APPLE)
-# build the main application
+-generate_version_info (wsjtx_VERSION_RESOURCES
+- NAME wsjtx
+- BUNDLE ${PROJECT_BUNDLE_NAME}
+- ICON ${WSJTX_ICON_FILE}
+- )
+-
-add_executable (wsjtx MACOSX_BUNDLE
- ${wsjtx_CXXSRCS}
- ${wsjtx_GENUISRCS}
-- wsjtx.rc
- ${WSJTX_ICON_FILE}
- ${wsjtx_RESOURCES_RCC}
+- ${wsjtx_VERSION_RESOURCES}
- )
-
- if (WSJT_CREATE_WINMAIN)
- set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
- endif (WSJT_CREATE_WINMAIN)
-
+-if (WSJT_CREATE_WINMAIN)
+- set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
+-endif (WSJT_CREATE_WINMAIN)
+-
-set_target_properties (wsjtx PROPERTIES
- MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
-- MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}"
+- MACOSX_BUNDLE_INFO_STRING "${PROJECT_DESCRIPTION}"
- MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
-- MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION}
-- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}"
-- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}"
-- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}"
+- MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
+- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
+- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${SCS_VERSION_STR}"
+- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_BUNDLE_NAME}"
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
- MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
@@ -51,9 +151,9 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
-
-target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
-if (APPLE)
-- target_link_libraries (wsjtx Qt5::SerialPort wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
+- target_link_libraries (wsjtx wsjt_fort)
-else ()
-- target_link_libraries (wsjtx Qt5::SerialPort wsjt_fort_omp wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
+- target_link_libraries (wsjtx wsjt_fort_omp)
- if (OpenMP_C_FLAGS)
- set_target_properties (wsjtx PROPERTIES
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
@@ -65,18 +165,42 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
- )
- if (WIN32)
- set_target_properties (wsjtx PROPERTIES
-- LINK_FLAGS -Wl,--stack,16777216
+- LINK_FLAGS -Wl,--stack,0x1000000,--heap,0x20000000
- )
- endif ()
-endif ()
+-target_link_libraries (wsjtx Qt5::SerialPort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES} ${LIBM_LIBRARIES})
-
# make a library for WSJT-X UDP servers
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
-@@ -1437,24 +1394,9 @@
- set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
- endif (WSJT_CREATE_WINMAIN)
+@@ -1473,47 +1349,9 @@
+ add_executable (wsjtx_app_version AppVersion/AppVersion.cpp ${wsjtx_app_version_VERSION_RESOURCES})
+ target_link_libraries (wsjtx_app_version wsjt_qt)
+-generate_version_info (message_aggregator_VERSION_RESOURCES
+- NAME message_aggregator
+- BUNDLE ${PROJECT_BUNDLE_NAME}
+- ICON ${WSJTX_ICON_FILE}
+- FILE_DESCRIPTION "Example WSJT-X UDP Message Protocol application"
+- )
+-add_resources (message_aggregator_RESOURCES /qss ${message_aggregator_STYLESHEETS})
+-configure_file (UDPExamples/message_aggregator.qrc.in message_aggregator.qrc @ONLY)
+-qt5_add_resources (message_aggregator_RESOURCES_RCC
+- ${CMAKE_CURRENT_BINARY_DIR}/message_aggregator.qrc
+- contrib/QDarkStyleSheet/qdarkstyle/style.qrc
+- )
+-add_executable (message_aggregator
+- ${message_aggregator_CXXSRCS}
+- ${message_aggregator_RESOURCES_RCC}
+- ${message_aggregator_VERSION_RESOURCES}
+- )
+-target_link_libraries (message_aggregator wsjt_qt Qt5::Widgets wsjtx_udp-static)
+-
+-if (WSJT_CREATE_WINMAIN)
+- set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
+-endif (WSJT_CREATE_WINMAIN)
+-
-if (UNIX)
- if (NOT WSJT_SKIP_MANPAGES)
- add_subdirectory (manpages)
@@ -98,21 +222,21 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
# install (TARGETS wsjtx_udp EXPORT udp
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-@@ -1473,12 +1415,7 @@
+@@ -1532,12 +1370,7 @@
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
# )
--install (TARGETS udp_daemon message_aggregator
+-install (TARGETS udp_daemon message_aggregator wsjtx_app_version
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
- BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
- )
-
-install (TARGETS jt9 wsprd fmtave fcal fmeasure
-+install (TARGETS jt9 wsprd
++install (TARGETS wsjtx_app_version jt9 wsprd
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
)
-@@ -1491,39 +1428,6 @@
+@@ -1549,38 +1382,6 @@
)
endif(WSJT_BUILD_UTILS)
@@ -143,13 +267,50 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
- AUTHORS
- THANKS
- NEWS
-- INSTALL
- BUGS
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
- #COMPONENT runtime
- )
-
install (FILES
- contrib/Ephemeris/JPLEPH
- DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
-Only in wsjtx: .idea
+ cty.dat
+ cty.dat_copyright.txt
+@@ -1589,13 +1390,6 @@
+ #COMPONENT runtime
+ )
+
+-install (DIRECTORY
+- example_log_configurations
+- DESTINATION ${CMAKE_INSTALL_DOCDIR}
+- FILES_MATCHING REGEX "^.*[^~]$"
+- #COMPONENT runtime
+- )
+-
+ #
+ # Mac installer files
+ #
+@@ -1648,22 +1442,6 @@
+ )
+
+
+-if (NOT WIN32 AND NOT APPLE)
+- # install a desktop file so wsjtx appears in the application start
+- # menu with an icon
+- install (
+- FILES wsjtx.desktop message_aggregator.desktop
+- DESTINATION share/applications
+- #COMPONENT runtime
+- )
+- install (
+- FILES icons/Unix/wsjtx_icon.png
+- DESTINATION share/pixmaps
+- #COMPONENT runtime
+- )
+-endif (NOT WIN32 AND NOT APPLE)
+-
+-
+ #
+ # bundle fixup only done in non-Debug configurations
+ #
+Only in wsjtx/: CMakeLists.txt.orig
+Only in wsjtx/: .idea
diff --git a/docker/scripts/install-connectors.sh b/docker/scripts/install-connectors.sh
index be76988b..570b5c10 100755
--- a/docker/scripts/install-connectors.sh
+++ b/docker/scripts/install-connectors.sh
@@ -24,8 +24,8 @@ apt-get update
apt-get -y install --no-install-recommends $BUILD_PACKAGES
git clone https://github.com/jketterl/owrx_connector.git
-# latest develop as of 2020-11-28 (int32 samples; debhelper)
-cmakebuild owrx_connector 87a2fcc54e221aad71ec0700737ca7f385c388de
+# latest develop as of 2021-05-18 (individual connector versions)
+cmakebuild owrx_connector 167324219813f61b2be8164eb4acb1237ba2c304
apt-get -y purge --autoremove $BUILD_PACKAGES
apt-get clean
diff --git a/docker/scripts/install-dependencies-redpitaya.sh b/docker/scripts/install-dependencies-redpitaya.sh
deleted file mode 100755
index e88b5c8b..00000000
--- a/docker/scripts/install-dependencies-redpitaya.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-export MAKEFLAGS="-j4"
-
-function cmakebuild() {
- cd $1
- if [[ ! -z "${2:-}" ]]; then
- git checkout $2
- fi
- mkdir build
- cd build
- cmake ..
- make
- make install
- cd ../..
- rm -rf $1
-}
-
-cd /tmp
-
-STATIC_PACKAGES=""
-BUILD_PACKAGES="git cmake make gcc g++"
-
-apt-get update
-apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
-
-git clone https://github.com/pothosware/SoapyRedPitaya.git
-cmakebuild SoapyRedPitaya soapy-redpitaya-0.1.1
-
-SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
-apt-get clean
-rm -rf /var/lib/apt/lists/*
diff --git a/docker/scripts/install-dependencies-eb200.sh b/docker/scripts/install-dependencies-runds.sh
similarity index 71%
rename from docker/scripts/install-dependencies-eb200.sh
rename to docker/scripts/install-dependencies-runds.sh
index ce0aba16..711a4372 100755
--- a/docker/scripts/install-dependencies-eb200.sh
+++ b/docker/scripts/install-dependencies-runds.sh
@@ -24,9 +24,9 @@ BUILD_PACKAGES="git cmake make gcc g++ pkg-config"
apt-get update
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
-git clone https://github.com/jketterl/eb200_connector.git
-# latest from develop as of 2020-12-01
-cmakebuild eb200_connector 9c8313770c1072df72d2fdb85307ca206c29c60a
+git clone https://github.com/jketterl/runds_connector.git
+# latest develop as of 2021-05-18 (individual connector versions)
+cmakebuild runds_connector adfa04bee4ee36852feb07e7b845be2c3d3f97c7
apt-get -y purge --autoremove $BUILD_PACKAGES
apt-get clean
diff --git a/docker/scripts/install-dependencies-sdrplay.sh b/docker/scripts/install-dependencies-sdrplay.sh
index 23241f37..d91ec6ce 100755
--- a/docker/scripts/install-dependencies-sdrplay.sh
+++ b/docker/scripts/install-dependencies-sdrplay.sh
@@ -48,9 +48,9 @@ cd ..
rm -rf sdrplay
rm $BINARY
-git clone https://github.com/SDRplay/SoapySDRPlay.git
-# latest from master as of 2020-09-04
-cmakebuild SoapySDRPlay 105f8a6b3d449982d7ef860790c201aa066b8fa9
+git clone https://github.com/pothosware/SoapySDRPlay3.git
+# latest from master as of 2021-06-19 (reliability fixes)
+cmakebuild SoapySDRPlay3 a869f25364a1f0d5b16169ff908aa21a2ace475d
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
apt-get clean
diff --git a/docker/scripts/install-dependencies.sh b/docker/scripts/install-dependencies.sh
index 55a95e7c..bae8d910 100755
--- a/docker/scripts/install-dependencies.sh
+++ b/docker/scripts/install-dependencies.sh
@@ -18,8 +18,8 @@ function cmakebuild() {
cd /tmp
-STATIC_PACKAGES="sox libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline7 libgfortran4 libgomp1 libasound2 libudev1 ca-certificates libqt5gui5 libqt5sql5 libqt5printsupport5 libpulse0 libfaad2 libopus0 libboost-program-options1.67.0"
-BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-default libfaad-dev libopus-dev libgtest-dev libboost-dev libboost-program-options-dev"
+STATIC_PACKAGES="sox libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline7 libgfortran4 libgomp1 libasound2 libudev1 ca-certificates libqt5gui5 libqt5sql5 libqt5printsupport5 libpulse0 libfaad2 libopus0 libboost-program-options1.67.0 libboost-log1.67.0"
+BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-default libfaad-dev libopus-dev libgtest-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev"
apt-get update
apt-get -y install auto-apt-proxy
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
@@ -40,15 +40,6 @@ wget https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s
tar xzf s6-overlay-${PLATFORM}.tar.gz -C /
rm s6-overlay-${PLATFORM}.tar.gz
-git clone https://git.code.sf.net/p/itpp/git itpp
-cmakebuild itpp bb5c7e95f40e8fdb5c3f3d01a84bcbaf76f3676d
-
-git clone https://github.com/szechyjs/mbelib.git
-cmakebuild mbelib 9a04ed5c78176a9965f3d43f7aa1b1f5330e771f
-
-git clone https://github.com/f4exb/dsd.git
-cmakebuild dsd f6939f9edbbc6f66261833616391a4e59cb2b3d7
-
JS8CALL_VERSION=2.2.0
JS8CALL_DIR=js8call
JS8CALL_TGZ=js8call-${JS8CALL_VERSION}.tgz
@@ -60,7 +51,7 @@ rm /js8call-hamlib.patch
CMAKE_ARGS="-D CMAKE_CXX_FLAGS=-DJS8_USE_HAMLIB_THREE" cmakebuild ${JS8CALL_DIR}
rm ${JS8CALL_TGZ}
-WSJT_DIR=wsjtx-2.2.2
+WSJT_DIR=wsjtx-2.4.0
WSJT_TGZ=${WSJT_DIR}.tgz
wget http://physics.princeton.edu/pulsar/k1jt/${WSJT_TGZ}
tar xfz ${WSJT_TGZ}
@@ -111,12 +102,14 @@ rm -rf dream
rm dream-2.1.1-svn808.tar.gz
git clone https://github.com/mobilinkd/m17-cxx-demod.git
-# latest master as of 2020-12-27 (new sync words)
-cmakebuild m17-cxx-demod 2b84657676efb3b07b33de3ab3d0a6218e9d88b5
+# latest master as of 2021-04-20
+cmakebuild m17-cxx-demod c1d954fd5e5c53d28a2524e99484f832f9dcb826
git clone https://github.com/hessu/aprs-symbols /usr/share/aprs-symbols
pushd /usr/share/aprs-symbols
git checkout 5c2abe2658ee4d2563f3c73b90c6f59124839802
+# remove unused files (including git meta information)
+rm -rf .git aprs-symbols.ai aprs-sym-export.js
popd
apt-get -y purge --autoremove $BUILD_PACKAGES
diff --git a/docker/scripts/install-owrx-tools.sh b/docker/scripts/install-owrx-tools.sh
index 9018c373..3ae5afc8 100755
--- a/docker/scripts/install-owrx-tools.sh
+++ b/docker/scripts/install-owrx-tools.sh
@@ -18,8 +18,8 @@ function cmakebuild() {
cd /tmp
-STATIC_PACKAGES="libfftw3-bin"
-BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++"
+STATIC_PACKAGES="libfftw3-bin libprotobuf17"
+BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++ libprotobuf-dev protobuf-compiler"
apt-get update
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
@@ -40,8 +40,15 @@ make install
cd ..
rm -rf csdr
+git clone https://github.com/jketterl/codecserver.git
+mkdir -p /usr/local/etc/codecserver
+cp codecserver/conf/codecserver.conf /usr/local/etc/codecserver
+#latest develop as of 2021-07-04 (optional checksum fix)
+cmakebuild codecserver d73c9a56a773355679bc2d4a10f199b62223d7a0
+
git clone https://github.com/jketterl/digiham.git
-cmakebuild digiham 0.3.0
+#latest develop as of 2021-06-15 (DMR LCSS overflow fix; D-Star alternate terminator)
+cmakebuild digiham 418145d74b528596a39198a537ab56207d932595
apt-get -y purge --autoremove $BUILD_PACKAGES
apt-get clean
diff --git a/docker/scripts/run.sh b/docker/scripts/run.sh
index 0f8bd322..cde6fdf8 100755
--- a/docker/scripts/run.sh
+++ b/docker/scripts/run.sh
@@ -1,19 +1,25 @@
#!/bin/bash
set -euo pipefail
-mkdir -p /etc/openwebrx/
+mkdir -p /etc/openwebrx/openwebrx.conf.d
+mkdir -p /var/lib/openwebrx
mkdir -p /tmp/openwebrx/
-if [[ ! -f /etc/openwebrx/config_webrx.py ]] ; then
- sed 's/temporary_directory = "\/tmp"/temporary_directory = "\/tmp\/openwebrx"/' < "/opt/openwebrx/config_webrx.py" > "/etc/openwebrx/config_webrx.py"
+if [[ ! -f /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf ]] ; then
+ cat << EOF > /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf
+[core]
+temporary_directory = /tmp/openwebrx
+EOF
fi
if [[ ! -f /etc/openwebrx/bands.json ]] ; then
cp bands.json /etc/openwebrx/
fi
-if [[ ! -f /etc/openwebrx/bookmarks.json ]] ; then
- cp bookmarks.json /etc/openwebrx/
+if [[ ! -f /etc/openwebrx/openwebrx.conf ]] ; then
+ cp openwebrx.conf /etc/openwebrx/
fi
-if [[ ! -f /etc/openwebrx/users.json ]] ; then
- cp users.json /etc/openwebrx/
+if [[ ! -z "${OPENWEBRX_ADMIN_USER:-}" ]] && [[ ! -z "${OPENWEBRX_ADMIN_PASSWORD:-}" ]] ; then
+ if ! python3 openwebrx.py admin --silent hasuser "${OPENWEBRX_ADMIN_USER}" ; then
+ OWRX_PASSWORD="${OPENWEBRX_ADMIN_PASSWORD}" python3 openwebrx.py admin --noninteractive adduser "${OPENWEBRX_ADMIN_USER}"
+ fi
fi
diff --git a/htdocs/apple-touch-icon.png b/htdocs/apple-touch-icon.png
new file mode 100644
index 00000000..5bc3c155
Binary files /dev/null and b/htdocs/apple-touch-icon.png differ
diff --git a/htdocs/css/admin.css b/htdocs/css/admin.css
index b6ebcea8..b956e9e3 100644
--- a/htdocs/css/admin.css
+++ b/htdocs/css/admin.css
@@ -1,14 +1,162 @@
@import url("openwebrx-header.css");
@import url("openwebrx-globals.css");
+html, body {
+ height: unset;
+}
+
+body {
+ margin-bottom: 5rem;
+}
+
+hr {
+ background: #444;
+}
+
.buttons {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: #222;
+ z-index: 2;
+ padding: 10px;
text-align: right;
+ border-top: 1px solid #444;
}
.row .map-input {
margin: 15px 15px 0;
}
-.device {
- margin-top: 20px;
+.settings-section h3 {
+ margin-top: 1em;
+ margin-bottom: 1em;
}
+
+h1 {
+ margin: 1em 0;
+ text-align: center;
+}
+
+.matrix {
+ display: grid;
+}
+
+.q65-matrix {
+ grid-template-columns: repeat(5, auto);
+}
+
+.imageupload .image-container {
+ max-width: 100%;
+ padding: 7px;
+}
+
+.imageupload img.webrx-top-photo {
+ max-height: 350px;
+ max-width: 100%;
+}
+
+.settings-grid > div {
+ padding: 20px;
+}
+
+.settings-grid .btn {
+ width: 100%;
+ height: 100px;
+ padding: 20px;
+ font-size: 1.2rem;
+}
+
+.tab-body {
+ overflow: auto;
+ border: 1px solid #444;
+ border-top: none;
+ border-bottom-left-radius: 0.25rem;
+ border-bottom-right-radius: 0.25rem;
+}
+
+.tab-body .form-group {
+ padding-right: 15px;
+}
+
+.bookmarks table .frequency, .bookmark-list table .frequency {
+ text-align: right;
+}
+
+.bookmarks table input, .bookmarks table select {
+ width: initial;
+ text-align: inherit;
+ display: initial;
+}
+
+.bookmark-list table .form-check-input {
+ margin-left: 0;
+}
+
+.actions {
+ margin: 1rem 0;
+}
+
+.actions .btn {
+ width: 100%;
+}
+
+.wsjt-decoding-depths-table {
+ width: auto;
+ margin: 0;
+}
+
+.wsjt-decoding-depths-table td:first-child {
+ padding-left: 0;
+}
+
+.sdr-device-list .list-group-item,
+.sdr-profile-list .list-group-item {
+ background: initial;
+}
+
+.sdr-device-list .sdr-profile-list {
+ max-height: 20rem;
+ overflow-y: auto;
+}
+
+.removable-group.removable, .add-group {
+ display: flex;
+ flex-direction: row;
+}
+
+.removable-group.removable .removable-item, .add-group .add-group-select {
+ flex: 1 0 auto;
+ margin-right: .25rem;
+}
+
+.removable-group.removable .option-remove-button, .add-group .option-add-button {
+ flex: 0 0 70px;
+}
+
+.option-add-button, .option-remove-button {
+ width: 70px;
+}
+
+.scheduler-static-time-inputs {
+ display: flex;
+ flex-direction: row;
+}
+
+.scheduler-static-time-inputs > * {
+ flex: 0 0 auto;
+ width: unset;
+}
+
+.scheduler-static-time-inputs > select {
+ flex: 1 0 auto;
+}
+
+.breadcrumb {
+ margin-top: .5rem;
+}
+
+.imageupload.is-invalid ~ .invalid-feedback {
+ display: block;
+}
\ No newline at end of file
diff --git a/htdocs/css/features.css b/htdocs/css/features.css
deleted file mode 100644
index be41fef8..00000000
--- a/htdocs/css/features.css
+++ /dev/null
@@ -1,7 +0,0 @@
-@import url("openwebrx-header.css");
-@import url("openwebrx-globals.css");
-
-h1 {
- text-align: center;
- margin: 50px 0;
-}
diff --git a/htdocs/css/login.css b/htdocs/css/login.css
index 5e51dc9c..ccd6c026 100644
--- a/htdocs/css/login.css
+++ b/htdocs/css/login.css
@@ -1,6 +1,16 @@
@import url("openwebrx-header.css");
@import url("openwebrx-globals.css");
+body {
+ display: flex;
+ flex-direction: column;
+}
+
+.login-container {
+ flex: 1;
+ position: relative;
+}
+
.login {
position: absolute;
left: 50%;
diff --git a/htdocs/css/map.css b/htdocs/css/map.css
index 796f4422..70702b96 100644
--- a/htdocs/css/map.css
+++ b/htdocs/css/map.css
@@ -6,10 +6,6 @@ body {
flex-direction: column;
}
-#webrx-top-container {
- flex: none;
-}
-
.openwebrx-map {
flex: 1 1 auto;
}
diff --git a/htdocs/css/openwebrx-globals.css b/htdocs/css/openwebrx-globals.css
index 8417ffd3..57598477 100644
--- a/htdocs/css/openwebrx-globals.css
+++ b/htdocs/css/openwebrx-globals.css
@@ -5,21 +5,3 @@ html, body
height: 100%;
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
}
-
-.sprite {
- background-image: url(../gfx/openwebrx-sprites.png);
- display: inline-block;
-}
-
-.openwebrx-button.highlighted .sprite {
- background-image: linear-gradient(rgba(255,127,0,0.5), rgba(255,127,0,0.5)), url(../gfx/openwebrx-sprites.png);
- background-blend-mode: overlay;
-}
-
-@media only screen and (-webkit-min-device-pixel-ratio: 2),
-only screen and (min-device-pixel-ratio: 2) {
- .sprite {
- background-image: url(../gfx/openwebrx-sprites-2x.png);
- background-size: 198px 77px;
- }
-}
\ No newline at end of file
diff --git a/htdocs/css/openwebrx-header.css b/htdocs/css/openwebrx-header.css
index 83061f39..4e8601b7 100644
--- a/htdocs/css/openwebrx-header.css
+++ b/htdocs/css/openwebrx-header.css
@@ -1,4 +1,4 @@
-#webrx-top-container {
+.webrx-top-container {
position: relative;
z-index:1000;
background-color: #575757;
@@ -12,7 +12,7 @@
overflow: hidden;
}
-#openwebrx-description-container {
+.openwebrx-description-container {
transition-property: height, opacity;
transition-duration: 1s;
transition-timing-function: ease-out;
@@ -23,12 +23,12 @@
overflow: hidden;
}
-#openwebrx-description-container.expanded {
+.openwebrx-description-container.expanded {
opacity: 1;
height: 283px;
}
-.webrx-top-bar-parts {
+.webrx-top-bar {
height:67px;
background: rgba(128, 128, 128, 0.15);
@@ -46,26 +46,27 @@
flex-direction: row;
}
-.webrx-top-bar-parts > * {
+.webrx-top-bar > * {
flex: 0;
}
-#webrx-top-container, #webrx-top-container * {
+.webrx-top-container, .webrx-top-container * {
line-height: initial;
box-sizing: initial;
}
-#webrx-top-logo {
+.webrx-top-logo {
+ width: 261px;
padding: 12px;
+ filter: drop-shadow(0 0 2.5px rgba(0, 0, 0, .9));
/* overwritten by media queries */
display: none;
}
-#webrx-rx-avatar {
+.webrx-rx-avatar {
background-color: rgba(154, 154, 154, .5);
margin: 7px;
- cursor:pointer;
width: 46px;
height: 46px;
padding: 4px;
@@ -73,82 +74,66 @@
box-sizing: content-box;
}
-#webrx-rx-texts {
+.webrx-rx-texts {
/* minimum layout width */
width: 0;
/* will be getting wider with flex */
flex: 1;
overflow: hidden;
+ margin: auto 0;
}
-#webrx-rx-texts div {
+.webrx-rx-texts div, .webrx-rx-texts h1 {
margin: 0 10px;
padding: 3px;
white-space:nowrap;
overflow: hidden;
- cursor:pointer;
color: #909090;
+ text-align: left;
}
-#webrx-rx-texts div:first-child {
- margin-top: 10px;
-}
-
-#webrx-rx-title {
+.webrx-rx-title {
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
font-size: 11pt;
font-weight: bold;
}
-#webrx-rx-desc {
+.webrx-rx-desc {
font-size: 10pt;
}
-#openwebrx-rx-details-arrow {
- cursor:pointer;
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translate(-50%, 0);
-}
-
-#openwebrx-rx-details-arrow a {
- margin: 0;
- padding: 0;
- line-height: 0;
- display: block;
-}
-
-#openwebrx-main-buttons .button {
+.openwebrx-main-buttons .button {
display: block;
width: 55px;
cursor:pointer;
}
-#openwebrx-main-buttons .button[data-toggle-panel] {
+.openwebrx-main-buttons .button[data-toggle-panel] {
/* will be enabled by javascript if the panel is present in the DOM */
display: none;
}
-#openwebrx-main-buttons .button img {
+.openwebrx-main-buttons .button img,
+.openwebrx-main-buttons .button svg {
height: 38px;
+ filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.5));
}
-#openwebrx-main-buttons a {
+.openwebrx-main-buttons a {
color: inherit;
text-decoration: inherit;
}
-#openwebrx-main-buttons .button:hover {
+.openwebrx-main-buttons .button:hover {
background-color: rgba(255, 255, 255, 0.3);
}
-#openwebrx-main-buttons .button:active {
+.openwebrx-main-buttons .button:active {
background-color: rgba(255, 255, 255, 0.55);
}
-#openwebrx-main-buttons {
+.openwebrx-main-buttons {
padding: 5px 15px;
display: flex;
list-style: none;
@@ -160,7 +145,7 @@
font-weight: bold;
}
-#webrx-rx-photo-title {
+.webrx-rx-photo-title {
margin: 10px 15px;
color: white;
font-size: 16pt;
@@ -168,7 +153,7 @@
opacity: 1;
}
-#webrx-rx-photo-desc {
+.webrx-rx-photo-desc {
margin: 10px 15px;
color: white;
font-size: 10pt;
@@ -178,17 +163,21 @@
line-height: 1.5em;
}
-#webrx-rx-photo-desc a {
+.webrx-rx-photo-desc a {
color: #5ca8ff;
text-shadow: none;
}
+.openwebrx-photo-trigger {
+ cursor: pointer;
+}
+
/*
* Responsive stuff
*/
@media (min-width: 576px) {
- #webrx-rx-texts {
+ .webrx-rx-texts {
display: initial;
}
}
@@ -197,7 +186,7 @@
}
@media (min-width: 992px) {
- #webrx-top-logo {
+ .webrx-top-logo {
display: initial;
}
}
@@ -206,47 +195,33 @@
}
/*
- * Sprites (images)
+ * RX details arrow up/down switching
*/
-.sprite-panel-status {
- background-position: 0 0;
- width: 44px;
- height: 38px;
+.openwebrx-rx-details-arrow {
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translate(-50%, 0);
+
+ margin: 0;
+ padding: 0;
+ line-height: 0;
+ display: block;
}
-.sprite-panel-log {
- background-position: -44px 0;
- width: 38px;
- height: 38px;
-}
-
-.sprite-panel-receiver {
- background-position: -82px 0;
- width: 40px;
- height: 38px;
-}
-
-.sprite-panel-map {
- background-position: -122px 0;
- width: 38px;
- height: 38px;
-}
-
-.sprite-panel-settings {
- background-position: -160px 0;
- width: 38px;
- height: 38px;
-}
-
-.sprite-rx-details-arrow-down {
- background-position: 0 -65px;
- width: 43px;
+.openwebrx-rx-details-arrow svg {
height: 12px;
}
-.sprite-rx-details-arrow-up {
- background-position: -43px -65px;
- width: 43px;
- height: 12px;
+.openwebrx-rx-details-arrow .up {
+ display: none;
+}
+
+.openwebrx-rx-details-arrow--up .down {
+ display: none;
+}
+
+.openwebrx-rx-details-arrow--up .up {
+ display: initial;
}
\ No newline at end of file
diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css
index bb0bb396..cb1e9549 100644
--- a/htdocs/css/openwebrx.css
+++ b/htdocs/css/openwebrx.css
@@ -36,15 +36,14 @@ input
vertical-align:middle;
}
-input[type=range]
-{
+input[type=range] {
-webkit-appearance: none;
margin: 0 0;
- background: transparent;
+ background: transparent !important;
--track-background: #B6B6B6;
}
-input[type=range]:focus
-{
+
+input[type=range]:focus {
outline: none;
}
@@ -297,11 +296,13 @@ input[type=range]:disabled {
#webrx-canvas-container canvas
{
position: absolute;
+ top: 0;
border-style: none;
image-rendering: crisp-edges;
image-rendering: -webkit-optimize-contrast;
width: 100%;
height: 200px;
+ will-change: transform;
}
#openwebrx-log-scroll
@@ -336,12 +337,58 @@ input[type=range]:disabled {
margin: 0;
display: flex;
flex-direction: row;
+ cursor: pointer;
}
.webrx-actual-freq > * {
flex: 1;
}
+.webrx-actual-freq .input-group {
+ display: flex;
+ flex-direction: row;
+}
+
+.webrx-actual-freq .input-group > * {
+ flex: 0 0 auto;
+}
+
+.webrx-actual-freq .input-group input {
+ flex: 1 0 auto;
+ margin-right: 0;
+ border-right: 1px solid #373737;
+ -moz-appearance: textfield;
+}
+
+.webrx-actual-freq .input-group input::-webkit-outer-spin-button,
+.webrx-actual-freq .input-group input::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+.input-group > :not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.input-group > :not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.input-group :first-child {
+ padding-left: 5px;
+}
+
+.input-group :last-child {
+ padding-right: 5px
+}
+
+.webrx-actual-freq .input-group input, .webrx-actual-freq .input-group select {
+ outline: none;
+ font-size: 16pt;
+}
+
.webrx-actual-freq input {
font-family: 'roboto-mono';
width: 0;
@@ -355,7 +402,10 @@ input[type=range]:disabled {
.webrx-actual-freq, .webrx-actual-freq input {
font-size: 16pt;
font-family: 'roboto-mono';
- line-height: 22px;
+}
+
+.webrx-actual-freq .digit {
+ cursor: ns-resize;
}
.webrx-actual-freq .digit:hover {
@@ -552,6 +602,7 @@ img.openwebrx-mirror-img
-moz-user-select: none;
-ms-user-select: none;
overflow: hidden;
+ z-index: 1
}
.openwebrx-progressbar-bar {
@@ -564,6 +615,7 @@ img.openwebrx-mirror-img
transition-timing-function: ease-in-out;
transform: translate(-100%) translateZ(0);
will-change: transform, background-color;
+ z-index: 0;
}
.openwebrx-progressbar--over .openwebrx-progressbar-bar {
@@ -573,11 +625,11 @@ img.openwebrx-mirror-img
.openwebrx-progressbar-text
{
position: absolute;
- left:50;
+ left:50%;
top:50%;
transform: translate(-50%, -50%);
white-space: nowrap;
- z-index: 1;
+ z-index: 2;
}
#openwebrx-panel-status
@@ -602,6 +654,7 @@ img.openwebrx-mirror-img
#openwebrx-panel-receiver .frequencies-container {
display: flex;
flex-direction: row;
+ gap: 5px;
}
#openwebrx-panel-receiver .frequencies {
@@ -614,16 +667,6 @@ img.openwebrx-mirror-img
text-align: center;
}
-#openwebrx-mute-on
-{
- color: lime;
-}
-
-#openwebrx-mute-off
-{
- color: white;
-}
-
.openwebrx-panel-slider
{
position: relative;
@@ -631,13 +674,6 @@ img.openwebrx-mirror-img
width: 95px;
}
-.openwebrx-sliderbtn-img
-{
- width: 14px;
- position:relative;
- top: 1px;
-}
-
.openwebrx-panel-line
{
padding-top: 5px;
@@ -714,19 +750,19 @@ img.openwebrx-mirror-img
}
.openwebrx-overlay {
- position: fixed;
- width: 100%;
- height: 100%;
- margin: 0;
- padding: 0;
- opacity: 0.8;
- background-color: #777;
- left: 0;
- top: 0;
- z-index: 1001;
- color: white;
- font-weight: bold;
- font-size: 20pt;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ opacity: 0.8;
+ background-color: #777;
+ left: 0;
+ top: 0;
+ z-index: 1001;
+ color: white;
+ font-weight: bold;
+ font-size: 20pt;
}
#openwebrx-autoplay-overlay
@@ -735,8 +771,7 @@ img.openwebrx-mirror-img
transition: opacity 0.3s linear;
}
-#openwebrx-autoplay-overlay img
-{
+#openwebrx-autoplay-overlay svg {
width: 150px;
}
@@ -768,11 +803,14 @@ img.openwebrx-mirror-img
#openwebrx-digimode-canvas-container canvas
{
position: absolute;
+ top: 0;
pointer-events: none;
transition: width 500ms, left 500ms;
+ will-change: transform;
}
.openwebrx-panel select,
+.openwebrx-panel input,
.openwebrx-dialog select,
.openwebrx-dialog input {
border-radius: 5px;
@@ -781,11 +819,26 @@ img.openwebrx-mirror-img
font-weight: normal;
font-size: 13pt;
margin-right: 1px;
- background:-webkit-gradient( linear, left top, left bottom, color-stop(0.0 , #373737), color-stop(1, #4F4F4F) );
- background:-moz-linear-gradient( center top, #373737 0%, #4F4F4F 100% );
+ background:linear-gradient(#373737, #4F4F4F);
border-color: transparent;
border-width: 0px;
- -moz-appearance: none;
+}
+
+@supports(-moz-appearance: none) {
+ .openwebrx-panel select,
+ .openwebrx-dialog select {
+ -moz-appearance: none;
+ background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%20%20xmlns%3Av%3D%22https%3A%2F%2Fvecta.io%2Fnano%22%3E%3Cpath%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8s-1.9-9.2-5.5-12.8z%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E'),
+ linear-gradient(#373737, #4F4F4F);
+ background-repeat: no-repeat, repeat;
+ background-position: right .3em top 50%, 0 0;
+ background-size: .65em auto, 100%;
+ }
+
+ .openwebrx-panel .input-group select,
+ .openwebrx-dialog .input-group select {
+ padding-right: 1em;
+ }
}
.openwebrx-panel select option,
@@ -912,6 +965,8 @@ img.openwebrx-mirror-img
display: flex;
flex-direction: row;
gap: 10px;
+ /* compatibility with iOS 14.2 */
+ flex: 0 0 auto;
}
.openwebrx-meta-slot {
@@ -928,26 +983,22 @@ img.openwebrx-mirror-img
display: flex;
flex-direction: column;
position: relative;
+ overflow: hidden;
}
.openwebrx-meta-slot > * {
- flex: 0;
- flex-basis: 1.2em;
+ flex: 1 0 0;
line-height: 1.2em;
}
-.openwebrx-meta-slot, .openwebrx-meta-slot.muted:before {
+.openwebrx-meta-slot, .openwebrx-meta-slot .mute {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
-.openwebrx-meta-slot.muted:before {
- display: block;
- content: "";
- background-image: url("../gfx/openwebrx-mute.png");
- background-position: center;
- background-repeat: no-repeat;
+.openwebrx-meta-slot .mute {
+ display: none;
cursor: pointer;
position: absolute;
@@ -958,6 +1009,17 @@ img.openwebrx-mirror-img
background-color: rgba(0,0,0,.3);
}
+.openwebrx-meta-slot .mute svg {
+ position: absolute;
+ top: 50%;
+ left: 0;
+ transform: translate(0, -50%);
+}
+
+.openwebrx-meta-slot.muted .mute {
+ display: block;
+}
+
.openwebrx-meta-slot.active {
background-color: #95bbdf;
}
@@ -974,18 +1036,29 @@ img.openwebrx-mirror-img
}
.openwebrx-meta-slot .openwebrx-meta-user-image {
- flex: 1;
+ flex: 0 1 100%;
background-position: center;
background-repeat: no-repeat;
+ line-height: 0;
+ overflow: hidden;
}
-.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image,
-#openwebrx-panel-metadata-ysf .openwebrx-meta-slot.active .openwebrx-meta-user-image {
- background-image: url("../gfx/openwebrx-directcall.png");
+.openwebrx-meta-slot .openwebrx-meta-user-image img {
+ max-width: 100%;
+ max-height: 100%;
+ display: none;
}
-.openwebrx-meta-slot.active.group .openwebrx-meta-user-image {
- background-image: url("../gfx/openwebrx-groupcall.png");
+.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image .directcall,
+.openwebrx-meta-slot.active.individual .openwebrx-meta-user-image .directcall,
+#openwebrx-panel-metadata-ysf .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall,
+#openwebrx-panel-metadata-dstar .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall {
+ display: initial;
+}
+
+.openwebrx-meta-slot.active.group .openwebrx-meta-user-image .groupcall,
+.openwebrx-meta-slot.active.conference .openwebrx-meta-user-image .groupcall {
+ display: initial;
}
.openwebrx-meta-slot.group .openwebrx-dmr-target:not(:empty):before {
@@ -998,6 +1071,7 @@ img.openwebrx-mirror-img
.openwebrx-dmr-timeslot-panel * {
cursor: pointer;
+ user-select: none;
}
.openwebrx-ysf-mode:not(:empty):before {
@@ -1012,14 +1086,30 @@ img.openwebrx-mirror-img
content: "Down: ";
}
-.openwebrx-maps-pin {
- background-image: url("../gfx/google_maps_pin.svg");
- background-position: center;
- background-repeat: no-repeat;
+.openwebrx-dstar-yourcall:not(:empty):before {
+ content: "UR: ";
+}
+
+.openwebrx-dstar-departure:not(:empty):before {
+ content: "RPT1: ";
+}
+
+.openwebrx-dstar-destination:not(:empty):before {
+ content: "RPT2: ";
+}
+
+.openwebrx-meta-slot.individual .openwebrx-nxdn-destination:not(:empty):before {
+ content: "Direct: ";
+}
+
+.openwebrx-meta-slot.conference .openwebrx-nxdn-destination:not(:empty):before {
+ content: "Conference: ";
+}
+
+.openwebrx-maps-pin svg {
width: 15px;
height: 15px;
- background-size: contain;
- display: inline-block;
+ vertical-align: middle;
}
.openwebrx-message-panel {
@@ -1192,6 +1282,7 @@ img.openwebrx-mirror-img
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-content-container,
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-content-container,
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-content-container,
+#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-content-container,
#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel,
#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel,
#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-select-channel,
@@ -1201,7 +1292,8 @@ img.openwebrx-mirror-img
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-select-channel,
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-select-channel,
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-select-channel,
-#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-select-channel
+#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-select-channel,
+#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-select-channel
{
display: none;
}
@@ -1215,81 +1307,58 @@ img.openwebrx-mirror-img
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-canvas-container,
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-canvas-container,
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-canvas-container,
-#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-canvas-container
+#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-canvas-container,
+#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-canvas-container
{
height: 200px;
margin: -10px;
}
-.sprite-zoom-in {
- background-position: 0 -38px;
- width: 27px;
+.openwebrx-zoom-button svg {
height: 27px;
}
-.sprite-zoom-out {
- background-position: -27px -38px;
- width: 27px;
- height: 27px;
-}
-
-.sprite-zoom-in-total {
- background-position: -54px -38px;
- width: 24px;
- height: 27px;
-}
-
-.sprite-zoom-out-total {
- background-position: -78px -38px;
- width: 25px;
- height: 27px;
-}
-
-.sprite-edit {
- background-position: -131px -51px;
- width: 14px;
+.openwebrx-slider-button svg {
+ position:relative;
+ top: 1px;
height: 14px;
}
-.sprite-trashcan {
- background-position: -145px -38px;
- width: 14px;
+.openwebrx-mute-button svg.muted {
+ display: none;
+}
+
+.openwebrx-mute-button.muted svg.muted {
+ display: initial;
+}
+
+.openwebrx-mute-button.muted svg.unmuted {
+ display: none;
+}
+
+.bookmark .bookmark-actions .openwebrx-button svg {
height: 14px;
}
-.sprite-speaker {
- width: 14px;
- height: 15px;
+#openwebrx-waterfall-colors-auto .continuous {
+ display: none;
}
-.openwebrx-mute-button .sprite-speaker {
- background-position: -103px -38px;
+#openwebrx-waterfall-colors-auto.highlighted .continuous {
+ display: initial;
}
-.openwebrx-mute-button.muted .sprite-speaker {
- background-position: -117px -38px;
+#openwebrx-waterfall-colors-auto.highlighted .auto {
+ display: none;
}
-.sprite-squelch {
- background-position: -131px -38px;
- width: 14px;
- height: 13px;
+.openwebrx-waterfall-container {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ position: relative;
}
-.sprite-waterfall-auto {
- background-position: -103px -53px;
- width: 14px;
- height: 11px;
-}
-
-.sprite-waterfall-default {
- background-position: -117px -53px;
- width: 14px;
- height: 12px;
-}
-
-.sprite-bookmark {
- background-position: -159px -38px;
- width: 21px;
- height: 27px;
+.openwebrx-waterfall-container > * {
+ flex: 0 0 auto;
}
\ No newline at end of file
diff --git a/htdocs/favicon.ico b/htdocs/favicon.ico
index f8c9a2ae..6a07f1b1 100644
Binary files a/htdocs/favicon.ico and b/htdocs/favicon.ico differ
diff --git a/htdocs/features.html b/htdocs/features.html
index 90d156ea..53099b6d 100644
--- a/htdocs/features.html
+++ b/htdocs/features.html
@@ -3,7 +3,6 @@
-
@@ -11,6 +10,7 @@
${header}
+ ${breadcrumb}
OpenWebRX Feature Report
@@ -20,5 +20,6 @@
| Available |
+ ${breadcrumb}