\ No newline at end of file
diff --git a/htdocs/features.js b/htdocs/features.js
index cb96f09..e534bcb 100644
--- a/htdocs/features.js
+++ b/htdocs/features.js
@@ -1,5 +1,24 @@
$(function(){
+ var converter = new showdown.Converter();
$.ajax('/api/features').done(function(data){
- $('body').html(JSON.stringify(data));
+ $table = $('table.features');
+ $.each(data, function(name, details) {
+ requirements = $.map(details.requirements, function(r, name){
+ return '
' +
+ '
' +
+ '
' + name + '
' +
+ '
' + converter.makeHtml(r.description) + '
' +
+ '
' + (r.available ? 'YES' : 'NO') + '
' +
+ '
';
+ });
+ $table.append(
+ '
' +
+ '
' + name + '
' +
+ '
' + converter.makeHtml(details.description) + '
' +
+ '
' + (details.available ? 'YES' : 'NO') + '
' +
+ '
' +
+ requirements.join("")
+ );
+ })
});
});
\ No newline at end of file
diff --git a/owrx/feature.py b/owrx/feature.py
index 8a45b10..d8bcdca 100644
--- a/owrx/feature.py
+++ b/owrx/feature.py
@@ -4,6 +4,7 @@ from functools import reduce
from operator import and_
import re
from distutils.version import LooseVersion
+import inspect
import logging
logger = logging.getLogger(__name__)
@@ -12,6 +13,7 @@ logger = logging.getLogger(__name__)
class UnknownFeatureException(Exception):
pass
+
class FeatureDetector(object):
features = {
"core": [ "csdr", "nmux", "nc" ],
@@ -27,8 +29,22 @@ class FeatureDetector(object):
return {name: self.is_available(name) for name in FeatureDetector.features}
def feature_report(self):
+ def requirement_details(name):
+ available = self.has_requirement(name)
+ return {
+ "available": available,
+ # as of now, features are always enabled as soon as they are available. this may change in the future.
+ "enabled": available,
+ "description": self.get_requirement_description(name)
+ }
+
def feature_details(name):
- return self.get_requirements(name)
+ return {
+ "description": "",
+ "available": self.is_available(name),
+ "requirements": {name: requirement_details(name) for name in self.get_requirements(name)}
+ }
+
return {name: feature_details(name) for name in FeatureDetector.features}
def is_available(self, feature):
@@ -43,45 +59,84 @@ class FeatureDetector(object):
def has_requirements(self, requirements):
passed = True
for requirement in requirements:
- methodname = "has_" + requirement
- if hasattr(self, methodname) and callable(getattr(self, methodname)):
- passed = passed and getattr(self, methodname)()
- else:
- logger.error("detection of requirement {0} not implement. please fix in code!".format(requirement))
+ passed = passed and self.has_requirement(requirement)
return passed
+ def _get_requirement_method(self, requirement):
+ methodname = "has_" + requirement
+ if hasattr(self, methodname) and callable(getattr(self, methodname)):
+ return getattr(self, methodname)
+ return None
+
+ def has_requirement(self, requirement):
+ method = self._get_requirement_method(requirement)
+ if method is not None:
+ return method()
+ else:
+ logger.error("detection of requirement {0} not implement. please fix in code!".format(requirement))
+ return False
+
+ def get_requirement_description(self, requirement):
+ return inspect.getdoc(self._get_requirement_method(requirement))
+
def command_is_runnable(self, command):
return os.system("{0} 2>/dev/null >/dev/null".format(command)) != 32512
def has_csdr(self):
+ """
+ OpenWebRX uses the demodulator and pipeline tools provided by the csdr project. Please check out [the project
+ page on github](https://github.com/simonyiszk/csdr) for further details and installation instructions.
+ """
return self.command_is_runnable("csdr")
def has_nmux(self):
+ """
+ Nmux is another tool provided by the csdr project. It is used for internal multiplexing of the IQ data streams.
+ If you're missing nmux even though you have csdr installed, please update your csdr version.
+ """
return self.command_is_runnable("nmux --help")
def has_nc(self):
+ """
+ Nc is the client used to connect to the nmux multiplexer. It is provided by either the BSD netcat (recommended
+ for better performance) or GNU netcat packages. Please check your distribution package manager for options.
+ """
return self.command_is_runnable('nc --help')
def has_rtl_sdr(self):
+ """
+ The rtl-sdr command is required to read I/Q data from an RTL SDR USB-Stick. It is available in most
+ distribution package managers.
+ """
return self.command_is_runnable("rtl_sdr --help")
def has_rx_tools(self):
+ """
+ The rx_tools package can be used to interface with SDR devices compatible with SoapySDR. It is currently used
+ to connect to SDRPlay devices. Please check the following pages for more details:
+
+ * [rx_tools GitHub page](https://github.com/rxseger/rx_tools)
+ * [SoapySDR Project wiki](https://github.com/pothosware/SoapySDR/wiki)
+ * [SDRPlay homepage](https://www.sdrplay.com/)
+ """
return self.command_is_runnable("rx_sdr --help")
- """
- To use a HackRF, compile the HackRF host tools from its "stdout" branch:
- git clone https://github.com/mossmann/hackrf/
- cd hackrf
- git fetch
- git checkout origin/stdout
- cd host
- mkdir build
- cd build
- cmake .. -DINSTALL_UDEV_RULES=ON
- make
- sudo make install
- """
def has_hackrf_transfer(self):
+ """
+ To use a HackRF, compile the HackRF host tools from its "stdout" branch:
+ ```
+ git clone https://github.com/mossmann/hackrf/
+ cd hackrf
+ git fetch
+ git checkout origin/stdout
+ cd host
+ mkdir build
+ cd build
+ cmake .. -DINSTALL_UDEV_RULES=ON
+ make
+ sudo make install
+ ```
+ """
# TODO i don't have a hackrf, so somebody doublecheck this.
# TODO also check if it has the stdout feature
return self.command_is_runnable("hackrf_transfer --help")
@@ -89,15 +144,15 @@ class FeatureDetector(object):
def command_exists(self, command):
return os.system("which {0}".format(command)) == 0
- """
- To use DMR and YSF, the digiham package is required. You can find the package and installation instructions here:
- https://github.com/jketterl/digiham
-
- Please note: there is close interaction between digiham and openwebrx, so older versions will probably not work.
- If you have an older verison of digiham installed, please update it along with openwebrx.
- As of now, we require version 0.2 of digiham.
- """
def has_digiham(self):
+ """
+ To use digital voice modes, the digiham package is required. You can find the package and installation
+ instructions [here](https://github.com/jketterl/digiham).
+
+ Please note: there is close interaction between digiham and openwebrx, so older versions will probably not work.
+ If you have an older verison of digiham installed, please update it along with openwebrx.
+ As of now, we require version 0.2 of digiham.
+ """
required_version = LooseVersion("0.2")
digiham_version_regex = re.compile('^digiham version (.*)$')
@@ -118,10 +173,23 @@ class FeatureDetector(object):
True)
def has_dsd(self):
+ """
+ The digital voice modes NXDN and D-Star can be decoded by the dsd project. Please note that you need the version
+ modified by F4EXB that provides stdin/stdout support. You can find it [here](https://github.com/f4exb/dsd).
+ """
return self.command_is_runnable("dsd")
def has_sox(self):
+ """
+ The sox audio library is used to convert between the typical 8 kHz audio sampling rate used by digital modes and
+ the audio sampling rate requested by the client.
+
+ It is available for most distributions through the respective package manager.
+ """
return self.command_is_runnable("sox")
def has_airspy_rx(self):
+ """
+ In order to use an Airspy Receiver, you need to install the airspy_rx receiver software.
+ """
return self.command_is_runnable("airspy_rx --help 2> /dev/null")