restore js8 functionality
This commit is contained in:
parent
6014ce8921
commit
f9f0bdde12
@ -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>");
|
||||||
|
@ -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;
|
||||||
|
@ -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 = {
|
||||||
|
16
owrx/dsp.py
16
owrx/dsp.py
@ -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":
|
||||||
|
44
owrx/js8.py
44
owrx/js8.py
@ -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()
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user