From 26321ab68b3775e7646cb3ab9ef605e5947964b8 Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Sun, 26 Apr 2020 18:45:41 +0200 Subject: [PATCH] keep more parameters on the server side --- csdr/csdr.py | 2 + htdocs/css/openwebrx.css | 4 ++ htdocs/lib/Modes.js | 13 +++-- htdocs/openwebrx.js | 116 ++++++++++----------------------------- owrx/connection.py | 37 ++++++++----- owrx/modes.py | 57 ++++++++++++------- 6 files changed, 106 insertions(+), 123 deletions(-) diff --git a/csdr/csdr.py b/csdr/csdr.py index 8fe1606..57cd5cb 100644 --- a/csdr/csdr.py +++ b/csdr/csdr.py @@ -607,6 +607,8 @@ class dsp(object): self.restart() def set_demodulator(self, demodulator): + if demodulator in ["usb", "lsb", "cw"]: + demodulator = "ssb" if self.demodulator == demodulator: return self.demodulator = demodulator diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index b5693c8..731bac1 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -446,6 +446,10 @@ input[type=range]:focus::-ms-fill-upper margin-right: 5px; } +.openwebrx-demodulator-button.disabled { + color: #B6B6B6; +} + .openwebrx-square-button img { height: 27px; diff --git a/htdocs/lib/Modes.js b/htdocs/lib/Modes.js index e7b2597..bf258d1 100644 --- a/htdocs/lib/Modes.js +++ b/htdocs/lib/Modes.js @@ -15,9 +15,8 @@ var Modes = { }, updateModePanel:function() { var available = this.modes.filter(function(m){ return m.isAvailable(); }); - var normalModes = available.filter(function(m){ return !m.digimode; }); - var digiModes = available.filter(function(m){ return m.digimode; }); - + var normalModes = available.filter(function(m){ return m.type === 'analog'; }); + var digiModes = available.filter(function(m){ return m.type === 'digimode'; }); var html = [] @@ -63,8 +62,14 @@ var Modes = { var Mode = function(json){ this.modulation = json.modulation; this.name = json.name; - this.digimode = json.digimode; + this.type = json.type; this.requirements = json.requirements; + if (json.bandpass) { + this.bandpass = json.bandpass; + } + if (this.type === 'digimode') { + this.underlying = json.underlying; + } }; Mode.prototype.isAvailable = function(){ diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index cd08808..ea1b281 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -374,40 +374,10 @@ function Demodulator_default_analog(offset_frequency, subtype) { }; } }; - //Subtypes only define some filter parameters and the mod string sent to server, - //so you may set these parameters in your custom child class. - //Why? As of demodulation is done on the server, difference is mainly on the server side. - this.server_mod = subtype; - if (subtype === "lsb") { - this.low_cut = -3000; - this.high_cut = -300; - this.server_mod = "ssb"; - } - else if (subtype === "usb") { - this.low_cut = 300; - this.high_cut = 3000; - this.server_mod = "ssb"; - } - else if (subtype === "cw") { - this.low_cut = 700; - this.high_cut = 900; - this.server_mod = "ssb"; - } - else if (subtype === "nfm") { - this.low_cut = -4000; - this.high_cut = 4000; - } - else if (subtype === "dmr" || subtype === "ysf") { - this.low_cut = -4000; - this.high_cut = 4000; - } - else if (subtype === "dstar" || subtype === "nxdn") { - this.low_cut = -3250; - this.high_cut = 3250; - } - else if (subtype === "am") { - this.low_cut = -4000; - this.high_cut = 4000; + var mode = Modes.findByModulation(subtype); + if (mode) { + this.low_cut = mode.bandpass.low_cut; + this.high_cut = mode.bandpass.high_cut; } this.wait_for_timer = false; @@ -433,7 +403,7 @@ function Demodulator_default_analog(offset_frequency, subtype) { "high_cut": this.high_cut, "offset_freq": this.offset_frequency }; - if (first_time) params.mod = this.server_mod; + if (first_time) params.mod = this.subtype; ws.send(JSON.stringify({"type": "dspcontrol", "params": params})); mkenvelopes(get_visible_freq_range()); }; @@ -1174,6 +1144,7 @@ function on_ws_recv(evt) { break; case 'modes': Modes.setModes(json['value']); + demodulator_buttons_update(); break; default: console.warn('received message of unknown type: ' + json['type']); @@ -1947,29 +1918,24 @@ function initPanels() { } function demodulator_buttons_update() { - $(".openwebrx-demodulator-button").removeClass("highlighted"); + var $buttons = $(".openwebrx-demodulator-button"); + $buttons.removeClass("highlighted").removeClass('disabled'); if (!demodulators.length) return; + var mod = demodulators[0].subtype; + $("#openwebrx-button-" + mod).addClass("highlighted"); if (secondary_demod) { $("#openwebrx-button-dig").addClass("highlighted"); $('#openwebrx-secondary-demod-listbox').val(secondary_demod); - } else switch (demodulators[0].subtype) { - case "lsb": - case "usb": - case "cw": - if (demodulators[0].high_cut - demodulators[0].low_cut < 300) - $("#openwebrx-button-cw").addClass("highlighted"); - else { - if (demodulators[0].high_cut < 0) - $("#openwebrx-button-lsb").addClass("highlighted"); - else if (demodulators[0].low_cut > 0) - $("#openwebrx-button-usb").addClass("highlighted"); - else $("#openwebrx-button-lsb, #openwebrx-button-usb").addClass("highlighted"); - } - break; - default: - var mod = demodulators[0].subtype; - $("#openwebrx-button-" + mod).addClass("highlighted"); - break; + var mode = Modes.findByModulation(secondary_demod); + if (mode) { + var active = mode.underlying.map(function(u){ return 'openwebrx-button-' + u; }); + console.info(active); + $buttons.filter(function(){ + console.info(this.id); + console.info(active.indexOf(this.id)); + return this.id !== "openwebrx-button-dig" && active.indexOf(this.id) < 0; + }).addClass('disabled'); + } } } @@ -2013,41 +1979,19 @@ function demodulator_digital_replace_last() { function demodulator_digital_replace(subtype) { if (secondary_demod === subtype) return; var mode = Modes.findByModulation(subtype); - if (mode && !mode.isAvailable()) { + if (!mode) { + return; + } + if (!mode.isAvailable()) { divlog('Digital mode "' + mode.name + '" not supported. Please check requirements', true); return; } - switch (subtype) { - case "bpsk31": - case "bpsk63": - case "rtty": - case "ft8": - case "jt65": - case "jt9": - case "ft4": - case "js8": - secondary_demod_start(subtype); - demodulator_analog_replace('usb', true); - break; - case "wspr": - secondary_demod_start(subtype); - demodulator_analog_replace('usb', true); - // WSPR only samples between 1400 and 1600 Hz - demodulators[0].low_cut = 1350; - demodulators[0].high_cut = 1650; - demodulators[0].set(); - break; - case "packet": - secondary_demod_start(subtype); - demodulator_analog_replace('nfm', true); - break; - case "pocsag": - secondary_demod_start(subtype); - demodulator_analog_replace('nfm', true); - demodulators[0].low_cut = -6000; - demodulators[0].high_cut = 6000; - demodulators[0].set(); - break; + secondary_demod_start(subtype); + demodulator_analog_replace(mode.underlying[0], true); + if (mode.bandpass) { + demodulators[0].low_cut = mode.bandpass.low_cut; + demodulators[0].high_cut = mode.bandpass.high_cut; + demodulators[0].set(); } demodulator_buttons_update(); $('#openwebrx-panel-digimodes').attr('data-mode', subtype); diff --git a/owrx/connection.py b/owrx/connection.py index 3d54ee8..8deff4f 100644 --- a/owrx/connection.py +++ b/owrx/connection.py @@ -11,7 +11,7 @@ from owrx.bookmarks import Bookmarks from owrx.map import Map from owrx.locator import Locator from owrx.property import PropertyStack -from owrx.modes import Modes +from owrx.modes import Modes, DigitalMode from multiprocessing import Queue from queue import Full from js8py import Js8Frame @@ -114,18 +114,18 @@ class OpenWebRxReceiverClient(Client): receiver_info["locator"] = Locator.fromCoordinates(receiver_info["receiver_gps"]) self.write_receiver_details(receiver_info) - # TODO unsubscribe - receiver_details.wire(send_receiver_info) - send_receiver_info() - - self.__sendProfiles() - features = FeatureDetector().feature_availability() self.write_features(features) modes = Modes.getModes() self.write_modes(modes) + # TODO unsubscribe + receiver_details.wire(send_receiver_info) + send_receiver_info() + + self.__sendProfiles() + CpuUsageThread.getSharedInstance().add_client(self) def __sendProfiles(self): @@ -350,12 +350,23 @@ class OpenWebRxReceiverClient(Client): }}) def write_modes(self, modes): - self.send({"type": "modes", "value": [{ - "modulation": m.modulation, - "name": m.name, - "digimode": m.digimode, - "requirements": m.requirements - } for m in modes]}) + def to_json(m): + res = { + "modulation": m.modulation, + "name": m.name, + "type": "digimode" if isinstance(m, DigitalMode) else "analog", + "requirements": m.requirements + } + if m.bandpass is not None: + res["bandpass"] = { + "low_cut": m.bandpass.low_cut, + "high_cut": m.bandpass.high_cut + } + if isinstance(m, DigitalMode): + res["underlying"] = m.underlying + return res + + self.send({"type": "modes", "value": [to_json(m) for m in modes]}) class MapConnection(Client): diff --git a/owrx/modes.py b/owrx/modes.py index d2d890a..80fe94b 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -2,13 +2,19 @@ from owrx.feature import FeatureDetector from functools import reduce +class Bandpass(object): + def __init__(self, low_cut, high_cut): + self.low_cut = low_cut + self.high_cut = high_cut + + class Mode(object): - def __init__(self, modulation, name, requirements=None, service=False, digimode=False): + def __init__(self, modulation, name, bandpass: Bandpass = None, requirements=None, service=False): self.modulation = modulation self.name = name - self.digimode = digimode self.requirements = requirements if requirements is not None else [] self.service = service + self.bandpass = bandpass def is_available(self): fd = FeatureDetector() @@ -20,26 +26,37 @@ class Mode(object): return self.service +class AnalogMode(Mode): + pass + + +class DigitalMode(Mode): + def __init__(self, modulation, name, underlying, bandpass: Bandpass = None, requirements=None, service=False): + super().__init__(modulation, name, bandpass, requirements, service) + self.underlying = underlying + + class Modes(object): mappings = [ - Mode("nfm", "FM"), - Mode("am", "AM"), - Mode("lsb", "LSB"), - Mode("usb", "USB"), - Mode("cw", "CW"), - Mode("dmr", "DMR", requirements=["digital_voice_digiham"]), - Mode("dstar", "DStar", requirements=["digital_voice_dsd"]), - Mode("nxdn", "NXDN", requirements=["digital_voice_dsd"]), - Mode("ysf", "YSF", requirements=["digital_voice_digiham"]), - Mode("bpsk31", "BPSK31", digimode=True), - Mode("bpsk63", "BPSK63", digimode=True), - Mode("ft8", "FT8", requirements=["wsjt-x"], service=True, digimode=True), - Mode("ft4", "FT4", requirements=["wsjt-x"], service=True, digimode=True), - Mode("jt65", "JT65", requirements=["wsjt-x"], service=True, digimode=True), - Mode("jt9", "JT9", requirements=["wsjt-x"], service=True, digimode=True), - Mode("wspr", "WSPR", requirements=["wsjt-x"], service=True, digimode=True), - Mode("packet", "Packet", ["packet"], service=True, digimode=True), - Mode("js8", "JS8Call", requirements=["js8call"], service=True, digimode=True), + AnalogMode("nfm", "FM", bandpass=Bandpass(-4000, 4000)), + AnalogMode("am", "AM", bandpass=Bandpass(-4000, 4000)), + 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"]), + 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("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"]) ] @staticmethod