restore js8 functionality

This commit is contained in:
Jakob Ketterl 2021-09-06 22:50:57 +02:00
parent 6014ce8921
commit f9f0bdde12
8 changed files with 45 additions and 78 deletions

View File

@ -70,7 +70,7 @@ Js8Thread.prototype.getMessageDuration = function() {
Js8Thread.prototype.getMode = function() { Js8Thread.prototype.getMode = function() {
// we filter messages by mode, so the first one is as good as any // we filter messages by mode, so the first one is as good as any
if (!this.messages.length) return; if (!this.messages.length) return;
return this.messages[0].mode; return this.messages[0].js8mode;
}; };
Js8Thread.prototype.acceptsMode = function(mode) { Js8Thread.prototype.acceptsMode = function(mode) {
@ -117,6 +117,10 @@ Js8Threader = function(el){
Js8Threader.prototype = new MessagePanel(); Js8Threader.prototype = new MessagePanel();
Js8Threader.prototype.supportsMessage = function(message) {
return message['mode'] === 'JS8';
};
Js8Threader.prototype.render = function() { Js8Threader.prototype.render = function() {
$(this.el).append($( $(this.el).append($(
'<table>' + '<table>' +
@ -158,7 +162,7 @@ Js8Threader.prototype.pushMessage = function(message) {
var thread; var thread;
// only look for exising threads if the message is not a starting message // only look for exising threads if the message is not a starting message
if ((message.thread_type & 1) === 0) { if ((message.thread_type & 1) === 0) {
thread = this.findThread(message.freq, message.mode); thread = this.findThread(message.freq, message.js8mode);
} }
if (!thread) { if (!thread) {
var line = $("<tr></tr>"); var line = $("<tr></tr>");

View File

@ -821,9 +821,6 @@ function on_ws_recv(evt) {
this.update(json['value']); this.update(json['value']);
}); });
break; break;
case "js8_message":
$("#openwebrx-panel-js8-message").js8().pushMessage(json['value']);
break;
case "dial_frequencies": case "dial_frequencies":
var as_bookmarks = json['value'].map(function (d) { var as_bookmarks = json['value'].map(function (d) {
return { return {
@ -849,7 +846,8 @@ function on_ws_recv(evt) {
var panels = [ var panels = [
$("#openwebrx-panel-wsjt-message").wsjtMessagePanel(), $("#openwebrx-panel-wsjt-message").wsjtMessagePanel(),
$('#openwebrx-panel-packet-message').packetMessagePanel(), $('#openwebrx-panel-packet-message').packetMessagePanel(),
$('#openwebrx-panel-pocsag-message').pocsagMessagePanel() $('#openwebrx-panel-pocsag-message').pocsagMessagePanel(),
$("#openwebrx-panel-js8-message").js8()
]; ];
if (!panels.some(function(panel) { if (!panels.some(function(panel) {
if (!panel.supportsMessage(value)) return false; if (!panel.supportsMessage(value)) return false;

View File

@ -437,22 +437,6 @@ class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient):
def write_backoff_message(self, reason): def write_backoff_message(self, reason):
self.send({"type": "backoff", "reason": reason}) self.send({"type": "backoff", "reason": reason})
def write_js8_message(self, frame: Js8Frame, freq: int):
self.send(
{
"type": "js8_message",
"value": {
"msg": str(frame),
"timestamp": frame.timestamp,
"db": frame.db,
"dt": frame.dt,
"freq": freq + frame.freq,
"thread_type": frame.thread_type,
"mode": frame.mode,
},
}
)
def write_modes(self, modes): def write_modes(self, modes):
def to_json(m): def to_json(m):
res = { res = {

View File

@ -281,7 +281,6 @@ class DspManager(Output, SdrSourceEventClient):
self.sdrSource = sdrSource self.sdrSource = sdrSource
self.parsers = { self.parsers = {
"meta": MetaParser(self.handler), "meta": MetaParser(self.handler),
"js8_demod": Js8Parser(self.handler),
} }
self.props = PropertyStack() self.props = PropertyStack()
@ -364,18 +363,6 @@ class DspManager(Output, SdrSourceEventClient):
# TODO there's multiple outputs depending on the modulation right now # TODO there's multiple outputs depending on the modulation right now
self.wireOutput("secondary_demod", buffer) self.wireOutput("secondary_demod", buffer)
def set_dial_freq(changes):
if (
"center_freq" not in self.props
or self.props["center_freq"] is None
or "offset_freq" not in self.props
or self.props["offset_freq"] is None
):
return
freq = self.props["center_freq"] + self.props["offset_freq"]
for parser in self.parsers.values():
parser.setDialFrequency(freq)
if "start_mod" in self.props: if "start_mod" in self.props:
self.setDemodulator(self.props["start_mod"]) self.setDemodulator(self.props["start_mod"])
mode = Modes.findByModulation(self.props["start_mod"]) mode = Modes.findByModulation(self.props["start_mod"])
@ -409,7 +396,6 @@ class DspManager(Output, SdrSourceEventClient):
# self.props.wireProperty("wfm_deemphasis_tau", self.dsp.set_wfm_deemphasis_tau), # self.props.wireProperty("wfm_deemphasis_tau", self.dsp.set_wfm_deemphasis_tau),
# TODO # TODO
# self.props.wireProperty("digital_voice_codecserver", self.dsp.set_codecserver), # self.props.wireProperty("digital_voice_codecserver", self.dsp.set_codecserver),
self.props.filter("center_freq", "offset_freq").wire(set_dial_freq),
] ]
# TODO # TODO
@ -489,6 +475,8 @@ class DspManager(Output, SdrSourceEventClient):
# TODO add remaining modes # TODO add remaining modes
if mod in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]: if mod in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]:
return AudioChopperDemodulator(mod, WsjtParser()) return AudioChopperDemodulator(mod, WsjtParser())
elif mod == "js8":
return AudioChopperDemodulator(mod, Js8Parser())
elif mod == "packet": elif mod == "packet":
return PacketDemodulator() return PacketDemodulator()
elif mod == "pocsag": elif mod == "pocsag":

View File

@ -1,5 +1,4 @@
from owrx.audio import AudioChopperProfile, ConfigWiredProfileSource from owrx.audio import AudioChopperProfile, ConfigWiredProfileSource
from owrx.parser import Parser
import re import re
from js8py import Js8 from js8py import Js8
from js8py.frames import Js8FrameHeartbeat, Js8FrameCompound from js8py.frames import Js8FrameHeartbeat, Js8FrameCompound
@ -8,6 +7,7 @@ from owrx.metrics import Metrics, CounterMetric
from owrx.config import Config from owrx.config import Config
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from owrx.reporting import ReportingEngine from owrx.reporting import ReportingEngine
from owrx.bands import Bandplan
from typing import List from typing import List
import logging import logging
@ -81,13 +81,15 @@ class Js8TurboProfile(Js8Profile):
return "C" return "C"
class Js8Parser(Parser): class Js8Parser:
decoderRegex = re.compile(" ?<Decode(Started|Debug|Finished)>") decoderRegex = re.compile(" ?<Decode(Started|Debug|Finished)>")
def parse(self, raw): def parse(self, profile, freq, raw_msg):
try: try:
profile, freq, raw_msg = raw band = None
self.setDialFrequency(freq) if freq is not None:
band = Bandplan.getSharedInstance().findBand(freq)
msg = raw_msg.decode().rstrip() msg = raw_msg.decode().rstrip()
if Js8Parser.decoderRegex.match(msg): if Js8Parser.decoderRegex.match(msg):
return return
@ -95,38 +97,48 @@ class Js8Parser(Parser):
return return
frame = Js8().parse_message(msg) frame = Js8().parse_message(msg)
self.handler.write_js8_message(frame, self.dial_freq)
self.pushDecode() self.pushDecode(band)
if (isinstance(frame, Js8FrameHeartbeat) or isinstance(frame, Js8FrameCompound)) and frame.grid: if (isinstance(frame, Js8FrameHeartbeat) or isinstance(frame, Js8FrameCompound)) and frame.grid:
Map.getSharedInstance().updateLocation( Map.getSharedInstance().updateLocation(
frame.callsign, LocatorLocation(frame.grid), "JS8", self.band frame.callsign, LocatorLocation(frame.grid), "JS8", band
) )
ReportingEngine.getSharedInstance().spot( ReportingEngine.getSharedInstance().spot(
{ {
"callsign": frame.callsign, "callsign": frame.callsign,
"mode": "JS8", "mode": "JS8",
"locator": frame.grid, "locator": frame.grid,
"freq": self.dial_freq + frame.freq, "freq": freq + frame.freq,
"db": frame.db, "db": frame.db,
"timestamp": frame.timestamp, "timestamp": frame.timestamp,
"msg": str(frame), "msg": str(frame),
} }
) )
out = {
"mode": "JS8",
"msg": str(frame),
"timestamp": frame.timestamp,
"db": frame.db,
"dt": frame.dt,
"freq": freq + frame.freq,
"thread_type": frame.thread_type,
"js8mode": frame.mode,
}
return out
except Exception: except Exception:
logger.exception("error while parsing js8 message") logger.exception("error while parsing js8 message")
def pushDecode(self): def pushDecode(self, band):
metrics = Metrics.getSharedInstance() metrics = Metrics.getSharedInstance()
band = "unknown" bandName = "unknown"
if self.band is not None: if band is not None:
band = self.band.getName() bandName = band.getName()
if band is None:
band = "unknown"
name = "js8call.decodes.{band}.JS8".format(band=band) name = "js8call.decodes.{band}.JS8".format(band=bandName)
metric = metrics.getMetric(name) metric = metrics.getMetric(name)
if metric is None: if metric is None:
metric = CounterMetric() metric = CounterMetric()

View File

@ -5,7 +5,6 @@ from datetime import datetime, timedelta
import logging import logging
import threading import threading
from owrx.map import Map, LatLngLocation from owrx.map import Map, LatLngLocation
from owrx.parser import Parser
from owrx.aprs import AprsParser, AprsLocation from owrx.aprs import AprsParser, AprsLocation
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
@ -159,9 +158,9 @@ class DStarEnricher(Enricher):
return meta return meta
class MetaParser(Parser): class MetaParser:
def __init__(self, handler): def __init__(self, handler):
super().__init__(handler) self.handler = handler
self.enrichers = { self.enrichers = {
"DMR": RadioIDEnricher("dmr", self), "DMR": RadioIDEnricher("dmr", self),
"YSF": YsfMetaEnricher(self), "YSF": YsfMetaEnricher(self),

View File

@ -1,20 +0,0 @@
from abc import ABC, abstractmethod
from owrx.bands import Bandplan
class Parser(ABC):
def __init__(self, handler):
self.handler = handler
self.dial_freq = None
self.band = None
@abstractmethod
def parse(self, raw):
pass
def setDialFrequency(self, freq):
self.dial_freq = freq
self.band = Bandplan.getSharedInstance().findBand(freq)
def getBand(self):
return self.band

View File

@ -3,10 +3,10 @@ from owrx.source import SdrSourceEventClient, SdrSourceState, SdrClientClass
from owrx.sdr import SdrService from owrx.sdr import SdrService
from owrx.bands import Bandplan from owrx.bands import Bandplan
from owrx.wsjt import WsjtParser from owrx.wsjt import WsjtParser
from owrx.js8 import Js8Parser
from owrx.config import Config from owrx.config import Config
from owrx.source.resampler import Resampler from owrx.source.resampler import Resampler
from owrx.property import PropertyLayer, PropertyDeleted from owrx.property import PropertyLayer, PropertyDeleted
from js8py import Js8Frame
from owrx.service.schedule import ServiceScheduler from owrx.service.schedule import ServiceScheduler
from owrx.service.chain import ServiceDemodulatorChain from owrx.service.chain import ServiceDemodulatorChain
from owrx.modes import Modes, DigitalMode from owrx.modes import Modes, DigitalMode
@ -250,7 +250,7 @@ class ServiceHandler(SdrSourceEventClient):
logger.warning("mode is not a digimode: %s", mode) logger.warning("mode is not a digimode: %s", mode)
return None return None
demod = self._getDemodulator(modeObject.get_modulation(), source.getProps()) demod = self._getDemodulator(modeObject.get_modulation())
secondaryDemod = self._getSecondaryDemodulator(modeObject.modulation) secondaryDemod = self._getSecondaryDemodulator(modeObject.modulation)
center_freq = source.getProps()["center_freq"] center_freq = source.getProps()["center_freq"]
sampleRate = source.getProps()["samp_rate"] sampleRate = source.getProps()["samp_rate"]
@ -269,7 +269,7 @@ class ServiceHandler(SdrSourceEventClient):
return chain return chain
# TODO move this elsewhere # TODO move this elsewhere
def _getDemodulator(self, demod: Union[str, BaseDemodulatorChain], props): def _getDemodulator(self, demod: Union[str, BaseDemodulatorChain]):
if isinstance(demod, BaseDemodulatorChain): if isinstance(demod, BaseDemodulatorChain):
return demod return demod
# TODO: move this to Modes # TODO: move this to Modes
@ -288,6 +288,8 @@ class ServiceHandler(SdrSourceEventClient):
# TODO add remaining modes # TODO add remaining modes
if mod in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]: if mod in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]:
return AudioChopperDemodulator(mod, WsjtParser()) return AudioChopperDemodulator(mod, WsjtParser())
elif mod == "js8":
return AudioChopperDemodulator(mod, Js8Parser())
elif mod == "packet": elif mod == "packet":
return PacketDemodulator(service=True) return PacketDemodulator(service=True)
return None return None