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]