detect and pass band information to the map

This commit is contained in:
Jakob Ketterl 2019-07-14 19:32:48 +02:00
parent c94331bf24
commit a15341fdcf
6 changed files with 158 additions and 10 deletions

97
bands.json Normal file
View File

@ -0,0 +1,97 @@
[
{
"name": "160m",
"lower_bound": 1810000,
"upper_bound": 2000000
},
{
"name": "80m",
"lower_bound": 3500000,
"upper_bound": 3800000
},
{
"name": "60m",
"lower_bound": 5351500,
"upper_bound": 3566500
},
{
"name": "40m",
"lower_bound": 7000000,
"upper_bound": 7200000
},
{
"name": "30m",
"lower_bound": 10100000,
"upper_bound": 10150000
},
{
"name": "20m",
"lower_bound": 14000000,
"upper_bound": 14350000
},
{
"name": "17m",
"lower_bound": 18068000,
"upper_bound": 18168000
},
{
"name": "15m",
"lower_bound": 21000000,
"upper_bound": 21450000
},
{
"name": "12m",
"lower_bound": 24890000,
"upper_bound": 24990000
},
{
"name": "10m",
"lower_bound": 28000000,
"upper_bound": 29700000
},
{
"name": "6m",
"lower_bound": 50030000,
"upper_bound": 51000000
},
{
"name": "4m",
"lower_bound": 70150000,
"upper_bound": 70200000
},
{
"name": "2m",
"lower_bound": 144000000,
"upper_bound": 146000000
},
{
"name": "70cm",
"lower_bound": 430000000,
"upper_bound": 440000000
},
{
"name": "23cm",
"lower_bound": 1240000000,
"upper_bound": 1300000000
},
{
"name": "13cm",
"lower_bound": 2320000000,
"upper_bound": 2450000000
},
{
"name": "9cm",
"lower_bound": 3400000000,
"upper_bound": 3475000000
},
{
"name": "6cm",
"lower_bound": 5650000000,
"upper_bound": 5850000000
},
{
"name": "3cm",
"lower_bound": 10000000000,
"upper_bound": 10500000000
}
]

View File

