keep more parameters on the server side

This commit is contained in:
Jakob Ketterl 2020-04-26 18:45:41 +02:00
parent 449b3b3986
commit 26321ab68b
6 changed files with 106 additions and 123 deletions

View File

@ -607,6 +607,8 @@ class dsp(object):
self.restart() self.restart()
def set_demodulator(self, demodulator): def set_demodulator(self, demodulator):
if demodulator in ["usb", "lsb", "cw"]:
demodulator = "ssb"
if self.demodulator == demodulator: if self.demodulator == demodulator:
return return
self.demodulator = demodulator self.demodulator = demodulator

View File

@ -446,6 +446,10 @@ input[type=range]:focus::-ms-fill-upper
margin-right: 5px; margin-right: 5px;
} }
.openwebrx-demodulator-button.disabled {
color: #B6B6B6;
}
.openwebrx-square-button img .openwebrx-square-button img
{ {
height: 27px; height: 27px;

View File

@ -15,9 +15,8 @@ var Modes = {
}, },
updateModePanel:function() { updateModePanel:function() {
var available = this.modes.filter(function(m){ return m.isAvailable(); }); var available = this.modes.filter(function(m){ return m.isAvailable(); });
var normalModes = 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.digimode; }); var digiModes = available.filter(function(m){ return m.type === 'digimode'; });
var html = [] var html = []
@ -63,8 +62,14 @@ var Modes = {
var Mode = function(json){ var Mode = function(json){
this.modulation = json.modulation; this.modulation = json.modulation;
this.name = json.name; this.name = json.name;
this.digimode = json.digimode; this.type = json.type;
this.requirements = json.requirements; this.requirements = json.requirements;
if (json.bandpass) {
this.bandpass = json.bandpass;
}
if (this.type === 'digimode') {
this.underlying = json.underlying;
}
}; };
Mode.prototype.isAvailable = function(){ Mode.prototype.isAvailable = function(){

View File

@ -374,40 +374,10 @@ function Demodulator_default_analog(offset_frequency, subtype) {
}; };
} }
}; };
//Subtypes only define some filter parameters and the mod string sent to server, var mode = Modes.findByModulation(subtype);
//so you may set these parameters in your custom child class. if (mode) {
//Why? As of demodulation is done on the server, difference is mainly on the server side. this.low_cut = mode.bandpass.low_cut;
this.server_mod = subtype; this.high_cut = mode.bandpass.high_cut;
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;
} }
this.wait_for_timer = false; this.wait_for_timer = false;
@ -433,7 +403,7 @@ function Demodulator_default_analog(offset_frequency, subtype) {
"high_cut": this.high_cut, "high_cut": this.high_cut,
"offset_freq": this.offset_frequency "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})); ws.send(JSON.stringify({"type": "dspcontrol", "params": params}));
mkenvelopes(get_visible_freq_range()); mkenvelopes(get_visible_freq_range());
}; };
@ -1174,6 +1144,7 @@ function on_ws_recv(evt) {
break; break;
case 'modes': case 'modes':
Modes.setModes(json['value']); Modes.setModes(json['value']);
demodulator_buttons_update();
break; break;
default: default:
console.warn('received message of unknown type: ' + json['type']); console.warn('received message of unknown type: ' + json['type']);
@ -1947,29 +1918,24 @@ function initPanels() {
} }
function demodulator_buttons_update() { function demodulator_buttons_update() {
$(".openwebrx-demodulator-button").removeClass("highlighted"); var $buttons = $(".openwebrx-demodulator-button");
$buttons.removeClass("highlighted").removeClass('disabled');
if (!demodulators.length) return; if (!demodulators.length) return;
var mod = demodulators[0].subtype;
$("#openwebrx-button-" + mod).addClass("highlighted");
if (secondary_demod) { if (secondary_demod) {
$("#openwebrx-button-dig").addClass("highlighted"); $("#openwebrx-button-dig").addClass("highlighted");
$('#openwebrx-secondary-demod-listbox').val(secondary_demod); $('#openwebrx-secondary-demod-listbox').val(secondary_demod);
} else switch (demodulators[0].subtype) { var mode = Modes.findByModulation(secondary_demod);
case "lsb": if (mode) {
case "usb": var active = mode.underlying.map(function(u){ return 'openwebrx-button-' + u; });
case "cw": console.info(active);
if (demodulators[0].high_cut - demodulators[0].low_cut < 300) $buttons.filter(function(){
$("#openwebrx-button-cw").addClass("highlighted"); console.info(this.id);
else { console.info(active.indexOf(this.id));
if (demodulators[0].high_cut < 0) return this.id !== "openwebrx-button-dig" && active.indexOf(this.id) < 0;
$("#openwebrx-button-lsb").addClass("highlighted"); }).addClass('disabled');
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;
} }
} }
@ -2013,41 +1979,19 @@ function demodulator_digital_replace_last() {
function demodulator_digital_replace(subtype) { function demodulator_digital_replace(subtype) {
if (secondary_demod === subtype) return; if (secondary_demod === subtype) return;
var mode = Modes.findByModulation(subtype); 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); divlog('Digital mode "' + mode.name + '" not supported. Please check requirements', true);
return; return;
} }
switch (subtype) {
case "bpsk31":
case "bpsk63":
case "rtty":
case "ft8":
case "jt65":
case "jt9":
case "ft4":
case "js8":
secondary_demod_start(subtype); secondary_demod_start(subtype);
demodulator_analog_replace('usb', true); demodulator_analog_replace(mode.underlying[0], true);
break; if (mode.bandpass) {
case "wspr": demodulators[0].low_cut = mode.bandpass.low_cut;
secondary_demod_start(subtype); demodulators[0].high_cut = mode.bandpass.high_cut;
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(); 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;
} }
demodulator_buttons_update(); demodulator_buttons_update();
$('#openwebrx-panel-digimodes').attr('data-mode', subtype); $('#openwebrx-panel-digimodes').attr('data-mode', subtype);

View File

@ -11,7 +11,7 @@ from owrx.bookmarks import Bookmarks
from owrx.map import Map from owrx.map import Map
from owrx.locator import Locator from owrx.locator import Locator
from owrx.property import PropertyStack from owrx.property import PropertyStack
from owrx.modes import Modes from owrx.modes import Modes, DigitalMode
from multiprocessing import Queue from multiprocessing import Queue
from queue import Full from queue import Full
from js8py import Js8Frame from js8py import Js8Frame
@ -114,18 +114,18 @@ class OpenWebRxReceiverClient(Client):
receiver_info["locator"] = Locator.fromCoordinates(receiver_info["receiver_gps"]) receiver_info["locator"] = Locator.fromCoordinates(receiver_info["receiver_gps"])
self.write_receiver_details(receiver_info) self.write_receiver_details(receiver_info)
# TODO unsubscribe
receiver_details.wire(send_receiver_info)
send_receiver_info()
self.__sendProfiles()
features = FeatureDetector().feature_availability() features = FeatureDetector().feature_availability()
self.write_features(features) self.write_features(features)
modes = Modes.getModes() modes = Modes.getModes()
self.write_modes(modes) self.write_modes(modes)
# TODO unsubscribe
receiver_details.wire(send_receiver_info)
send_receiver_info()
self.__sendProfiles()
CpuUsageThread.getSharedInstance().add_client(self) CpuUsageThread.getSharedInstance().add_client(self)
def __sendProfiles(self): def __sendProfiles(self):
@ -350,12 +350,23 @@ class OpenWebRxReceiverClient(Client):
}}) }})
def write_modes(self, modes): def write_modes(self, modes):
self.send({"type": "modes", "value": [{ def to_json(m):
res = {
"modulation": m.modulation, "modulation": m.modulation,
"name": m.name, "name": m.name,
"digimode": m.digimode, "type": "digimode" if isinstance(m, DigitalMode) else "analog",
"requirements": m.requirements "requirements": m.requirements
} for m in modes]}) }
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): class MapConnection(Client):

