Merge branch 'jketterl:develop' into tuning_step

This commit is contained in:
Luarvique L. Luarvique 2022-10-25 20:18:41 -04:00 committed by GitHub
commit caf77f686a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 114 additions and 20 deletions

View File

@ -1,5 +1,9 @@
**unreleased** **unreleased**
**1.2.1**
- FifiSDR support fixed (pipeline formats now line up correctly)
- Added "Device" input for FifiSDR devices for sound card selection
**1.2.0** **1.2.0**
- Major rewrite of all demodulation components to make use of the new csdr/pycsdr and digiham/pydigiham demodulator - Major rewrite of all demodulation components to make use of the new csdr/pycsdr and digiham/pydigiham demodulator
modules modules

9
debian/changelog vendored
View File

@ -1,6 +1,13 @@
openwebrx (1.3.0) UNRELEASED; urgency=low openwebrx (1.3.0) UNRELEASED; urgency=low
-- Jakob Ketterl <jakob.ketterl@gmx.de> Thu, 16 Jun 2022 21:47:00 +0000 -- Jakob Ketterl <jakob.ketterl@gmx.de> Fri, 30 Sep 2022 16:47:00 +0000
openwebrx (1.2.1) bullseye jammy; urgency=low
* FifiSDR support fixed (pipeline formats now line up correctly)
* Added "Device" input for FifiSDR devices for sound card selection
-- Jakob Ketterl <jakob.ketterl@gmx.de> Tue, 20 Sep 2022 16:01:00 +0000
openwebrx (1.2.0) bullseye jammy; urgency=low openwebrx (1.2.0) bullseye jammy; urgency=low

View File

@ -24,7 +24,7 @@ apt-get update
apt-get -y install --no-install-recommends $BUILD_PACKAGES apt-get -y install --no-install-recommends $BUILD_PACKAGES
git clone https://github.com/jketterl/owrx_connector.git git clone https://github.com/jketterl/owrx_connector.git
cmakebuild owrx_connector 0.6.0 cmakebuild owrx_connector 0.6.1
apt-get -y purge --autoremove $BUILD_PACKAGES apt-get -y purge --autoremove $BUILD_PACKAGES
apt-get clean apt-get clean

View File

@ -25,7 +25,7 @@ apt-get update
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
git clone https://github.com/jketterl/runds_connector.git git clone https://github.com/jketterl/runds_connector.git
cmakebuild runds_connector 0.2.1 cmakebuild runds_connector 0.2.2
apt-get -y purge --autoremove $BUILD_PACKAGES apt-get -y purge --autoremove $BUILD_PACKAGES
apt-get clean apt-get clean

View File

@ -31,11 +31,11 @@ popd
rm -rf js8py rm -rf js8py
git clone https://github.com/jketterl/csdr.git git clone https://github.com/jketterl/csdr.git
cmakebuild csdr 0.18.0 cmakebuild csdr 0.18.1
git clone https://github.com/jketterl/pycsdr.git git clone https://github.com/jketterl/pycsdr.git
cd pycsdr cd pycsdr
git checkout 0.18.0 git checkout 0.18.1
./setup.py install install_headers ./setup.py install install_headers
cd .. cd ..
rm -rf pycsdr rm -rf pycsdr
@ -46,11 +46,11 @@ cp codecserver/conf/codecserver.conf /usr/local/etc/codecserver
cmakebuild codecserver 0.2.0 cmakebuild codecserver 0.2.0
git clone https://github.com/jketterl/digiham.git git clone https://github.com/jketterl/digiham.git
cmakebuild digiham 0.6.0 cmakebuild digiham 0.6.1
git clone https://github.com/jketterl/pydigiham.git git clone https://github.com/jketterl/pydigiham.git
cd pydigiham cd pydigiham
git checkout 0.6.0 git checkout 0.6.1
./setup.py install ./setup.py install
cd .. cd ..
rm -rf pydigiham rm -rf pydigiham

View File

