add Q65 mode integration
This commit is contained in:
parent
e66be7c12d
commit
d6d6d97a13
@ -1,7 +1,8 @@
|
|||||||
**unreleased**
|
**unreleased**
|
||||||
- Introduced `squelch_auto_margin` config option that allows configuring the auto squelch level
|
- Introduced `squelch_auto_margin` config option that allows configuring the auto squelch level
|
||||||
- Removed `port` configuration option; `rtltcp_compat` takes the port number with the new connectors
|
- Removed `port` configuration option; `rtltcp_compat` takes the port number with the new connectors
|
||||||
- Added support for new WSJT-X modes FST4 and FST4W (only available with WSJT-X 2.3)
|
- Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X 2.3) and Q65 (only avilable with
|
||||||
|
WSJT-X 2.4)
|
||||||
- Added support for demodulating M17 digital voice signals using m17-cxx-demod
|
- Added support for demodulating M17 digital voice signals using m17-cxx-demod
|
||||||
- New reporting infrastructure, allowing WSPR and FST4W spots to be sent to wsprnet.org
|
- New reporting infrastructure, allowing WSPR and FST4W spots to be sent to wsprnet.org
|
||||||
- Add some basic filtering capabilities to the map
|
- Add some basic filtering capabilities to the map
|
||||||
|
@ -318,6 +318,10 @@ fst4_enabled_intervals = [15, 30]
|
|||||||
# available values (in seconds): 120, 300, 900, 1800
|
# available values (in seconds): 120, 300, 900, 1800
|
||||||
fst4w_enabled_intervals = [120, 300]
|
fst4w_enabled_intervals = [120, 300]
|
||||||
|
|
||||||
|
# Q65 allows many combinations of intervals and submodes. This setting determines which combinations will be decoded.
|
||||||
|
# Please use python tuples of (interval: int, mode: str) to specify the combinations. For example:
|
||||||
|
q65_enabled_combinations = [(30, "A"), (120, "E"), (60, "C")]
|
||||||
|
|
||||||
# JS8 comes in different speeds: normal, slow, fast, turbo. This setting controls which ones are enabled.
|
# JS8 comes in different speeds: normal, slow, fast, turbo. This setting controls which ones are enabled.
|
||||||
js8_enabled_profiles = ["normal", "slow"]
|
js8_enabled_profiles = ["normal", "slow"]
|
||||||
# JS8 decoding depth; higher value will get more results, but will also consume more cpu
|
# JS8 decoding depth; higher value will get more results, but will also consume more cpu
|
||||||
|
@ -29,7 +29,7 @@ import math
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from owrx.kiss import KissClient, DirewolfConfig
|
from owrx.kiss import KissClient, DirewolfConfig
|
||||||
from owrx.wsjt import Ft8Profile, WsprProfile, Jt9Profile, Jt65Profile, Ft4Profile, Fst4Profile, Fst4wProfile
|
from owrx.wsjt import Ft8Profile, WsprProfile, Jt9Profile, Jt65Profile, Ft4Profile, Fst4Profile, Fst4wProfile, Q65Profile
|
||||||
from owrx.js8 import Js8Profiles
|
from owrx.js8 import Js8Profiles
|
||||||
from owrx.audio import AudioChopper
|
from owrx.audio import AudioChopper
|
||||||
|
|
||||||
@ -433,6 +433,8 @@ class dsp(object):
|
|||||||
chopper_profiles = Fst4Profile.getEnabledProfiles()
|
chopper_profiles = Fst4Profile.getEnabledProfiles()
|
||||||
elif smd == "fst4w":
|
elif smd == "fst4w":
|
||||||
chopper_profiles = Fst4wProfile.getEnabledProfiles()
|
chopper_profiles = Fst4wProfile.getEnabledProfiles()
|
||||||
|
elif smd == "q65":
|
||||||
|
chopper_profiles = Q65Profile.getEnabledProfiles()
|
||||||
if chopper_profiles is not None and len(chopper_profiles):
|
if chopper_profiles is not None and len(chopper_profiles):
|
||||||
chopper = AudioChopper(self, self.secondary_process_demod.stdout, *chopper_profiles)
|
chopper = AudioChopper(self, self.secondary_process_demod.stdout, *chopper_profiles)
|
||||||
chopper.start()
|
chopper.start()
|
||||||
@ -573,7 +575,7 @@ class dsp(object):
|
|||||||
def isWsjtMode(self, demodulator=None):
|
def isWsjtMode(self, demodulator=None):
|
||||||
if demodulator is None:
|
if demodulator is None:
|
||||||
demodulator = self.get_secondary_demodulator()
|
demodulator = self.get_secondary_demodulator()
|
||||||
return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w"]
|
return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]
|
||||||
|
|
||||||
def isJs8(self, demodulator=None):
|
def isJs8(self, demodulator=None):
|
||||||
if demodulator is None:
|
if demodulator is None:
|
||||||
|
4
debian/changelog
vendored
4
debian/changelog
vendored
@ -3,8 +3,8 @@ openwebrx (0.21.0) UNRELEASED; urgency=low
|
|||||||
auto squelch level
|
auto squelch level
|
||||||
* Removed `port` configuration option; `rtltcp_compat` takes the port number
|
* Removed `port` configuration option; `rtltcp_compat` takes the port number
|
||||||
with the new connectors
|
with the new connectors
|
||||||
* Added support for new WSJT-X modes FST4 and FST4W (only available with
|
* Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X
|
||||||
WSJT-X 2.3)
|
2.3) and Q65 (only available with WSJT-X 2.4)
|
||||||
* Added support for demodulating M17 digital voice signals using
|
* Added support for demodulating M17 digital voice signals using
|
||||||
m17-cxx-demod
|
m17-cxx-demod
|
||||||
* New reporting infrastructure, allowing WSPR and FST4W spots to be sent to
|
* New reporting infrastructure, allowing WSPR and FST4W spots to be sent to
|
||||||
|
@ -1192,6 +1192,7 @@ img.openwebrx-mirror-img
|
|||||||
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-content-container,
|
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-content-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-content-container,
|
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-content-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-content-container,
|
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-content-container,
|
||||||
|
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-content-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel,
|
#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="wspr"] #openwebrx-digimode-select-channel,
|
||||||
#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-select-channel,
|
#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-select-channel,
|
||||||
@ -1201,7 +1202,8 @@ img.openwebrx-mirror-img
|
|||||||
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-select-channel,
|
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-select-channel,
|
||||||
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-select-channel,
|
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-select-channel,
|
||||||
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-select-channel,
|
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-select-channel,
|
||||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-select-channel
|
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-select-channel,
|
||||||
|
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-select-channel
|
||||||
{
|
{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -1215,7 +1217,8 @@ img.openwebrx-mirror-img
|
|||||||
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-canvas-container,
|
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-canvas-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-canvas-container,
|
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-canvas-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-canvas-container,
|
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-canvas-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-canvas-container
|
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-canvas-container,
|
||||||
|
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-canvas-container
|
||||||
{
|
{
|
||||||
height: 200px;
|
height: 200px;
|
||||||
margin: -10px;
|
margin: -10px;
|
||||||
|
@ -158,7 +158,7 @@ DemodulatorPanel.prototype.updatePanels = function() {
|
|||||||
var modulation = this.getDemodulator().get_secondary_demod();
|
var modulation = this.getDemodulator().get_secondary_demod();
|
||||||
$('#openwebrx-panel-digimodes').attr('data-mode', modulation);
|
$('#openwebrx-panel-digimodes').attr('data-mode', modulation);
|
||||||
toggle_panel("openwebrx-panel-digimodes", !!modulation);
|
toggle_panel("openwebrx-panel-digimodes", !!modulation);
|
||||||
toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4', 'fst4', 'fst4w'].indexOf(modulation) >= 0);
|
toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4', 'fst4', 'fst4w', "q65"].indexOf(modulation) >= 0);
|
||||||
toggle_panel("openwebrx-panel-js8-message", modulation == "js8");
|
toggle_panel("openwebrx-panel-js8-message", modulation == "js8");
|
||||||
toggle_panel("openwebrx-panel-packet-message", modulation === "packet");
|
toggle_panel("openwebrx-panel-packet-message", modulation === "packet");
|
||||||
toggle_panel("openwebrx-panel-pocsag-message", modulation === "pocsag");
|
toggle_panel("openwebrx-panel-pocsag-message", modulation === "pocsag");
|
||||||
|
@ -78,7 +78,7 @@ WsjtMessagePanel.prototype.pushMessage = function(msg) {
|
|||||||
return $('<div/>').text(input).html()
|
return $('<div/>').text(input).html()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (['FT8', 'JT65', 'JT9', 'FT4', 'FST4'].indexOf(msg['mode']) >= 0) {
|
if (['FT8', 'JT65', 'JT9', 'FT4', 'FST4', 'Q65'].indexOf(msg['mode']) >= 0) {
|
||||||
matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/);
|
matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/);
|
||||||
if (matches && matches[2] !== 'RR73') {
|
if (matches && matches[2] !== 'RR73') {
|
||||||
linkedmsg = html_escape(matches[1]) + '<a href="map?locator=' + matches[2] + '" target="openwebrx-map">' + matches[2] + '</a>';
|
linkedmsg = html_escape(matches[1]) + '<a href="map?locator=' + matches[2] + '" target="openwebrx-map">' + matches[2] + '</a>';
|
||||||
|
@ -98,6 +98,9 @@ class Modes(object):
|
|||||||
requirements=["wsjt-x-2-3"],
|
requirements=["wsjt-x-2-3"],
|
||||||
service=True,
|
service=True,
|
||||||
),
|
),
|
||||||
|
DigitalMode(
|
||||||
|
"q65", "Q65", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x-2-4"], service=True
|
||||||
|
),
|
||||||
DigitalMode(
|
DigitalMode(
|
||||||
"js8", "JS8Call", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["js8call"], service=True
|
"js8", "JS8Call", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["js8call"], service=True
|
||||||
),
|
),
|
||||||
|
@ -18,7 +18,7 @@ class PskReporter(Reporter):
|
|||||||
interval = 300
|
interval = 300
|
||||||
|
|
||||||
def getSupportedModes(self):
|
def getSupportedModes(self):
|
||||||
return ["FT8", "FT4", "JT9", "JT65", "FST4", "JS8"]
|
return ["FT8", "FT4", "JT9", "JT65", "FST4", "JS8", "Q65"]
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.cancelTimer()
|
self.cancelTimer()
|
||||||
|
32
owrx/wsjt.py
32
owrx/wsjt.py
@ -7,6 +7,7 @@ from owrx.parser import Parser
|
|||||||
from owrx.audio import AudioChopperProfile
|
from owrx.audio import AudioChopperProfile
|
||||||
from abc import ABC, ABCMeta, abstractmethod
|
from abc import ABC, ABCMeta, abstractmethod
|
||||||
from owrx.config import Config
|
from owrx.config import Config
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -142,6 +143,37 @@ class Fst4wProfile(WsjtProfile):
|
|||||||
return [Fst4wProfile(i) for i in profiles if i in Fst4wProfile.availableIntervals]
|
return [Fst4wProfile(i) for i in profiles if i in Fst4wProfile.availableIntervals]
|
||||||
|
|
||||||
|
|
||||||
|
class Q65Mode(Enum):
|
||||||
|
A = 1
|
||||||
|
B = 2
|
||||||
|
C = 3
|
||||||
|
D = 4
|
||||||
|
E = 5
|
||||||
|
|
||||||
|
|
||||||
|
class Q65Profile(WsjtProfile):
|
||||||
|
availableIntervals = [15, 30, 60, 120, 300]
|
||||||
|
|
||||||
|
def __init__(self, interval, mode: Q65Mode):
|
||||||
|
self.interval = interval
|
||||||
|
self.mode = mode
|
||||||
|
|
||||||
|
def getMode(self):
|
||||||
|
return "Q65"
|
||||||
|
|
||||||
|
def getInterval(self):
|
||||||
|
return self.interval
|
||||||
|
|
||||||
|
def decoder_commandline(self, file):
|
||||||
|
return ["jt9", "--q65", "-p", str(self.interval), "-b", self.mode.name, "-d", str(self.decoding_depth()), file]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getEnabledProfiles():
|
||||||
|
config = Config.get()
|
||||||
|
profiles = config["q65_enabled_combinations"] if "q65_enabled_combinations" in config else []
|
||||||
|
return [Q65Profile(i, Q65Mode[m]) for i, m in profiles if i in Fst4wProfile.availableIntervals]
|
||||||
|
|
||||||
|
|
||||||
class WsjtParser(Parser):
|
class WsjtParser(Parser):
|
||||||
def parse(self, messages):
|
def parse(self, messages):
|
||||||
for data in messages:
|
for data in messages:
|
||||||
|
Loading…
Reference in New Issue
Block a user