add preliminary parsing and display of M17 metadata
This commit is contained in:
parent
81b8f183c2
commit
40c68933e1
@ -1,18 +1,19 @@
|
|||||||
from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain
|
from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, MetaProvider
|
||||||
from csdr.module.m17 import M17Module
|
from csdr.module.m17 import M17Module
|
||||||
from pycsdr.modules import FmDemod, Limit, Convert
|
from pycsdr.modules import FmDemod, Limit, Convert, Writer
|
||||||
from pycsdr.types import Format
|
from pycsdr.types import Format
|
||||||
from digiham.modules import DcBlock
|
from digiham.modules import DcBlock
|
||||||
|
|
||||||
|
|
||||||
class M17(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain):
|
class M17(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, MetaProvider):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.module = M17Module()
|
||||||
workers = [
|
workers = [
|
||||||
FmDemod(),
|
FmDemod(),
|
||||||
DcBlock(),
|
DcBlock(),
|
||||||
Limit(),
|
Limit(),
|
||||||
Convert(Format.FLOAT, Format.SHORT),
|
Convert(Format.FLOAT, Format.SHORT),
|
||||||
M17Module(),
|
self.module,
|
||||||
]
|
]
|
||||||
super().__init__(workers)
|
super().__init__(workers)
|
||||||
|
|
||||||
@ -24,3 +25,6 @@ class M17(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain):
|
|||||||
|
|
||||||
def supportsSquelch(self) -> bool:
|
def supportsSquelch(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def setMetaWriter(self, writer: Writer) -> None:
|
||||||
|
self.module.setMetaWriter(writer)
|
||||||
|
@ -118,8 +118,11 @@ class PopenModule(AutoStartModule, metaclass=ABCMeta):
|
|||||||
def getCommand(self):
|
def getCommand(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _getProcess(self):
|
||||||
|
return Popen(self.getCommand(), stdin=PIPE, stdout=PIPE)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.process = Popen(self.getCommand(), stdin=PIPE, stdout=PIPE)
|
self.process = self._getProcess()
|
||||||
# resume in case the reader has been stop()ed before
|
# resume in case the reader has been stop()ed before
|
||||||
self.reader.resume()
|
self.reader.resume()
|
||||||
Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start()
|
Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start()
|
||||||
|
@ -1,8 +1,20 @@
|
|||||||
from csdr.module import PopenModule
|
from csdr.module import PopenModule
|
||||||
from pycsdr.types import Format
|
from pycsdr.types import Format
|
||||||
|
from pycsdr.modules import Writer
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
import re
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
class M17Module(PopenModule):
|
class M17Module(PopenModule):
|
||||||
|
lsfRegex = re.compile("SRC: ([a-zA-Z0-9]+), DEST: ([a-zA-Z0-9]+)")
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.metawriter = None
|
||||||
|
|
||||||
def getInputFormat(self) -> Format:
|
def getInputFormat(self) -> Format:
|
||||||
return Format.SHORT
|
return Format.SHORT
|
||||||
|
|
||||||
@ -10,4 +22,37 @@ class M17Module(PopenModule):
|
|||||||
return Format.SHORT
|
return Format.SHORT
|
||||||
|
|
||||||
def getCommand(self):
|
def getCommand(self):
|
||||||
return ["m17-demod"]
|
return ["m17-demod", "-l"]
|
||||||
|
|
||||||
|
def _getProcess(self):
|
||||||
|
return Popen(self.getCommand(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
super().start()
|
||||||
|
Thread(target=self._readOutput).start()
|
||||||
|
|
||||||
|
def _readOutput(self):
|
||||||
|
while True:
|
||||||
|
line = self.process.stderr.readline()
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
self.parseOutput(line.decode())
|
||||||
|
|
||||||
|
def parseOutput(self, line):
|
||||||
|
if self.metawriter is None:
|
||||||
|
return
|
||||||
|
matches = self.lsfRegex.match(line)
|
||||||
|
msg = {"protocol": "M17"}
|
||||||
|
if matches:
|
||||||
|
# fake sync
|
||||||
|
msg["sync"] = "voice"
|
||||||
|
msg["source"] = matches.group(1)
|
||||||
|
msg["destination"] = matches.group(2)
|
||||||
|
elif line.startswith("EOS"):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
self.metawriter.write(pickle.dumps(msg))
|
||||||
|
|
||||||
|
def setMetaWriter(self, writer: Writer) -> None:
|
||||||
|
self.metawriter = writer
|
||||||
|
@ -1025,7 +1025,8 @@ img.openwebrx-mirror-img
|
|||||||
.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image .directcall,
|
.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image .directcall,
|
||||||
.openwebrx-meta-slot.active.individual .openwebrx-meta-user-image .directcall,
|
.openwebrx-meta-slot.active.individual .openwebrx-meta-user-image .directcall,
|
||||||
#openwebrx-panel-metadata-ysf .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall,
|
#openwebrx-panel-metadata-ysf .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall,
|
||||||
#openwebrx-panel-metadata-dstar .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall {
|
#openwebrx-panel-metadata-dstar .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall,
|
||||||
|
#openwebrx-panel-metadata-m17 .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall {
|
||||||
display: initial;
|
display: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1059,6 +1060,14 @@ img.openwebrx-mirror-img
|
|||||||
content: "Down: ";
|
content: "Down: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openwebrx-m17-source:not(:empty):before {
|
||||||
|
content: "SRC: ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.openwebrx-m17-destination:not(:empty):before {
|
||||||
|
content: "DEST: ";
|
||||||
|
}
|
||||||
|
|
||||||
.openwebrx-dstar-yourcall:not(:empty):before {
|
.openwebrx-dstar-yourcall:not(:empty):before {
|
||||||
content: "UR: ";
|
content: "UR: ";
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,15 @@
|
|||||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-js8-message" style="display:none; width: 619px;" data-panel-name="js8-message"></div>
|
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-js8-message" style="display:none; width: 619px;" data-panel-name="js8-message"></div>
|
||||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-packet-message" style="display: none; width: 619px;" data-panel-name="aprs-message"></div>
|
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-packet-message" style="display: none; width: 619px;" data-panel-name="aprs-message"></div>
|
||||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-pocsag-message" style="display: none; width: 619px;" data-panel-name="pocsag-message"></div>
|
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-pocsag-message" style="display: none; width: 619px;" data-panel-name="pocsag-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">
|
||||||
|
<div class="openwebrx-meta-user-image">
|
||||||
|
<img class="directcall" src="static/gfx/openwebrx-directcall.svg">
|
||||||
|
</div>
|
||||||
|
<div class="openwebrx-m17-source"></div>
|
||||||
|
<div class="openwebrx-m17-destination"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-ysf" style="display: none;" data-panel-name="metadata-ysf">
|
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-ysf" style="display: none;" data-panel-name="metadata-ysf">
|
||||||
<div class="openwebrx-meta-slot">
|
<div class="openwebrx-meta-slot">
|
||||||
<div class="openwebrx-ysf-mode"></div>
|
<div class="openwebrx-ysf-mode"></div>
|
||||||
|
@ -321,18 +321,57 @@ NxdnMetaPanel.prototype.clear = function() {
|
|||||||
this.setDestination();
|
this.setDestination();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function M17MetaPanel(el) {
|
||||||
|
MetaPanel.call(this, el);
|
||||||
|
this.modes = ['M17'];
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
M17MetaPanel.prototype = new MetaPanel();
|
||||||
|
|
||||||
|
M17MetaPanel.prototype.update = function(data) {
|
||||||
|
if (!this.isSupported(data)) return;
|
||||||
|
|
||||||
|
if (data['sync'] && data['sync'] === 'voice') {
|
||||||
|
this.el.find(".openwebrx-meta-slot").addClass("active");
|
||||||
|
this.setSource(data['source']);
|
||||||
|
this.setDestination(data['destination']);
|
||||||
|
} else {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
M17MetaPanel.prototype.setSource = function(source) {
|
||||||
|
if (this.source === source) return;
|
||||||
|
this.source = source;
|
||||||
|
this.el.find('.openwebrx-m17-source').text(source || '');
|
||||||
|
};
|
||||||
|
|
||||||
|
M17MetaPanel.prototype.setDestination = function(destination) {
|
||||||
|
if (this.destination === destination) return;
|
||||||
|
this.destination = destination;
|
||||||
|
this.el.find('.openwebrx-m17-destination').text(destination || '');
|
||||||
|
};
|
||||||
|
|
||||||
|
M17MetaPanel.prototype.clear = function() {
|
||||||
|
MetaPanel.prototype.clear.call(this);
|
||||||
|
this.setSource();
|
||||||
|
this.setDestination();
|
||||||
|
};
|
||||||
|
|
||||||
MetaPanel.types = {
|
MetaPanel.types = {
|
||||||
dmr: DmrMetaPanel,
|
dmr: DmrMetaPanel,
|
||||||
ysf: YsfMetaPanel,
|
ysf: YsfMetaPanel,
|
||||||
dstar: DStarMetaPanel,
|
dstar: DStarMetaPanel,
|
||||||
nxdn: NxdnMetaPanel,
|
nxdn: NxdnMetaPanel,
|
||||||
|
m17: M17MetaPanel,
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.metaPanel = function() {
|
$.fn.metaPanel = function() {
|
||||||
return this.map(function() {
|
return this.map(function() {
|
||||||
var $self = $(this);
|
var $self = $(this);
|
||||||
if (!$self.data('metapanel')) {
|
if (!$self.data('metapanel')) {
|
||||||
var matches = /^openwebrx-panel-metadata-([a-z]+)$/.exec($self.prop('id'));
|
var matches = /^openwebrx-panel-metadata-([a-z0-9]+)$/.exec($self.prop('id'));
|
||||||
var constructor = matches && MetaPanel.types[matches[1]] || MetaPanel;
|
var constructor = matches && MetaPanel.types[matches[1]] || MetaPanel;
|
||||||
$self.data('metapanel', new constructor($self));
|
$self.data('metapanel', new constructor($self));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user