From beed0c1a70a09b307569effe5ced917f24408d1e Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Sun, 3 May 2020 19:55:48 +0200 Subject: [PATCH] improve squelch handling squelch is now included in the URL hash some modes now have the squelch visually disabled, refs #65 --- htdocs/css/openwebrx.css | 8 +++++ htdocs/index.html | 4 +-- htdocs/lib/Demodulator.js | 11 +++++- htdocs/lib/DemodulatorPanel.js | 61 +++++++++++++++++++++++++++++----- htdocs/lib/Modes.js | 1 + htdocs/openwebrx.js | 21 ++---------- owrx/connection.py | 3 +- owrx/modes.py | 40 ++++++++++++++-------- 8 files changed, 104 insertions(+), 45 deletions(-) diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index 981bf9c..dbc0f14 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -150,6 +150,10 @@ input[type=range]:focus::-ms-fill-upper background: #B6B6B6; } +input[type=range]:disabled { + opacity: 0.5; +} + #webrx-page-container { height: 100%; @@ -435,6 +439,10 @@ input[type=range]:focus::-ms-fill-upper margin-right: 0; } +.openwebrx-button.disabled { + opacity: 0.5; +} + .openwebrx-demodulator-button { width: 38px; diff --git a/htdocs/index.html b/htdocs/index.html index 07b9fcc..abff134 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -165,8 +165,8 @@
-
- +
+
diff --git a/htdocs/lib/Demodulator.js b/htdocs/lib/Demodulator.js index 1683ada..1c47560 100644 --- a/htdocs/lib/Demodulator.js +++ b/htdocs/lib/Demodulator.js @@ -194,7 +194,8 @@ function Demodulator(offset_frequency, modulation) { this.high_cut = mode.bandpass.high_cut; } this.listeners = { - "frequencychange": [] + "frequencychange": [], + "squelchchange": [] }; } @@ -293,8 +294,16 @@ Demodulator.prototype.set = function () { //this function sends demodulator par }; Demodulator.prototype.setSquelch = function(squelch) { + if (this.squelch_level == squelch) { + return; + } this.squelch_level = squelch; this.set(); + this.emit("squelchchange", squelch); +}; + +Demodulator.prototype.getSquelch = function() { + return this.squelch_level; }; Demodulator.prototype.setDmrFilter = function(dmr_filter) { diff --git a/htdocs/lib/DemodulatorPanel.js b/htdocs/lib/DemodulatorPanel.js index b4c2c07..8a92f2a 100644 --- a/htdocs/lib/DemodulatorPanel.js +++ b/htdocs/lib/DemodulatorPanel.js @@ -27,6 +27,14 @@ function DemodulatorPanel(el) { self.setMode(value); } }); + el.on('click', '.openwebrx-squelch-default', function() { + if (!self.squelchAvailable()) return; + el.find('.openwebrx-squelch-slider').val(getLogSmeterValue(smeter_level) + 10); + self.updateSquelch(); + }); + el.on('change', '.openwebrx-squelch-slider', function() { + self.updateSquelch(); + }); window.addEventListener('hashchange', function() { self.onHashChange(); }); @@ -95,18 +103,27 @@ DemodulatorPanel.prototype.setMode = function(modulation) { modulation = mode.underlying[0]; } - var current_offset_frequency = 0; + var current = this.collectParams(); if (this.demodulator) { - current_offset_frequency = this.demodulator.get_offset_frequency(); + current.offset_frequency = this.demodulator.get_offset_frequency(); + current.squelch_level = this.demodulator.getSquelch(); } this.stopDemodulator(); - this.demodulator = new Demodulator(current_offset_frequency, modulation); + this.demodulator = new Demodulator(current.offset_frequency, modulation); + this.demodulator.setSquelch(current.squelch_level); var self = this; this.demodulator.on("frequencychange", function(freq) { self.tuneableFrequencyDisplay.setFrequency(self.center_freq + freq); self.updateHash(); }); + updateSquelch = function(squelch) { + self.el.find('.openwebrx-squelch-slider').val(squelch); + self.updateHash(); + }; + this.demodulator.on('squelchchange', updateSquelch); + updateSquelch(this.demodulator.getSquelch()); + if (mode.type === 'digimode') { this.demodulator.set_secondary_demod(mode.modulation); if (mode.bandpass) { @@ -149,9 +166,18 @@ DemodulatorPanel.prototype.getDemodulator = function() { return this.demodulator; }; +DemodulatorPanel.prototype.collectParams = function() { + var defaults = { + offset_frequency: 0, + squelch_level: -150, + mod: 'nfm' + } + return $.extend(new Object(), defaults, this.initialParams || {}, this.transformHashParams(this.parseHash())); +}; + DemodulatorPanel.prototype.startDemodulator = function() { if (!Modes.initComplete()) return; - var params = $.extend({}, this.initialParams || {}, this.transformHashParams(this.parseHash())); + var params = this.collectParams(); this._apply(params); }; @@ -167,6 +193,7 @@ DemodulatorPanel.prototype.stopDemodulator = function() { DemodulatorPanel.prototype._apply = function(params) { this.setMode(params.mod); this.getDemodulator().set_offset_frequency(params.offset_frequency); + this.getDemodulator().setSquelch(params.squelch_level); this.updateButtons(); }; @@ -179,12 +206,18 @@ DemodulatorPanel.prototype.onHashChange = function() { }; DemodulatorPanel.prototype.transformHashParams = function(params) { - return { - mod: params.secondary_mod || params.mod, - offset_frequency: params.offset_frequency + var ret = { + mod: params.secondary_mod || params.mod }; + if (params.offset_frequency) ret.offset_frequency = params.offset_frequency; + if (params.sql) ret.squelch_level = parseInt(params.sql); + return ret; }; +DemodulatorPanel.prototype.squelchAvailable = function () { + return this.mode && this.mode.squelch; +} + DemodulatorPanel.prototype.updateButtons = function() { var $buttons = this.el.find(".openwebrx-demodulator-button"); $buttons.removeClass("highlighted").removeClass('disabled'); @@ -205,6 +238,9 @@ DemodulatorPanel.prototype.updateButtons = function() { } else { this.el.find('.openwebrx-secondary-demod-listbox').val('none'); } + var squelch_disabled = !this.squelchAvailable(); + this.el.find('.openwebrx-squelch-slider').prop('disabled', squelch_disabled); + this.el.find('.openwebrx-squelch-default')[squelch_disabled ? 'addClass' : 'removeClass']('disabled'); } DemodulatorPanel.prototype.setCenterFrequency = function(center_freq) { @@ -234,7 +270,7 @@ DemodulatorPanel.prototype.parseHash = function() { DemodulatorPanel.prototype.validateHash = function(params) { var self = this; params = Object.keys(params).filter(function(key) { - if (key == 'freq' || key == 'mod' || key == 'secondary_mod') { + if (key == 'freq' || key == 'mod' || key == 'secondary_mod' || key == 'sql') { return params.freq && Math.abs(params.freq - self.center_freq) < bandwidth; } return true; @@ -258,7 +294,8 @@ DemodulatorPanel.prototype.updateHash = function() { window.location.hash = $.map({ freq: demod.get_offset_frequency() + self.center_freq, mod: demod.get_modulation(), - secondary_mod: demod.get_secondary_demod() + secondary_mod: demod.get_secondary_demod(), + sql: demod.getSquelch(), }, function(value, key){ if (!value) return undefined; return key + '=' + value; @@ -267,6 +304,12 @@ DemodulatorPanel.prototype.updateHash = function() { }).join(','); }; +DemodulatorPanel.prototype.updateSquelch = function() { + var sliderValue = parseInt(this.el.find(".openwebrx-squelch-slider").val()); + var demod = this.getDemodulator(); + if (demod) demod.setSquelch(sliderValue); +}; + $.fn.demodulatorPanel = function(){ if (!this.data('panel')) { this.data('panel', new DemodulatorPanel(this)); diff --git a/htdocs/lib/Modes.js b/htdocs/lib/Modes.js index c12ff23..a33cf4f 100644 --- a/htdocs/lib/Modes.js +++ b/htdocs/lib/Modes.js @@ -36,6 +36,7 @@ var Mode = function(json){ this.name = json.name; this.type = json.type; this.requirements = json.requirements; + this.squelch = json.squelch; if (json.bandpass) { this.bandpass = json.bandpass; } diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index 2e41038..7b32731 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -103,14 +103,12 @@ function toggleMute() { e("openwebrx-mute-on").id = "openwebrx-mute-off"; e("openwebrx-mute-img").src = "static/gfx/openwebrx-speaker.png"; e("openwebrx-panel-volume").disabled = false; - e("openwebrx-panel-volume").style.opacity = 1.0; e("openwebrx-panel-volume").value = volumeBeforeMute; } else { mute = true; e("openwebrx-mute-off").id = "openwebrx-mute-on"; e("openwebrx-mute-img").src = "static/gfx/openwebrx-speaker-muted.png"; e("openwebrx-panel-volume").disabled = true; - e("openwebrx-panel-volume").style.opacity = 0.5; volumeBeforeMute = e("openwebrx-panel-volume").value; e("openwebrx-panel-volume").value = 0; } @@ -134,17 +132,6 @@ function zoomOutTotal() { zoom_set(0); } -function setSquelchToAuto() { - e("openwebrx-panel-squelch").value = (getLogSmeterValue(smeter_level) + 10).toString(); - updateSquelch(); -} - -function updateSquelch() { - var sliderValue = parseInt($("#openwebrx-panel-squelch").val()); - var demod = $('#openwebrx-panel-receiver').demodulatorPanel().getDemodulator(); - if (demod) demod.setSquelch(sliderValue); -} - var waterfall_min_level; var waterfall_max_level; var waterfall_min_level_default; @@ -189,7 +176,7 @@ function setSmeterRelativeValue(value) { } function setSquelchSliderBackground(val) { - var $slider = $('#openwebrx-panel-squelch'); + var $slider = $('#openwebrx-panel-receiver .openwebrx-squelch-slider'); var min = Number($slider.attr('min')); var max = Number($slider.attr('max')); var sliderPosition = $slider.val(); @@ -740,7 +727,8 @@ function on_ws_recv(evt) { var initial_demodulator_params = { mod: config['start_mod'], - offset_frequency: config['start_offset_freq'] + offset_frequency: config['start_offset_freq'], + squelch_level: Number.isInteger(config['initial_squelch_level']) ? config['initial_squelch_level'] : -150 }; bandwidth = config['samp_rate']; @@ -752,9 +740,6 @@ function on_ws_recv(evt) { fft_compression = config['fft_compression']; divlog("FFT stream is " + ((fft_compression === "adpcm") ? "compressed" : "uncompressed") + "."); clientProgressBar.setMaxClients(config['max_clients']); - var sql = Number.isInteger(config['initial_squelch_level']) ? config['initial_squelch_level'] : -150; - $("#openwebrx-panel-squelch").val(sql); - updateSquelch(); waterfall_init(); var demodulatorPanel = $('#openwebrx-panel-receiver').demodulatorPanel(); diff --git a/owrx/connection.py b/owrx/connection.py index 9fbc088..1f15031 100644 --- a/owrx/connection.py +++ b/owrx/connection.py @@ -353,7 +353,8 @@ class OpenWebRxReceiverClient(Client): "modulation": m.modulation, "name": m.name, "type": "digimode" if isinstance(m, DigitalMode) else "analog", - "requirements": m.requirements + "requirements": m.requirements, + "squelch": m.squelch, } if m.bandpass is not None: res["bandpass"] = { diff --git a/owrx/modes.py b/owrx/modes.py index 7617b5f..f455268 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -9,18 +9,17 @@ class Bandpass(object): class Mode(object): - def __init__(self, modulation, name, bandpass: Bandpass = None, requirements=None, service=False): + def __init__(self, modulation, name, bandpass: Bandpass = None, requirements=None, service=False, squelch=True): self.modulation = modulation self.name = name self.requirements = requirements if requirements is not None else [] self.service = service self.bandpass = bandpass + self.squelch = squelch def is_available(self): fd = FeatureDetector() - return reduce( - lambda a, b: a and b, [fd.is_available(r) for r in self.requirements], True - ) + return reduce(lambda a, b: a and b, [fd.is_available(r) for r in self.requirements], True) def is_service(self): return self.service @@ -31,8 +30,10 @@ class AnalogMode(Mode): class DigitalMode(Mode): - def __init__(self, modulation, name, underlying, bandpass: Bandpass = None, requirements=None, service=False): - super().__init__(modulation, name, bandpass, requirements, service) + def __init__( + self, modulation, name, underlying, bandpass: Bandpass = None, requirements=None, service=False, squelch=True + ): + super().__init__(modulation, name, bandpass, requirements, service, squelch) self.underlying = underlying @@ -43,20 +44,31 @@ class Modes(object): AnalogMode("lsb", "LSB", bandpass=Bandpass(-3000, -300)), AnalogMode("usb", "USB", bandpass=Bandpass(300, 3000)), AnalogMode("cw", "CW", bandpass=Bandpass(700, 900)), - AnalogMode("dmr", "DMR", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"]), - AnalogMode("dstar", "DStar", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"]), - AnalogMode("nxdn", "NXDN", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"]), - AnalogMode("ysf", "YSF", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"]), + AnalogMode("dmr", "DMR", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"], squelch=False), + AnalogMode("dstar", "DStar", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"], squelch=False), + AnalogMode("nxdn", "NXDN", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"], squelch=False), + AnalogMode("ysf", "YSF", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"], squelch=False), DigitalMode("bpsk31", "BPSK31", underlying=["usb"]), DigitalMode("bpsk63", "BPSK63", underlying=["usb"]), DigitalMode("ft8", "FT8", underlying=["usb"], requirements=["wsjt-x"], service=True), DigitalMode("ft4", "FT4", underlying=["usb"], requirements=["wsjt-x"], service=True), DigitalMode("jt65", "JT65", underlying=["usb"], requirements=["wsjt-x"], service=True), DigitalMode("jt9", "JT9", underlying=["usb"], requirements=["wsjt-x"], service=True), - DigitalMode("wspr", "WSPR", underlying=["usb"], bandpass=Bandpass(1350, 1650), requirements=["wsjt-x"], service=True), + DigitalMode( + "wspr", "WSPR", underlying=["usb"], bandpass=Bandpass(1350, 1650), requirements=["wsjt-x"], service=True + ), DigitalMode("js8", "JS8Call", underlying=["usb"], requirements=["js8call"], service=True), - DigitalMode("packet", "Packet", underlying=["nfm", "usb", "lsb"], requirements=["packet"], service=True), - DigitalMode("pocsag", "Pocsag", underlying=["nfm"], bandpass=Bandpass(-6000, 6000), requirements=["pocsag"]) + DigitalMode( + "packet", "Packet", underlying=["nfm", "usb", "lsb"], requirements=["packet"], service=True, squelch=False + ), + DigitalMode( + "pocsag", + "Pocsag", + underlying=["nfm"], + bandpass=Bandpass(-6000, 6000), + requirements=["pocsag"], + squelch=False, + ), ] @staticmethod @@ -75,4 +87,4 @@ class Modes(object): def findByModulation(modulation): modes = [m for m in Modes.getAvailableModes() if m.modulation == modulation] if modes: - return modes[0] \ No newline at end of file + return modes[0]