Adding UI for the DSC decoder.

This commit is contained in:
Marat Fayzullin 2024-02-28 22:35:44 -05:00
parent 1b9a525449
commit 8fdbf90303
8 changed files with 142 additions and 10 deletions

View File

@ -8,6 +8,7 @@ from pycsdr.types import Format
from owrx.aprs.direwolf import DirewolfModule
from owrx.sstv import SstvParser
from owrx.fax import FaxParser
from owrx.dsc import DscParser
from owrx.config import Config
@ -258,10 +259,11 @@ class SitorBDemodulator(SecondaryDemodulator, SecondarySelectorChain):
class DscDemodulator(SecondaryDemodulator, SecondarySelectorChain):
def __init__(self, baudRate=100, bandWidth=170, invert=False):
self.baudRate = baudRate
self.bandWidth = bandWidth
self.invert = invert
def __init__(self, baudRate=100, bandWidth=170, invert=False, service=False):
self.baudRate = baudRate
self.bandWidth = bandWidth
self.invert = invert
self.parser = DscParser(service=service)
# this is an assumption, we will adjust in setSampleRate
self.sampleRate = 12000
secondary_samples_per_bit = int(round(self.sampleRate / self.baudRate))
@ -274,6 +276,7 @@ class DscDemodulator(SecondaryDemodulator, SecondarySelectorChain):
TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10),
Ccir493Decoder(invert=invert),
DscDecoder(),
self.parser
]
super().__init__(workers)
@ -289,3 +292,4 @@ class DscDemodulator(SecondaryDemodulator, SecondarySelectorChain):
loop_gain = self.sampleRate / self.getBandwidth() / 5
self.replace(2, Lowpass(Format.FLOAT, cutoff))
self.replace(3, TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10))

View File

