Merge branch 'develop' into pycsdr
This commit is contained in:
commit
db83256bcf
13
README.md
13
README.md
@ -11,11 +11,17 @@ It has the following features:
|
|||||||
- filter passband can be set from GUI
|
- filter passband can be set from GUI
|
||||||
- it extensively uses HTML5 features like WebSocket, Web Audio API, and Canvas
|
- it extensively uses HTML5 features like WebSocket, Web Audio API, and Canvas
|
||||||
- it works in Google Chrome, Chromium and Mozilla Firefox
|
- it works in Google Chrome, Chromium and Mozilla Firefox
|
||||||
- currently supports RTL-SDR, HackRF, SDRplay, AirSpy, LimeSDR, PlutoSDR
|
- supports a wide range of [SDR hardware](https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices)
|
||||||
- Multiple SDR devices can be used simultaneously
|
- Multiple SDR devices can be used simultaneously
|
||||||
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag)
|
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag)
|
||||||
- [dsd](https://github.com/f4exb/dsdcc) based demodulators (D-Star, NXDN)
|
- [dsd](https://github.com/f4exb/dsdcc) based demodulators (D-Star, NXDN)
|
||||||
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9)
|
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
|
||||||
|
FST4W)
|
||||||
|
- [direwolf](https://github.com/wb2osz/direwolf) based demodulation of APRS packets
|
||||||
|
- [JS8Call](http://js8call.com/) support
|
||||||
|
- [DRM](https://github.com/jketterl/openwebrx/wiki/DRM-demodulator-notes) support
|
||||||
|
- [FreeDV](https://github.com/jketterl/openwebrx/wiki/FreeDV-demodulator-notes) support
|
||||||
|
- M17 support based on [m17-cxx-demod](https://github.com/mobilinkd/m17-cxx-demod)
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
@ -35,6 +41,9 @@ If you have trouble setting up or configuring your receiver, you have some great
|
|||||||
you just generally want to have some OpenWebRX-related chat, come visit us over on
|
you just generally want to have some OpenWebRX-related chat, come visit us over on
|
||||||
[our groups.io group](https://groups.io/g/openwebrx).
|
[our groups.io group](https://groups.io/g/openwebrx).
|
||||||
|
|
||||||
|
If you want to hang out, chat, or get in touch directly with the developers, receiver operators or users, feel free to
|
||||||
|
drop by in [our Discord server](https://discord.gg/gnE9hPz).
|
||||||
|
|
||||||
## Usage tips
|
## Usage tips
|
||||||
|
|
||||||
You can zoom the waterfall display by the mouse wheel. You can also drag the waterfall to pan across it.
|
You can zoom the waterfall display by the mouse wheel. You can also drag the waterfall to pan across it.
|
||||||
|
@ -927,6 +927,7 @@ img.openwebrx-mirror-img
|
|||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot > * {
|
.openwebrx-meta-slot > * {
|
||||||
@ -944,8 +945,6 @@ img.openwebrx-mirror-img
|
|||||||
display: block;
|
display: block;
|
||||||
content: "";
|
content: "";
|
||||||
background-image: url("../gfx/openwebrx-mute.png");
|
background-image: url("../gfx/openwebrx-mute.png");
|
||||||
width:100%;
|
|
||||||
height:133px;
|
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -186,7 +186,7 @@ PacketMessagePanel.prototype.pushMessage = function(msg) {
|
|||||||
'style="' + stylesToString(styles) + '"'
|
'style="' + stylesToString(styles) + '"'
|
||||||
].join(' ');
|
].join(' ');
|
||||||
if (msg.lat && msg.lon) {
|
if (msg.lat && msg.lon) {
|
||||||
link = '<a ' + attrs + ' href="map?callsign=' + source + '" target="openwebrx-map">' + overlay + '</a>';
|
link = '<a ' + attrs + ' href="map?callsign=' + encodeURIComponent(source) + '" target="openwebrx-map">' + overlay + '</a>';
|
||||||
} else {
|
} else {
|
||||||
link = '<div ' + attrs + '>' + overlay + '</div>'
|
link = '<div ' + attrs + '>' + overlay + '</div>'
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ YsfMetaPanel.prototype.setLocation = function(lat, lon, callsign) {
|
|||||||
this.hasLocation = hasLocation; this.callsign = callsign;
|
this.hasLocation = hasLocation; this.callsign = callsign;
|
||||||
var html = '';
|
var html = '';
|
||||||
if (hasLocation) {
|
if (hasLocation) {
|
||||||
html = '<a class="openwebrx-maps-pin" href="map?callsign=' + callsign + '" target="_blank"></a>';
|
html = '<a class="openwebrx-maps-pin" href="map?callsign=' + encodeURIComponent(callsign) + '" target="_blank"></a>';
|
||||||
}
|
}
|
||||||
this.el.find('.openwebrx-ysf-source .location').html(html);
|
this.el.find('.openwebrx-ysf-source .location').html(html);
|
||||||
};
|
};
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
var expectedCallsign;
|
var expectedCallsign;
|
||||||
if (query.callsign) expectedCallsign = query.callsign;
|
if (query.callsign) expectedCallsign = decodeURIComponent(query.callsign);
|
||||||
var expectedLocator;
|
var expectedLocator;
|
||||||
if (query.locator) expectedLocator = query.locator;
|
if (query.locator) expectedLocator = query.locator;
|
||||||
|
|
||||||
@ -137,14 +137,13 @@
|
|||||||
marker.band = update.band;
|
marker.band = update.band;
|
||||||
marker.comment = update.location.comment;
|
marker.comment = update.location.comment;
|
||||||
|
|
||||||
// TODO the trim should happen on the server side
|
if (expectedCallsign && expectedCallsign == update.callsign) {
|
||||||
if (expectedCallsign && expectedCallsign == update.callsign.trim()) {
|
|
||||||
map.panTo(pos);
|
map.panTo(pos);
|
||||||
showMarkerInfoWindow(update.callsign, pos);
|
showMarkerInfoWindow(update.callsign, pos);
|
||||||
expectedCallsign = false;
|
expectedCallsign = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (infowindow && infowindow.callsign && infowindow.callsign == update.callsign.trim()) {
|
if (infowindow && infowindow.callsign && infowindow.callsign == update.callsign) {
|
||||||
showMarkerInfoWindow(infowindow.callsign, pos);
|
showMarkerInfoWindow(infowindow.callsign, pos);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -319,6 +318,8 @@
|
|||||||
delete infowindow.callsign;
|
delete infowindow.callsign;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
delete infowindow.locator;
|
||||||
|
delete infowindow.callsign;
|
||||||
return infowindow;
|
return infowindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
owrx/meta.py
30
owrx/meta.py
@ -24,7 +24,7 @@ class DmrCache(object):
|
|||||||
self.cacheTimeout = timedelta(seconds=86400)
|
self.cacheTimeout = timedelta(seconds=86400)
|
||||||
|
|
||||||
def isValid(self, key):
|
def isValid(self, key):
|
||||||
if not key in self.cache:
|
if key not in self.cache:
|
||||||
return False
|
return False
|
||||||
entry = self.cache[key]
|
entry = self.cache[key]
|
||||||
return entry["timestamp"] + self.cacheTimeout > datetime.now()
|
return entry["timestamp"] + self.cacheTimeout > datetime.now()
|
||||||
@ -55,20 +55,20 @@ class DmrMetaEnricher(object):
|
|||||||
|
|
||||||
def enrich(self, meta):
|
def enrich(self, meta):
|
||||||
if not Config.get()["digital_voice_dmr_id_lookup"]:
|
if not Config.get()["digital_voice_dmr_id_lookup"]:
|
||||||
return None
|
return meta
|
||||||
if not "source" in meta:
|
if "source" not in meta:
|
||||||
return None
|
return meta
|
||||||
id = meta["source"]
|
id = meta["source"]
|
||||||
cache = DmrCache.getSharedInstance()
|
cache = DmrCache.getSharedInstance()
|
||||||
if not cache.isValid(id):
|
if not cache.isValid(id):
|
||||||
if not id in self.threads:
|
if id not in self.threads:
|
||||||
self.threads[id] = threading.Thread(target=self.downloadRadioIdData, args=[id], daemon=True)
|
self.threads[id] = threading.Thread(target=self.downloadRadioIdData, args=[id], daemon=True)
|
||||||
self.threads[id].start()
|
self.threads[id].start()
|
||||||
return None
|
return meta
|
||||||
data = cache.get(id)
|
data = cache.get(id)
|
||||||
if "count" in data and data["count"] > 0 and "results" in data:
|
if "count" in data and data["count"] > 0 and "results" in data:
|
||||||
return data["results"][0]
|
meta["additional"] = data["results"][0]
|
||||||
return None
|
return meta
|
||||||
|
|
||||||
|
|
||||||
class YsfMetaEnricher(object):
|
class YsfMetaEnricher(object):
|
||||||
@ -76,11 +76,17 @@ class YsfMetaEnricher(object):
|
|||||||
self.parser = parser
|
self.parser = parser
|
||||||
|
|
||||||
def enrich(self, meta):
|
def enrich(self, meta):
|
||||||
|
for key in ["source", "up", "down", "target"]:
|
||||||
|
if key in meta:
|
||||||
|
meta[key] = meta[key].strip()
|
||||||
|
for key in ["lat", "lon"]:
|
||||||
|
if key in meta:
|
||||||
|
meta[key] = float(meta[key])
|
||||||
if "source" in meta and "lat" in meta and "lon" in meta:
|
if "source" in meta and "lat" in meta and "lon" in meta:
|
||||||
# TODO parsing the float values should probably happen earlier
|
# TODO parsing the float values should probably happen earlier
|
||||||
loc = LatLngLocation(float(meta["lat"]), float(meta["lon"]))
|
loc = LatLngLocation(meta["lat"], meta["lon"])
|
||||||
Map.getSharedInstance().updateLocation(meta["source"], loc, "YSF", self.parser.getBand())
|
Map.getSharedInstance().updateLocation(meta["source"], loc, "YSF", self.parser.getBand())
|
||||||
return None
|
return meta
|
||||||
|
|
||||||
|
|
||||||
class MetaParser(Parser):
|
class MetaParser(Parser):
|
||||||
@ -95,7 +101,5 @@ class MetaParser(Parser):
|
|||||||
if "protocol" in meta:
|
if "protocol" in meta:
|
||||||
protocol = meta["protocol"]
|
protocol = meta["protocol"]
|
||||||
if protocol in self.enrichers:
|
if protocol in self.enrichers:
|
||||||
additional_data = self.enrichers[protocol].enrich(meta)
|
meta = self.enrichers[protocol].enrich(meta)
|
||||||
if additional_data is not None:
|
|
||||||
meta["additional"] = additional_data
|
|
||||||
self.handler.write_metadata(meta)
|
self.handler.write_metadata(meta)
|
||||||
|
Loading…
Reference in New Issue
Block a user