CW skimmer more usable now.
This commit is contained in:
parent
5dd807326a
commit
e0311ae04c
|
|
@ -224,7 +224,7 @@ class RdsDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
|||
|
||||
|
||||
class CwSkimmerDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
||||
def __init__(self, sampleRate: int = 12000, charCount: int = 4, service: bool = False):
|
||||
def __init__(self, sampleRate: int = 48000, charCount: int = 4, service: bool = False):
|
||||
self.sampleRate = sampleRate
|
||||
self.parser = CwSkimmerParser(service)
|
||||
workers = [
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ class AcarsDecModule(WavFileModule):
|
|||
|
||||
|
||||
class CwSkimmerModule(ExecModule):
|
||||
def __init__(self, sampleRate: int = 12000, charCount: int = 4):
|
||||
def __init__(self, sampleRate: int = 48000, charCount: int = 4):
|
||||
cmd = ["csdr-cwskimmer", "-i", "-r", str(sampleRate), "-n", str(charCount)]
|
||||
super().__init__(Format.SHORT, Format.CHAR, cmd)
|
||||
|
||||
|
|
|
|||
|
|
@ -1376,6 +1376,62 @@ img.openwebrx-mirror-img
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
#openwebrx-panel-cwskimmer-message {
|
||||
height: 310px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-cwskimmer-message tbody {
|
||||
height: 280px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-cwskimmer-message .freq {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-cwskimmer-message td.freq {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#openwebrx-panel-cwskimmer-message .text {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-cwskimmer-message td.text {
|
||||
font-family: monospace;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message {
|
||||
height: 310px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message tbody {
|
||||
height: 280px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .address {
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .device {
|
||||
width: 220px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .timestamp {
|
||||
width: 246px;
|
||||
max-width: 486px;
|
||||
white-space: pre;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .attr {
|
||||
width: 283px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-dsc-message {
|
||||
height: 310px;
|
||||
}
|
||||
|
|
@ -1415,37 +1471,6 @@ img.openwebrx-mirror-img
|
|||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message {
|
||||
height: 310px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message tbody {
|
||||
height: 280px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .address {
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .device {
|
||||
width: 220px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .timestamp {
|
||||
width: 246px;
|
||||
max-width: 486px;
|
||||
white-space: pre;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#openwebrx-panel-ism-message .attr {
|
||||
width: 283px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-sstv-message {
|
||||
height: 310px;
|
||||
width: 365px;
|
||||
|
|
|
|||
|
|
@ -881,7 +881,6 @@ $.fn.faxMessagePanel = function() {
|
|||
CwSkimmerMessagePanel = function(el) {
|
||||
MessagePanel.call(this, el);
|
||||
this.initClearTimer();
|
||||
this.freqs = [];
|
||||
this.texts = [];
|
||||
}
|
||||
|
||||
|
|
@ -895,8 +894,8 @@ CwSkimmerMessagePanel.prototype.render = function() {
|
|||
$(this.el).append($(
|
||||
'<table width="100%">' +
|
||||
'<thead><tr>' +
|
||||
'<th class="frequency">Freq</th>' +
|
||||
'<th class="data">Message</th>' +
|
||||
'<th class="freq">Freq</th>' +
|
||||
'<th class="text">Text</th>' +
|
||||
'</tr></thead>' +
|
||||
'<tbody></tbody>' +
|
||||
'</table>'
|
||||
|
|
@ -907,30 +906,40 @@ CwSkimmerMessagePanel.prototype.pushMessage = function(msg) {
|
|||
// Must have some text
|
||||
if (!msg.text) return;
|
||||
|
||||
// Find existing frequency
|
||||
var j = this.freqs.indexOf(msg.freq);
|
||||
if (j >= 0) {
|
||||
// Clear cache if requested
|
||||
if (msg.changed) this.texts = [];
|
||||
|
||||
// Current time
|
||||
var now = Date.now();
|
||||
|
||||
// Modify or add a new entry
|
||||
var j = this.texts.findIndex(function(x) { return x.freq >= msg.freq });
|
||||
if (j < 0) {
|
||||
// Append a new entry
|
||||
this.texts.push({ freq: msg.freq, text: msg.text, ts: now });
|
||||
} else if (this.texts[j].freq == msg.freq) {
|
||||
// Update existing entry
|
||||
this.texts[j] = (this.texts[j] + msg.text).slice(-64);
|
||||
this.texts[j].text = (this.texts[j].text + msg.text).slice(-64);
|
||||
this.texts[j].ts = now;
|
||||
} else {
|
||||
// Add a new entry
|
||||
this.freqs.push(msg.freq);
|
||||
this.texts.push(msg.text);
|
||||
// Limit the number of active frequencies
|
||||
// if (this.freqs.length > 16) {
|
||||
// this.freqs.shift();
|
||||
// this.texts.shift();
|
||||
// }
|
||||
// Insert a new entry
|
||||
this.texts.splice(j, 0, { freq: msg.freq, text: msg.text, ts: now });
|
||||
}
|
||||
|
||||
// Generate table body
|
||||
var body = '';
|
||||
for (j = 0 ; j < this.freqs.length ; j++) {
|
||||
for (var j = 0 ; j < this.texts.length ; j++) {
|
||||
// Limit the lifetime of entries depending on their length
|
||||
var cutoff = 5000 * this.texts[j].text.length;
|
||||
if (now - this.texts[j].ts >= cutoff) {
|
||||
this.texts.splice(j--, 1);
|
||||
} else {
|
||||
var f = Math.floor(this.texts[j].freq / 100.0) / 10.0;
|
||||
body +=
|
||||
'<tr style="color:black;background-color:' + (j&1? '#E0FFE0':'#FFFFFF') +
|
||||
';"><td style="text-align:right;">' + Math.round(this.freqs[j]/10)/100 +
|
||||
'</td><td style="font-family:monospace;white-space:nowrap;">' +
|
||||
this.texts[j] + '</td></tr>\n';
|
||||
';"><td class="freq">' + f.toFixed(1) +
|
||||
'</td><td class="text">' + this.texts[j].text + '</td></tr>\n';
|
||||
}
|
||||
}
|
||||
|
||||
// Assign new table body
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ class FeatureDetector(object):
|
|||
"mqtt": ["paho_mqtt"],
|
||||
"hdradio": ["nrsc5"],
|
||||
"rigcontrol": ["hamlib"],
|
||||
"cwskimmer": ["csdr_cwskimmer"],
|
||||
}
|
||||
|
||||
def feature_availability(self):
|
||||
|
|
@ -775,3 +776,11 @@ class FeatureDetector(object):
|
|||
The `hamlib` package is available in most Linux distributions.
|
||||
"""
|
||||
return self.command_is_runnable("rigctl -V")
|
||||
|
||||
def has_csdr_cwskimmer(self):
|
||||
"""
|
||||
OpenWebRX uses the [CSDR CWSkimmer](https://github.com/luarvique/csdr-cwskimmer)
|
||||
to decode multiple CW signals at once. You can install the
|
||||
`csdr-cwskimmer` package from the OpenWebRX+ repositories.
|
||||
"""
|
||||
return self.command_is_runnable("csdr-cwskimmer -h")
|
||||
|
|
|
|||
|
|
@ -174,6 +174,9 @@ class Modes(object):
|
|||
service=True,
|
||||
squelch=False,
|
||||
),
|
||||
# Replaced by Jakob's RTTY decoder
|
||||
# DigitalMode("mfrtty170", "RTTY-170", underlying=["usb"]),
|
||||
# DigitalMode("mfrtty450", "RTTY-450", underlying=["usb"]),
|
||||
# Replaced by the general paging decoder (both POCSAG and FLEX)
|
||||
# DigitalMode(
|
||||
# "pocsag",
|
||||
|
|
@ -194,10 +197,14 @@ class Modes(object):
|
|||
squelch=False,
|
||||
),
|
||||
DigitalMode("cwdecoder", "CW Decoder", underlying=["usb", "lsb"]),
|
||||
DigitalMode("cwskimmer", "CW Skimmer", underlying=["usb", "lsb"]),
|
||||
# Replaced by Jakob's RTTY decoder
|
||||
# DigitalMode("mfrtty170", "RTTY-170", underlying=["usb"]),
|
||||
# DigitalMode("mfrtty450", "RTTY-450", underlying=["usb"]),
|
||||
DigitalMode(
|
||||
"cwskimmer",
|
||||
"CW Skimmer",
|
||||
underlying=["usbd"],
|
||||
requirements=["cwskimmer"],
|
||||
service=False,
|
||||
squelch=False,
|
||||
),
|
||||
DigitalMode(
|
||||
"sstv",
|
||||
"SSTV",
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ class EasParser(TextParser):
|
|||
class CwSkimmerParser(TextParser):
|
||||
def __init__(self, service: bool = False):
|
||||
self.reLine = re.compile("^(\d+):(.+)$")
|
||||
self.freqChanged = False
|
||||
# Construct parent object
|
||||
super().__init__(filePrefix="CW", service=service)
|
||||
|
||||
|
|
@ -438,7 +439,15 @@ class CwSkimmerParser(TextParser):
|
|||
# Add frequency, if known
|
||||
if self.frequency:
|
||||
out["freq"] = self.frequency + freq
|
||||
# Report frequency changes
|
||||
if self.freqChanged:
|
||||
self.freqChanged = False
|
||||
out["changed"] = True
|
||||
# Done
|
||||
return out
|
||||
# No result
|
||||
return None
|
||||
|
||||
def setDialFrequency(self, frequency: int) -> None:
|
||||
self.freqChanged = frequency != self.frequency
|
||||
super().setDialFrequency(frequency)
|
||||
|
|
|
|||
Loading…
Reference in New Issue