@ -81,6 +81,12 @@ Envelope.prototype.draw = function(visible_range){
scale_ctx.fill(); scale_ctx.fill();
scale_ctx.globalAlpha = 1; scale_ctx.globalAlpha = 1;
scale_ctx.stroke(); scale_ctx.stroke();
scale_ctx.lineWidth = 1;
scale_ctx.textAlign = "left";
scale_ctx.fillText(this.demodulator.high_cut.toString(), to_px + env_att_w, env_h2);
scale_ctx.textAlign = "right";
scale_ctx.fillText(this.demodulator.low_cut.toString(), from_px - env_att_w, env_h2);
scale_ctx.lineWidth = 3;
} }
if (typeof line !== "undefined") // out of screen? if (typeof line !== "undefined") // out of screen?
{ {

View File

@ -37,6 +37,7 @@ $(function(){
var retention_time = 2 * 60 * 60 * 1000; var retention_time = 2 * 60 * 60 * 1000;
var strokeOpacity = 0.8; var strokeOpacity = 0.8;
var fillOpacity = 0.35; var fillOpacity = 0.35;
var callsign_url = null;
var colorKeys = {}; var colorKeys = {};
var colorScale = chroma.scale(['red', 'blue', 'green']).mode('hsl'); var colorScale = chroma.scale(['red', 'blue', 'green']).mode('hsl');
@ -286,6 +287,9 @@ $(function(){
if ('map_position_retention_time' in config) { if ('map_position_retention_time' in config) {
retention_time = config.map_position_retention_time * 1000; retention_time = config.map_position_retention_time * 1000;
} }
if ('callsign_url' in config) {
callsign_url = config['callsign_url'];
}
break; break;
case "update": case "update":
processUpdates(json.value); processUpdates(json.value);
@ -338,7 +342,33 @@ $(function(){
delete infowindow.locator; delete infowindow.locator;
delete infowindow.callsign; delete infowindow.callsign;
return infowindow; return infowindow;
} };
var linkifyCallsign = function(callsign) {
if ((callsign_url == null) || (callsign_url == ''))
return callsign;
else
return '<a target="callsign_info" href="' +
callsign_url.replaceAll('{}', callsign.replace(new RegExp('-.*$'), '')) +
'">' + callsign + '</a>';
};
var distanceKm = function(p1, p2) {
// Earth radius in km
var R = 6371.0;
// Convert degrees to radians
var rlat1 = p1.lat() * (Math.PI/180);
var rlat2 = p2.lat() * (Math.PI/180);
// Compute difference in radians
var difflat = rlat2-rlat1;
var difflon = (p2.lng()-p1.lng()) * (Math.PI/180);
// Compute distance
d = 2 * R * Math.asin(Math.sqrt(
Math.sin(difflat/2) * Math.sin(difflat/2) +
Math.cos(rlat1) * Math.cos(rlat2) * Math.sin(difflon/2) * Math.sin(difflon/2)
));
return Math.round(d);
};
var infowindow; var infowindow;
var showLocatorInfoWindow = function(locator, pos) { var showLocatorInfoWindow = function(locator, pos) {
@ -351,13 +381,15 @@ $(function(){
}).sort(function(a, b){ }).sort(function(a, b){
return b.lastseen - a.lastseen; return b.lastseen - a.lastseen;
}); });
var distance = receiverMarker?
" at " + distanceKm(receiverMarker.position, pos) + " km" : "";
infowindow.setContent( infowindow.setContent(
'<h3>Locator: ' + locator + '</h3>' + '<h3>Locator: ' + locator + distance + '</h3>' +
'<div>Active Callsigns:</div>' + '<div>Active Callsigns:</div>' +
'<ul>' + '<ul>' +
inLocator.map(function(i){ inLocator.map(function(i){
var timestring = moment(i.lastseen).fromNow(); var timestring = moment(i.lastseen).fromNow();
var message = i.callsign + ' (' + timestring + ' using ' + i.mode; var message = linkifyCallsign(i.callsign) + ' (' + timestring + ' using ' + i.mode;
if (i.band) message += ' on ' + i.band; if (i.band) message += ' on ' + i.band;
message += ')'; message += ')';
return '<li>' + message + '</li>' return '<li>' + message + '</li>'
@ -374,16 +406,20 @@ $(function(){
var marker = markers[callsign]; var marker = markers[callsign];
var timestring = moment(marker.lastseen).fromNow(); var timestring = moment(marker.lastseen).fromNow();
var commentString = ""; var commentString = "";
var distance = "";
if (marker.comment) { if (marker.comment) {
commentString = '<div>' + marker.comment + '</div>'; commentString = '<div>' + marker.comment + '</div>';
} }
if (receiverMarker) {
distance = " at " + distanceKm(receiverMarker.position, marker.position) + " km";
}
infowindow.setContent( infowindow.setContent(
'<h3>' + callsign + '</h3>' + '<h3>' + linkifyCallsign(callsign) + distance + '</h3>' +
'<div>' + timestring + ' using ' + marker.mode + ( marker.band ? ' on ' + marker.band : '' ) + '</div>' + '<div>' + timestring + ' using ' + marker.mode + ( marker.band ? ' on ' + marker.band : '' ) + '</div>' +
commentString commentString
); );
infowindow.open(map, marker); infowindow.open(map, marker);
} };
var showReceiverInfoWindow = function(marker) { var showReceiverInfoWindow = function(marker) {
var infowindow = getInfoWindow() var infowindow = getInfoWindow()
@ -392,7 +428,7 @@ $(function(){
'<div>Receiver location</div>' '<div>Receiver location</div>'
); );
infowindow.open(map, marker); infowindow.open(map, marker);
} };
var getScale = function(lastseen) { var getScale = function(lastseen) {
var age = new Date().getTime() - lastseen; var age = new Date().getTime() - lastseen;

View File

@ -802,6 +802,7 @@ function on_ws_recv(evt) {
$('#openwebrx-sdr-profiles-listbox').val(currentprofile.toString()); $('#openwebrx-sdr-profiles-listbox').val(currentprofile.toString());
waterfall_clear(); waterfall_clear();
zoom_set(0);
} }
if ('tuning_precision' in config) if ('tuning_precision' in config)
@ -969,9 +970,15 @@ var waterfall_measure_minmax_now = false;
var waterfall_measure_minmax_continuous = false; var waterfall_measure_minmax_continuous = false;
function waterfall_measure_minmax_do(what) { function waterfall_measure_minmax_do(what) {
// Get visible range
var range = get_visible_freq_range();
var start = center_freq - bandwidth / 2;
// this is based on an oversampling factor of about 1,25 // this is based on an oversampling factor of about 1,25
var ignored = .1 * what.length; range.start = Math.max(0.1, (range.start - start) / bandwidth);
var data = what.slice(ignored, -ignored); range.end = Math.min(0.9, (range.end - start) / bandwidth);
var data = what.slice(range.start * what.length, range.end * what.length);
return { return {
min: Math.min.apply(Math, data), min: Math.min.apply(Math, data),
max: Math.max.apply(Math, data) max: Math.max.apply(Math, data)

View File

@ -159,6 +159,7 @@ defaultConfig = PropertyLayer(
squelch_auto_margin=10, squelch_auto_margin=10,
google_maps_api_key="", google_maps_api_key="",
map_position_retention_time=2 * 60 * 60, map_position_retention_time=2 * 60 * 60,
callsign_url="https://www.qrzcq.com/call/{}",
decoding_queue_workers=2, decoding_queue_workers=2,
decoding_queue_length=10, decoding_queue_length=10,
wsjt_decoding_depth=3, wsjt_decoding_depth=3,

View File

@ -457,6 +457,7 @@ class MapConnection(OpenWebRxClient):
"google_maps_api_key", "google_maps_api_key",
"receiver_gps", "receiver_gps",
"map_position_retention_time", "map_position_retention_time",
"callsign_url",
"receiver_name", "receiver_name",
) )
filtered_config.wire(self.write_config) filtered_config.wire(self.write_config)

View File

@ -168,6 +168,13 @@ class GeneralSettingsController(SettingsFormController):
infotext="Specifies how log markers / grids will remain visible on the map", infotext="Specifies how log markers / grids will remain visible on the map",
append="s", append="s",
), ),
TextInput(
"callsign_url",
"Callsign database URL",
infotext="Specifies callsign lookup URL, such as QRZ.COM "
+ "or QRZCQ.COM. Place curly brackers ({}) where callsign "
+ "is supposed to be.",
),
), ),
] ]

View File

@ -249,10 +249,13 @@ class SdrSource(ABC):
def getPort(self): def getPort(self):
return self.port return self.port
def _getTcpSourceFormat(self):
return Format.COMPLEX_FLOAT
def _getTcpSource(self): def _getTcpSource(self):
with self.modificationLock: with self.modificationLock:
if self.tcpSource is None: if self.tcpSource is None:
self.tcpSource = TcpSource(self.port, Format.COMPLEX_FLOAT) self.tcpSource = TcpSource(self.port, self._getTcpSourceFormat())
return self.tcpSource return self.tcpSource
def getBuffer(self): def getBuffer(self):

View File

@ -11,6 +11,10 @@ logger = logging.getLogger(__name__)
class DirectSource(SdrSource, metaclass=ABCMeta): class DirectSource(SdrSource, metaclass=ABCMeta):
def __init__(self, id, props):
self._conversion = None
super().__init__(id, props)
def onPropertyChange(self, changes): def onPropertyChange(self, changes):
logger.debug("restarting sdr source due to property changes: {0}".format(changes)) logger.debug("restarting sdr source due to property changes: {0}".format(changes))
self.stop() self.stop()
@ -48,6 +52,10 @@ class DirectSource(SdrSource, metaclass=ABCMeta):
def getFormatConversion(self) -> Optional[Chain]: def getFormatConversion(self) -> Optional[Chain]:
return None return None
def _getTcpSourceFormat(self):
conversion = self.getFormatConversion()
return Format.COMPLEX_FLOAT if conversion is None else conversion.getInputFormat()
# override this in subclasses, if necessary # override this in subclasses, if necessary
def sleepOnRestart(self): def sleepOnRestart(self):
pass pass
@ -57,12 +65,12 @@ class DirectSource(SdrSource, metaclass=ABCMeta):
source = self._getTcpSource() source = self._getTcpSource()
buffer = Buffer(source.getOutputFormat()) buffer = Buffer(source.getOutputFormat())
source.setWriter(buffer) source.setWriter(buffer)
conversion = self.getFormatConversion() self._conversion = self.getFormatConversion()
if conversion is not None: if self._conversion is not None:
conversion.setReader(buffer.getReader()) self._conversion.setReader(buffer.getReader())
# this one must be COMPLEX_FLOAT # this one must be COMPLEX_FLOAT
buffer = Buffer(Format.COMPLEX_FLOAT) buffer = Buffer(Format.COMPLEX_FLOAT)
conversion.setWriter(buffer) self._conversion.setWriter(buffer)
self.buffer = buffer self.buffer = buffer
return self.buffer return self.buffer

View File

@ -4,6 +4,8 @@ from subprocess import Popen
from csdr.chain import Chain from csdr.chain import Chain
from pycsdr.modules import Convert, Gain from pycsdr.modules import Convert, Gain
from pycsdr.types import Format from pycsdr.types import Format
from typing import List
from owrx.form.input import Input, TextInput
import logging import logging
@ -49,3 +51,15 @@ class FifiSdrDeviceDescription(DirectSourceDeviceDescription):
def supportsPpm(self): def supportsPpm(self):
# not currently mapped, and it's unclear how this should be sent to the device # not currently mapped, and it's unclear how this should be sent to the device
return False return False
def getInputs(self) -> List[Input]:
return super().getInputs() + [
TextInput(
"device",
"Device identifier",
infotext="Alsa audio device identifier",
),
]
def getDeviceOptionalKeys(self):
return super().getDeviceOptionalKeys() + ["device"]