@ -58,6 +58,7 @@
}, getMarkerOpacityOptions(update.lastseen) )); }, getMarkerOpacityOptions(update.lastseen) ));
marker.lastseen = update.lastseen; marker.lastseen = update.lastseen;
marker.mode = update.mode; marker.mode = update.mode;
marker.band = update.band;
// TODO the trim should happen on the server side // TODO the trim should happen on the server side
if (expectedCallsign && expectedCallsign == update.callsign.trim()) { if (expectedCallsign && expectedCallsign == update.callsign.trim()) {
@ -96,6 +97,7 @@
rectangle.lastseen = update.lastseen; rectangle.lastseen = update.lastseen;
rectangle.locator = update.location.locator; rectangle.locator = update.location.locator;
rectangle.mode = update.mode; rectangle.mode = update.mode;
rectangle.band = update.band;
if (expectedLocator && expectedLocator == update.location.locator) { if (expectedLocator && expectedLocator == update.location.locator) {
map.panTo(center); map.panTo(center);
@ -194,7 +196,7 @@
var showLocatorInfoWindow = function(locator, pos) { var showLocatorInfoWindow = function(locator, pos) {
if (!infowindow) infowindow = new google.maps.InfoWindow(); if (!infowindow) infowindow = new google.maps.InfoWindow();
var inLocator = $.map(rectangles, function(r, callsign) { var inLocator = $.map(rectangles, function(r, callsign) {
return {callsign: callsign, locator: r.locator, lastseen: r.lastseen, mode: r.mode} return {callsign: callsign, locator: r.locator, lastseen: r.lastseen, mode: r.mode, band: r.band}
}).filter(function(d) { }).filter(function(d) {
return d.locator == locator; return d.locator == locator;
}).sort(function(a, b){ }).sort(function(a, b){
@ -206,7 +208,10 @@
'<ul>' + '<ul>' +
inLocator.map(function(i){ inLocator.map(function(i){
var timestring = moment(i.lastseen).fromNow(); var timestring = moment(i.lastseen).fromNow();
return '<li>' + i.callsign + ' (' + timestring + ' using ' + i.mode + ')</li>' var message = i.callsign + ' (' + timestring + ' using ' + i.mode;
if (i.band) message += ' on ' + i.band;
message += ')';
return '<li>' + message + '</li>'
}).join("") + }).join("") +
'</ul>' '</ul>'
); );

32
owrx/bands.py Normal file
View File

@ -0,0 +1,32 @@
import json
class Band(object):
def __init__(self, dict):
self.name = dict["name"]
self.lower_bound = dict["lower_bound"]
self.upper_bound = dict["upper_bound"]
def inBand(self, freq):
return self.lower_bound <= freq <= self.upper_bound
def getName(self):
return self.name
class Bandplan(object):
sharedInstance = None
@staticmethod
def getSharedInstance():
if Bandplan.sharedInstance is None:
Bandplan.sharedInstance = Bandplan()
return Bandplan.sharedInstance
def __init__(self):
f = open("bands.json", "r")
bands_json = json.load(f)
f.close()
self.bands = [Band(d) for d in bands_json]
def findBand(self, freq):
return next(band for band in self.bands if band.inBand(freq))

View File

@ -1,6 +1,7 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
import threading, time import threading, time
from owrx.config import PropertyManager from owrx.config import PropertyManager
from owrx.bands import Band
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -45,7 +46,8 @@ class Map(object):
"callsign": callsign, "callsign": callsign,
"location": record["location"].__dict__(), "location": record["location"].__dict__(),
"lastseen": record["updated"].timestamp() * 1000, "lastseen": record["updated"].timestamp() * 1000,
"mode" : record["mode"] "mode" : record["mode"],
"band" : record["band"].getName() if record["band"] is not None else None
} }
for (callsign, record) in self.positions.items() for (callsign, record) in self.positions.items()
]) ])
@ -56,15 +58,16 @@ class Map(object):
except ValueError: except ValueError:
pass pass
def updateLocation(self, callsign, loc: Location, mode: str): def updateLocation(self, callsign, loc: Location, mode: str, band: Band = None):
ts = datetime.now() ts = datetime.now()
self.positions[callsign] = {"location": loc, "updated": ts, "mode": mode} self.positions[callsign] = {"location": loc, "updated": ts, "mode": mode, "band": band}
self.broadcast([ self.broadcast([
{ {
"callsign": callsign, "callsign": callsign,
"location": loc.__dict__(), "location": loc.__dict__(),
"lastseen": ts.timestamp() * 1000, "lastseen": ts.timestamp() * 1000,
"mode" : mode "mode" : mode,
"band" : band.getName() if band is not None else None
} }
]) ])

View File

@ -353,7 +353,7 @@ class DspManager(csdr.output):
self.localProps = self.sdrSource.getProps().collect( self.localProps = self.sdrSource.getProps().collect(
"audio_compression", "fft_compression", "digimodes_fft_size", "csdr_dynamic_bufsize", "audio_compression", "fft_compression", "digimodes_fft_size", "csdr_dynamic_bufsize",
"csdr_print_bufsizes", "csdr_through", "digimodes_enable", "samp_rate", "digital_voice_unvoiced_quality", "csdr_print_bufsizes", "csdr_through", "digimodes_enable", "samp_rate", "digital_voice_unvoiced_quality",
"dmr_filter", "temporary_directory" "dmr_filter", "temporary_directory", "center_freq"
).defaults(PropertyManager.getSharedInstance()) ).defaults(PropertyManager.getSharedInstance())
self.dsp = csdr.dsp(self) self.dsp = csdr.dsp(self)
@ -369,6 +369,9 @@ class DspManager(csdr.output):
bpf[1] = cut bpf[1] = cut
self.dsp.set_bpf(*bpf) self.dsp.set_bpf(*bpf)
def set_dial_freq(key, value):
self.wsjtParser.setDialFrequency(self.localProps["center_freq"] + self.localProps["offset_freq"])
self.subscriptions = [ self.subscriptions = [
self.localProps.getProperty("audio_compression").wire(self.dsp.set_audio_compression), self.localProps.getProperty("audio_compression").wire(self.dsp.set_audio_compression),
self.localProps.getProperty("fft_compression").wire(self.dsp.set_fft_compression), self.localProps.getProperty("fft_compression").wire(self.dsp.set_fft_compression),
@ -382,7 +385,8 @@ class DspManager(csdr.output):
self.localProps.getProperty("mod").wire(self.dsp.set_demodulator), self.localProps.getProperty("mod").wire(self.dsp.set_demodulator),
self.localProps.getProperty("digital_voice_unvoiced_quality").wire(self.dsp.set_unvoiced_quality), self.localProps.getProperty("digital_voice_unvoiced_quality").wire(self.dsp.set_unvoiced_quality),
self.localProps.getProperty("dmr_filter").wire(self.dsp.set_dmr_filter), self.localProps.getProperty("dmr_filter").wire(self.dsp.set_dmr_filter),
self.localProps.getProperty("temporary_directory").wire(self.dsp.set_temporary_directory) self.localProps.getProperty("temporary_directory").wire(self.dsp.set_temporary_directory),
self.localProps.collect("center_freq", "offset_freq").wire(set_dial_freq)
] ]
self.dsp.set_offset_freq(0) self.dsp.set_offset_freq(0)

View File

@ -9,6 +9,7 @@ from multiprocessing.connection import Pipe
from owrx.map import Map, LocatorLocation from owrx.map import Map, LocatorLocation
import re import re
from owrx.config import PropertyManager from owrx.config import PropertyManager
from owrx.bands import Bandplan
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -172,6 +173,8 @@ class WsjtParser(object):
def __init__(self, handler): def __init__(self, handler):
self.handler = handler self.handler = handler
self.dial_freq = None
self.band = None
modes = { modes = {
"~": "FT8", "~": "FT8",
@ -229,7 +232,7 @@ class WsjtParser(object):
# likely this just means roger roger goodbye. # likely this just means roger roger goodbye.
if m.group(2) == "RR73": if m.group(2) == "RR73":
return return
Map.getSharedInstance().updateLocation(m.group(1), LocatorLocation(m.group(2)), mode) Map.getSharedInstance().updateLocation(m.group(1), LocatorLocation(m.group(2)), mode, self.band)
def parse_from_wsprd(self, msg): def parse_from_wsprd(self, msg):
# wspr sample # wspr sample
@ -252,4 +255,8 @@ class WsjtParser(object):
m = WsjtParser.wspr_splitter_pattern.match(msg) m = WsjtParser.wspr_splitter_pattern.match(msg)
if m is None: if m is None:
return return
Map.getSharedInstance().updateLocation(m.group(1), LocatorLocation(m.group(2)), "WSPR") Map.getSharedInstance().updateLocation(m.group(1), LocatorLocation(m.group(2)), "WSPR", self.band)
def setDialFrequency(self, freq):
self.dial_freq = freq
self.band = Bandplan.getSharedInstance().findBand(freq)