View File

@ -2,13 +2,19 @@ from owrx.feature import FeatureDetector
from functools import reduce 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): 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.modulation = modulation
self.name = name self.name = name
self.digimode = digimode
self.requirements = requirements if requirements is not None else [] self.requirements = requirements if requirements is not None else []
self.service = service self.service = service
self.bandpass = bandpass
def is_available(self): def is_available(self):
fd = FeatureDetector() fd = FeatureDetector()
@ -20,26 +26,37 @@ class Mode(object):
return self.service 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): class Modes(object):
mappings = [ mappings = [
Mode("nfm", "FM"), AnalogMode("nfm", "FM", bandpass=Bandpass(-4000, 4000)),
Mode("am", "AM"), AnalogMode("am", "AM", bandpass=Bandpass(-4000, 4000)),
Mode("lsb", "LSB"), AnalogMode("lsb", "LSB", bandpass=Bandpass(-3000, -300)),
Mode("usb", "USB"), AnalogMode("usb", "USB", bandpass=Bandpass(300, 3000)),
Mode("cw", "CW"), AnalogMode("cw", "CW", bandpass=Bandpass(700, 900)),
Mode("dmr", "DMR", requirements=["digital_voice_digiham"]), AnalogMode("dmr", "DMR", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"]),
Mode("dstar", "DStar", requirements=["digital_voice_dsd"]), AnalogMode("dstar", "DStar", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"]),
Mode("nxdn", "NXDN", requirements=["digital_voice_dsd"]), AnalogMode("nxdn", "NXDN", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"]),
Mode("ysf", "YSF", requirements=["digital_voice_digiham"]), AnalogMode("ysf", "YSF", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"]),
Mode("bpsk31", "BPSK31", digimode=True), DigitalMode("bpsk31", "BPSK31", underlying=["usb"]),
Mode("bpsk63", "BPSK63", digimode=True), DigitalMode("bpsk63", "BPSK63", underlying=["usb"]),
Mode("ft8", "FT8", requirements=["wsjt-x"], service=True, digimode=True), DigitalMode("ft8", "FT8", underlying=["usb"], requirements=["wsjt-x"], service=True),
Mode("ft4", "FT4", requirements=["wsjt-x"], service=True, digimode=True), DigitalMode("ft4", "FT4", underlying=["usb"], requirements=["wsjt-x"], service=True),
Mode("jt65", "JT65", requirements=["wsjt-x"], service=True, digimode=True), DigitalMode("jt65", "JT65", underlying=["usb"], requirements=["wsjt-x"], service=True),
Mode("jt9", "JT9", requirements=["wsjt-x"], service=True, digimode=True), DigitalMode("jt9", "JT9", underlying=["usb"], requirements=["wsjt-x"], service=True),
Mode("wspr", "WSPR", requirements=["wsjt-x"], service=True, digimode=True), DigitalMode("wspr", "WSPR", underlying=["usb"], bandpass=Bandpass(1350, 1650), requirements=["wsjt-x"], service=True),
Mode("packet", "Packet", ["packet"], service=True, digimode=True), DigitalMode("js8", "JS8Call", underlying=["usb"], requirements=["js8call"], service=True),
Mode("js8", "JS8Call", requirements=["js8call"], service=True, digimode=True), DigitalMode("packet", "Packet", underlying=["nfm", "usb", "lsb"], requirements=["packet"], service=True),
DigitalMode("pocsag", "Pocsag", underlying=["nfm"], bandpass=Bandpass(-6000, 6000), requirements=["pocsag"])
] ]
@staticmethod @staticmethod