@ -1360,6 +1360,45 @@ img.openwebrx-mirror-img
text-align: right;
}
#openwebrx-panel-dsc-message {
height: 310px;
}
#openwebrx-panel-dsc-message a {
color: inherit;
}
#openwebrx-panel-dsc-message tbody {
height: 280px;
}
#openwebrx-panel-dsc-message .timestamp {
width: 80px;
text-align: center;
}
#openwebrx-panel-dsc-message .src {
width: 80px;
text-align: center;
}
#openwebrx-panel-dsc-message .dst {
width: 80px;
text-align: center;
}
#openwebrx-panel-dsc-message .data {
width: 326px;
text-align: center;
}
#openwebrx-panel-dsc-message .message {
width: 566px;
max-width: 566px;
column-span: all;
word-wrap: break-word;
}
#openwebrx-panel-ism-message {
height: 310px;
}
@ -1533,6 +1572,7 @@ img.openwebrx-mirror-img
#openwebrx-panel-digimodes[data-mode="sstv"] #openwebrx-digimode-content-container,
#openwebrx-panel-digimodes[data-mode="fax"] #openwebrx-digimode-content-container,
#openwebrx-panel-digimodes[data-mode="ism"] #openwebrx-digimode-content-container,
#openwebrx-panel-digimodes[data-mode="dsc"] #openwebrx-digimode-content-container,
#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel,
#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel,
#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-select-channel,
@ -1580,7 +1620,8 @@ img.openwebrx-mirror-img
#openwebrx-panel-digimodes[data-mode="msk144"] #openwebrx-digimode-canvas-container,
#openwebrx-panel-digimodes[data-mode="sstv"] #openwebrx-digimode-canvas-container,
#openwebrx-panel-digimodes[data-mode="fax"] #openwebrx-digimode-canvas-container,
#openwebrx-panel-digimodes[data-mode="ism"] #openwebrx-digimode-canvas-container
#openwebrx-panel-digimodes[data-mode="ism"] #openwebrx-digimode-canvas-container,
#openwebrx-panel-digimodes[data-mode="dsc"] #openwebrx-digimode-canvas-container
{
height: 200px;
margin: -10px;

View File

@ -92,6 +92,7 @@
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-hfdl-message" style="display: none; width: 619px;" data-panel-name="hfdl-message"></div>
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-adsb-message" style="display: none; width: 619px;" data-panel-name="adsb-message"></div>
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-ism-message" style="display: none; width: 619px;" data-panel-name="ism-message"></div>
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-dsc-message" style="display: none; width: 619px;" data-panel-name="dsc-message"></div>
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-rds-message" style="display: none; width: 92%; max-width: 450px;" data-panel-name="rds-message"></div>
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-m17" style="display: none;" data-panel-name="metadata-m17">
<div class="openwebrx-meta-slot">

View File

@ -175,7 +175,7 @@ DemodulatorPanel.prototype.updatePanels = function() {
// Packet modes share the same panel
toggle_panel("openwebrx-panel-packet-message", ['packet', 'ais'].indexOf(modulation) >= 0);
// these modes come with their own
['js8', 'page', 'pocsag', 'sstv', 'fax', 'ism', 'rds'].forEach(function(m) {
['js8', 'page', 'pocsag', 'sstv', 'fax', 'ism', 'dsc', 'rds'].forEach(function(m) {
toggle_panel('openwebrx-panel-' + m + '-message', modulation === m);
});

View File

@ -562,6 +562,66 @@ $.fn.adsbMessagePanel = function() {
return this.data('panel');
};
DscMessagePanel = function(el) {
MessagePanel.call(this, el);
this.initClearTimer();
}
DscMessagePanel.prototype = Object.create(MessagePanel.prototype);
DscMessagePanel.prototype.supportsMessage = function(message) {
return message['mode'] === 'DSC';
};
DscMessagePanel.prototype.render = function() {
$(this.el).append($(
'<table>' +
'<thead><tr>' +
'<th class="timestamp">Time</th>' +
'<th class="src">From</th>' +
'<th class="dst">To</th>' +
'<th class="data">Data</th>' +
'</tr></thead>' +
'<tbody></tbody>' +
'</table>'
));
};
DscMessagePanel.prototype.pushMessage = function(msg) {
var tstamp = 0;
var src = '*';
var dst = '*';
var data = '';
// Append report
var $b = $(this.el).find('tbody');
$b.append($(
'<tr>' +
'<td class="timestamp">' + tstamp + '</td>' +
'<td class="src">' + src + '</td>' +
'<td class="dst">' + dst + '</td>' +
'<td class="data" style="text-align:left;">' + data + '</td>' +
'</tr>'
));
// Append messsage if present
if (msg.message) {
$b.append($(
'<tr><td class="message" colspan="4">' + Utils.htmlEscape(msg.message) + '</td></tr>'
))
}
// Jump list to the last received message
this.scrollToBottom();
};
$.fn.dscMessagePanel = function() {
if (!this.data('panel')) {
this.data('panel', new DscMessagePanel(this));
}
return this.data('panel');
};
IsmMessagePanel = function(el) {
MessagePanel.call(this, el);
this.initClearTimer();

View File

@ -1169,7 +1169,7 @@ function on_ws_recv(evt) {
break;
case 'secondary_demod':
var value = json['value'];
var panels = ['wsjt', 'packet', 'pocsag', 'page', 'sstv', 'fax', 'ism', 'hfdl', 'adsb'].map(function(id) {
var panels = ['wsjt', 'packet', 'pocsag', 'page', 'sstv', 'fax', 'ism', 'hfdl', 'adsb', 'dsc'].map(function(id) {
return $('#openwebrx-panel-' + id + '-message')[id + 'MessagePanel']();
});
panels.push($('#openwebrx-panel-js8-message').js8());
@ -1846,7 +1846,7 @@ function secondary_demod_init() {
.mousedown(secondary_demod_canvas_container_mousedown)
.mouseenter(secondary_demod_canvas_container_mousein)
.mouseleave(secondary_demod_canvas_container_mouseleave);
['wsjt', 'packet', 'pocsag', 'page', 'sstv', 'fax', 'ism', 'hfdl', 'adsb'].forEach(function(id){
['wsjt', 'packet', 'pocsag', 'page', 'sstv', 'fax', 'ism', 'hfdl', 'adsb', 'dsc'].forEach(function(id){
$('#openwebrx-panel-' + id + '-message')[id + 'MessagePanel']();
})
$('#openwebrx-panel-js8-message').js8();

27
owrx/dsc.py Normal file
View File

@ -0,0 +1,27 @@
from owrx.toolbox import TextParser
from owrx.color import ColorCache
import json
import logging
logger = logging.getLogger(__name__)
class DscParser(TextParser):
def __init__(self, service: bool = False):
# Colors will be assigned via this cache
self.colors = ColorCache()
# Construct parent object
super().__init__(filePrefix="DSC", service=service)
def parse(self, msg: bytes):
# Do not parse in service mode
if self.service:
return None
# Expect JSON data in text form
out = json.loads(msg)
# Add mode name and a color to identify the sender
out["mode"] = "DSC"
out["color"] = self.colors.getColor(out["src"])
logger.debug("{0}".format(out))
return out

View File

@ -142,8 +142,7 @@ class Modes(object):
DigitalMode("rtty450", "RTTY-450 (50N)", underlying=["usb", "lsb"]),
DigitalMode("rtty85", "RTTY-85 (50N)", underlying=["usb", "lsb"]),
DigitalMode("sitorb", "SITOR-B", underlying=["usb"]),
# Currently in development
# DigitalMode("dsc", "DSC", underlying=["usb"]),
DigitalMode("dsc", "DSC", underlying=["usb"]),
WsjtMode("ft8", "FT8"),
WsjtMode("ft4", "FT4"),
WsjtMode("jt65", "JT65"),