diff --git a/bands.json b/bands.json
new file mode 100644
index 0000000..3a6939a
--- /dev/null
+++ b/bands.json
@@ -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
+ }
+]
\ No newline at end of file
diff --git a/htdocs/map.js b/htdocs/map.js
index b5f905a..6af68ca 100644
--- a/htdocs/map.js
+++ b/htdocs/map.js
@@ -58,6 +58,7 @@
}, getMarkerOpacityOptions(update.lastseen) ));
marker.lastseen = update.lastseen;
marker.mode = update.mode;
+ marker.band = update.band;
// TODO the trim should happen on the server side
if (expectedCallsign && expectedCallsign == update.callsign.trim()) {
@@ -96,6 +97,7 @@
rectangle.lastseen = update.lastseen;
rectangle.locator = update.location.locator;
rectangle.mode = update.mode;
+ rectangle.band = update.band;
if (expectedLocator && expectedLocator == update.location.locator) {
map.panTo(center);
@@ -194,7 +196,7 @@
var showLocatorInfoWindow = function(locator, pos) {
if (!infowindow) infowindow = new google.maps.InfoWindow();
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) {
return d.locator == locator;
}).sort(function(a, b){
@@ -206,7 +208,10 @@
'
' +
inLocator.map(function(i){
var timestring = moment(i.lastseen).fromNow();
- return '- ' + i.callsign + ' (' + timestring + ' using ' + i.mode + ')
'
+ var message = i.callsign + ' (' + timestring + ' using ' + i.mode;
+ if (i.band) message += ' on ' + i.band;
+ message += ')';
+ return '- ' + message + '
'
}).join("") +
'
'
);
diff --git a/owrx/bands.py b/owrx/bands.py
new file mode 100644
index 0000000..c2ed79e
--- /dev/null
+++ b/owrx/bands.py
@@ -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))
diff --git a/owrx/map.py b/owrx/map.py
index 4d65a49..a6adbb6 100644
--- a/owrx/map.py
+++ b/owrx/map.py
@@ -1,6 +1,7 @@
from datetime import datetime, timedelta
import threading, time
from owrx.config import PropertyManager
+from owrx.bands import Band
import logging
logger = logging.getLogger(__name__)
@@ -45,7 +46,8 @@ class Map(object):
"callsign": callsign,
"location": record["location"].__dict__(),
"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()
])
@@ -56,15 +58,16 @@ class Map(object):
except ValueError:
pass
- def updateLocation(self, callsign, loc: Location, mode: str):
+ def updateLocation(self, callsign, loc: Location, mode: str, band: Band = None):
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([
{
"callsign": callsign,
"location": loc.__dict__(),
"lastseen": ts.timestamp() * 1000,
- "mode" : mode
+ "mode" : mode,
+ "band" : band.getName() if band is not None else None
}
])
diff --git a/owrx/source.py b/owrx/source.py
index 7a37ef6..2e2bca7 100644
--- a/owrx/source.py
+++ b/owrx/source.py
@@ -353,7 +353,7 @@ class DspManager(csdr.output):
self.localProps = self.sdrSource.getProps().collect(
"audio_compression", "fft_compression", "digimodes_fft_size", "csdr_dynamic_bufsize",
"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())
self.dsp = csdr.dsp(self)
@@ -369,6 +369,9 @@ class DspManager(csdr.output):
bpf[1] = cut
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.localProps.getProperty("audio_compression").wire(self.dsp.set_audio_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("digital_voice_unvoiced_quality").wire(self.dsp.set_unvoiced_quality),
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)
diff --git a/owrx/wsjt.py b/owrx/wsjt.py
index 75188ac..df3eda9 100644
--- a/owrx/wsjt.py
+++ b/owrx/wsjt.py
@@ -9,6 +9,7 @@ from multiprocessing.connection import Pipe
from owrx.map import Map, LocatorLocation
import re
from owrx.config import PropertyManager
+from owrx.bands import Bandplan
import logging
logger = logging.getLogger(__name__)
@@ -172,6 +173,8 @@ class WsjtParser(object):
def __init__(self, handler):
self.handler = handler
+ self.dial_freq = None
+ self.band = None
modes = {
"~": "FT8",
@@ -229,7 +232,7 @@ class WsjtParser(object):
# likely this just means roger roger goodbye.
if m.group(2) == "RR73":
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):
# wspr sample
@@ -252,4 +255,8 @@ class WsjtParser(object):
m = WsjtParser.wspr_splitter_pattern.match(msg)
if m is None:
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)