feature detection for digital voice; display modulator buttons only when
available
This commit is contained in:
parent
823995d4ba
commit
2408d77f15
@ -91,12 +91,16 @@
|
|||||||
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-cw"
|
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-cw"
|
||||||
onclick="demodulator_analog_replace('cw');">CW</div>
|
onclick="demodulator_analog_replace('cw');">CW</div>
|
||||||
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-dmr"
|
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-dmr"
|
||||||
|
style="display:none;" data-feature="digital_voice"
|
||||||
onclick="demodulator_analog_replace('dmr');">DMR</div>
|
onclick="demodulator_analog_replace('dmr');">DMR</div>
|
||||||
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-dstar"
|
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-dstar"
|
||||||
|
style="display:none;" data-feature="digital_voice"
|
||||||
onclick="demodulator_analog_replace('dstar');">DStar</div>
|
onclick="demodulator_analog_replace('dstar');">DStar</div>
|
||||||
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-nxdn"
|
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-nxdn"
|
||||||
|
style="display:none;" data-feature="digital_voice"
|
||||||
onclick="demodulator_analog_replace('nxdn');">NXDN</div>
|
onclick="demodulator_analog_replace('nxdn');">NXDN</div>
|
||||||
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-ysf"
|
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-ysf"
|
||||||
|
style="display:none;" data-feature="digital_voice"
|
||||||
onclick="demodulator_analog_replace('ysf');">YSF</div>
|
onclick="demodulator_analog_replace('ysf');">YSF</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="openwebrx-panel-line">
|
<div class="openwebrx-panel-line">
|
||||||
|
@ -1233,6 +1233,11 @@ function on_ws_recv(evt)
|
|||||||
return '<option value="' + profile.id + '">' + profile.name + "</option>";
|
return '<option value="' + profile.id + '">' + profile.name + "</option>";
|
||||||
}).join("");
|
}).join("");
|
||||||
break;
|
break;
|
||||||
|
case "features":
|
||||||
|
for (var feature in json.value) {
|
||||||
|
$('[data-feature="' + feature + '"')[json.value[feature] ? "show" : "hide"]();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn('received message of unknown type: ' + json.type);
|
console.warn('received message of unknown type: ' + json.type);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import PropertyManager
|
||||||
from owrx.source import DspManager, CpuUsageThread, SdrService, ClientRegistry
|
from owrx.source import DspManager, CpuUsageThread, SdrService, ClientRegistry
|
||||||
|
from owrx.feature import FeatureDetector
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -33,6 +34,9 @@ class OpenWebRxClient(object):
|
|||||||
profiles = [{"name": s.getName() + " " + p["name"], "id":sid + "|" + pid} for (sid, s) in SdrService.getSources().items() for (pid, p) in s.getProfiles().items()]
|
profiles = [{"name": s.getName() + " " + p["name"], "id":sid + "|" + pid} for (sid, s) in SdrService.getSources().items() for (pid, p) in s.getProfiles().items()]
|
||||||
self.write_profiles(profiles)
|
self.write_profiles(profiles)
|
||||||
|
|
||||||
|
features = FeatureDetector().feature_availability()
|
||||||
|
self.write_features(features)
|
||||||
|
|
||||||
CpuUsageThread.getSharedInstance().add_client(self)
|
CpuUsageThread.getSharedInstance().add_client(self)
|
||||||
|
|
||||||
def sendConfig(self, key, value):
|
def sendConfig(self, key, value):
|
||||||
@ -121,6 +125,8 @@ class OpenWebRxClient(object):
|
|||||||
self.protected_send({"type":"receiver_details","value":details})
|
self.protected_send({"type":"receiver_details","value":details})
|
||||||
def write_profiles(self, profiles):
|
def write_profiles(self, profiles):
|
||||||
self.protected_send({"type":"profiles","value":profiles})
|
self.protected_send({"type":"profiles","value":profiles})
|
||||||
|
def write_features(self, features):
|
||||||
|
self.protected_send({"type":"features","value":features})
|
||||||
|
|
||||||
class WebSocketMessageHandler(object):
|
class WebSocketMessageHandler(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
|
from functools import reduce
|
||||||
|
from operator import and_
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -12,9 +15,13 @@ class FeatureDetector(object):
|
|||||||
"core": [ "csdr", "nmux" ],
|
"core": [ "csdr", "nmux" ],
|
||||||
"rtl_sdr": [ "rtl_sdr" ],
|
"rtl_sdr": [ "rtl_sdr" ],
|
||||||
"sdrplay": [ "rx_tools" ],
|
"sdrplay": [ "rx_tools" ],
|
||||||
"hackrf": [ "hackrf_transfer" ]
|
"hackrf": [ "hackrf_transfer" ],
|
||||||
|
"digital_voice": [ "digiham" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def feature_availability(self):
|
||||||
|
return {name: self.is_available(name) for name in FeatureDetector.features}
|
||||||
|
|
||||||
def is_available(self, feature):
|
def is_available(self, feature):
|
||||||
return self.has_requirements(self.get_requirements(feature))
|
return self.has_requirements(self.get_requirements(feature))
|
||||||
|
|
||||||
@ -34,17 +41,20 @@ class FeatureDetector(object):
|
|||||||
logger.error("detection of requirement {0} not implement. please fix in code!".format(requirement))
|
logger.error("detection of requirement {0} not implement. please fix in code!".format(requirement))
|
||||||
return passed
|
return passed
|
||||||
|
|
||||||
|
def command_is_runnable(self, command):
|
||||||
|
return os.system("{0} 2>/dev/null >/dev/null".format(command)) != 32512
|
||||||
|
|
||||||
def has_csdr(self):
|
def has_csdr(self):
|
||||||
return os.system("csdr 2> /dev/null") != 32512
|
return self.command_is_runnable("csdr")
|
||||||
|
|
||||||
def has_nmux(self):
|
def has_nmux(self):
|
||||||
return os.system("nmux --help 2> /dev/null") != 32512
|
return self.command_is_runnable("nmux --help")
|
||||||
|
|
||||||
def has_rtl_sdr(self):
|
def has_rtl_sdr(self):
|
||||||
return os.system("rtl_sdr --help 2> /dev/null") != 32512
|
return self.command_is_runnable("rtl_sdr --help")
|
||||||
|
|
||||||
def has_rx_tools(self):
|
def has_rx_tools(self):
|
||||||
return os.system("rx_sdr --help 2> /dev/null") != 32512
|
return self.command_is_runnable("rx_sdr --help")
|
||||||
|
|
||||||
"""
|
"""
|
||||||
To use a HackRF, compile the HackRF host tools from its "stdout" branch:
|
To use a HackRF, compile the HackRF host tools from its "stdout" branch:
|
||||||
@ -62,4 +72,29 @@ class FeatureDetector(object):
|
|||||||
def has_hackrf_transfer(self):
|
def has_hackrf_transfer(self):
|
||||||
# TODO i don't have a hackrf, so somebody doublecheck this.
|
# TODO i don't have a hackrf, so somebody doublecheck this.
|
||||||
# TODO also check if it has the stdout feature
|
# TODO also check if it has the stdout feature
|
||||||
return os.system("hackrf_transfer --help 2> /dev/null") != 32512
|
return self.command_is_runnable("hackrf_transfer --help")
|
||||||
|
|
||||||
|
def command_exists(self, command):
|
||||||
|
return os.system("which {0}".format(command)) == 0
|
||||||
|
|
||||||
|
def has_digiham(self):
|
||||||
|
# the digiham tools expect to be fed via stdin, they will block until their stdin is closed.
|
||||||
|
def check_with_stdin(command):
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(command, stdin=subprocess.PIPE)
|
||||||
|
process.communicate("")
|
||||||
|
return process.wait() == 0
|
||||||
|
except FileNotFoundError:
|
||||||
|
return False
|
||||||
|
return reduce(and_,
|
||||||
|
map(
|
||||||
|
check_with_stdin,
|
||||||
|
["rrc_filter", "ysf_decoder", "dmr_decoder", "mbe_synthesizer"]
|
||||||
|
),
|
||||||
|
True)
|
||||||
|
|
||||||
|
def has_dsd(self):
|
||||||
|
return self.command_is_runnable("dsd")
|
||||||
|
|
||||||
|
def has_sox(self):
|
||||||
|
return self.command_is_runnable("sox")
|
Loading…
Reference in New Issue
Block a user