implement first stages of active mode communication
This commit is contained in:
parent
e61d3a22a3
commit
907787cfdc
@ -33,6 +33,7 @@
|
||||
<script src="static/lib/Measurement.js"></script>
|
||||
<script src="static/lib/FrequencyDisplay.js"></script>
|
||||
<script src="static/lib/Js8Threads.js"></script>
|
||||
<script src="static/lib/Modes.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="static/lib/nanoscroller.css" />
|
||||
<link rel="stylesheet" type="text/css" href="static/css/openwebrx.css" />
|
||||
<meta charset="utf-8">
|
||||
|
28
htdocs/lib/Modes.js
Normal file
28
htdocs/lib/Modes.js
Normal file
@ -0,0 +1,28 @@
|
||||
var Modes = {
|
||||
modes: [],
|
||||
features: {},
|
||||
setModes:function(json){
|
||||
this.modes = json.map(function(m){ return new Mode(m); });
|
||||
},
|
||||
setFeatures:function(features){
|
||||
this.features = features;
|
||||
},
|
||||
findByModulation:function(modulation){
|
||||
matches = this.modes.filter(function(m) { return m.modulation === modulation; });
|
||||
if (matches.length) return matches[0]
|
||||
}
|
||||
}
|
||||
|
||||
var Mode = function(json){
|
||||
this.modulation = json.modulation;
|
||||
this.name = json.name;
|
||||
this.requirements = json.requirements;
|
||||
};
|
||||
|
||||
Mode.prototype.isAvailable = function(){
|
||||
return this.requirements.map(function(r){
|
||||
return Modes.features[r];
|
||||
}).reduce(function(a, b){
|
||||
return a && b;
|
||||
}, true);
|
||||
}
|
@ -1177,6 +1177,10 @@ function on_ws_recv(evt) {
|
||||
// set a higher reconnection timeout right away to avoid additional load
|
||||
reconnect_timeout = 16000;
|
||||
break;
|
||||
case 'modes':
|
||||
Modes.setModes(json['value']);
|
||||
console.info(Modes);
|
||||
break;
|
||||
default:
|
||||
console.warn('received message of unknown type: ' + json['type']);
|
||||
}
|
||||
@ -2014,6 +2018,11 @@ function demodulator_digital_replace_last() {
|
||||
|
||||
function demodulator_digital_replace(subtype) {
|
||||
if (secondary_demod === subtype) return;
|
||||
var mode = Modes.findByModulation(subtype);
|
||||
if (mode && !mode.isAvailable()) {
|
||||
divlog('Digital mode "' + mode.name + '" not supported. Please check requirements', true);
|
||||
return;
|
||||
}
|
||||
switch (subtype) {
|
||||
case "bpsk31":
|
||||
case "bpsk63":
|
||||
|
@ -11,6 +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 multiprocessing import Queue
|
||||
from queue import Full
|
||||
from js8py import Js8Frame
|
||||
@ -122,6 +123,9 @@ class OpenWebRxReceiverClient(Client):
|
||||
features = FeatureDetector().feature_availability()
|
||||
self.write_features(features)
|
||||
|
||||
modes = Modes.getModes()
|
||||
self.write_modes(modes)
|
||||
|
||||
CpuUsageThread.getSharedInstance().add_client(self)
|
||||
|
||||
def __sendProfiles(self):
|
||||
@ -345,6 +349,13 @@ class OpenWebRxReceiverClient(Client):
|
||||
"mode": frame.mode
|
||||
}})
|
||||
|
||||
def write_modes(self, modes):
|
||||
self.send({"type": "modes", "value": [{
|
||||
"modulation": m.modulation,
|
||||
"name": m.name,
|
||||
"requirements": m.requirements
|
||||
} for m in modes]})
|
||||
|
||||
|
||||
class MapConnection(Client):
|
||||
def __init__(self, conn):
|
||||
|
@ -1,5 +1,5 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from owrx.service import ServiceDetector
|
||||
from owrx.modes import Modes
|
||||
from owrx.config import Config
|
||||
|
||||
|
||||
@ -196,7 +196,7 @@ class MultiCheckboxInput(Input):
|
||||
class ServicesCheckboxInput(MultiCheckboxInput):
|
||||
def __init__(self, id, label, infotext=None):
|
||||
services = [
|
||||
Option(s, s.upper()) for s in ServiceDetector.getAvailableServices()
|
||||
Option(s.modulation, s.name) for s in Modes.getAvailableServices()
|
||||
]
|
||||
super().__init__(id, label, services, infotext)
|
||||
|
||||
|
43
owrx/modes.py
Normal file
43
owrx/modes.py
Normal file
@ -0,0 +1,43 @@
|
||||
from owrx.feature import FeatureDetector
|
||||
from functools import reduce
|
||||
|
||||
|
||||
class Mode(object):
|
||||
def __init__(self, modulation, name, requirements=None, service=False):
|
||||
self.modulation = modulation
|
||||
self.name = name
|
||||
self.requirements = requirements if requirements is not None else []
|
||||
self.service = service
|
||||
|
||||
def is_available(self):
|
||||
fd = FeatureDetector()
|
||||
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
|
||||
|
||||
|
||||
class Modes(object):
|
||||
mappings = [
|
||||
Mode("ft8", "FT8", ["wsjt-x"], True),
|
||||
Mode("ft4", "FT4", ["wsjt-x"], True),
|
||||
Mode("jt65", "JT65", ["wsjt-x"], True),
|
||||
Mode("jt9", "JT9", ["wsjt-x"], True),
|
||||
Mode("wspr", "WSPR", ["wsjt-x"], True),
|
||||
Mode("packet", "Packet", ["packet"], True),
|
||||
Mode("js8", "JS8Call", ["js8call"], True),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def getModes():
|
||||
return Modes.mappings
|
||||
|
||||
@staticmethod
|
||||
def getAvailableModes():
|
||||
return [m for m in Modes.getModes() if m.is_available()]
|
||||
|
||||
@staticmethod
|
||||
def getAvailableServices():
|
||||
return [m for m in Modes.getAvailableModes() if m.is_service()]
|
@ -8,12 +8,11 @@ from owrx.aprs import AprsParser
|
||||
from owrx.js8 import Js8Parser
|
||||
from owrx.config import Config
|
||||
from owrx.source.resampler import Resampler
|
||||
from owrx.feature import FeatureDetector
|
||||
from owrx.property import PropertyLayer
|
||||
from js8py import Js8Frame
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from .schedule import ServiceScheduler
|
||||
from functools import reduce
|
||||
from owrx.modes import Modes
|
||||
|
||||
import logging
|
||||
|
||||
@ -60,31 +59,6 @@ class Js8ServiceOutput(ServiceOutput):
|
||||
return t == "js8_demod"
|
||||
|
||||
|
||||
class ServiceDetector(object):
|
||||
requirements = {
|
||||
"ft8": ["wsjt-x"],
|
||||
"ft4": ["wsjt-x"],
|
||||
"jt65": ["wsjt-x"],
|
||||
"jt9": ["wsjt-x"],
|
||||
"wspr": ["wsjt-x"],
|
||||
"packet": ["packet"],
|
||||
"js8": ["js8call"],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def getAvailableServices():
|
||||
# TODO this should be in a more central place (the frontend also needs this)
|
||||
fd = FeatureDetector()
|
||||
|
||||
return [
|
||||
name
|
||||
for name, requirements in ServiceDetector.requirements.items()
|
||||
if reduce(
|
||||
lambda a, b: a and b, [fd.is_available(r) for r in requirements], True
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class ServiceHandler(object):
|
||||
def __init__(self, source):
|
||||
self.lock = threading.Lock()
|
||||
@ -120,7 +94,7 @@ class ServiceHandler(object):
|
||||
|
||||
def isSupported(self, mode):
|
||||
configured = Config.get()["services_decoders"]
|
||||
available = ServiceDetector.getAvailableServices()
|
||||
available = [m.modulation for m in Modes.getAvailableServices()]
|
||||
return mode in configured and mode in available
|
||||
|
||||
def shutdown(self):
|
||||
|
Loading…
Reference in New Issue
Block a user