Compare commits
5 Commits
develop
...
active_arr
Author | SHA1 | Date | |
---|---|---|---|
|
b31581dc80 | ||
|
f73c62c5df | ||
|
e7e5af9a53 | ||
|
c7d2a5502c | ||
|
59759fa79d |
@ -1,6 +1,5 @@
|
||||
**unreleased**
|
||||
- SDR device log messages are now available in the web configuration to simplify troubleshooting
|
||||
- Added support for the MSK144 digimode
|
||||
|
||||
**1.2.1**
|
||||
- FifiSDR support fixed (pipeline formats now line up correctly)
|
||||
|
@ -14,7 +14,7 @@ It has the following features:
|
||||
- supports a wide range of [SDR hardware](https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices)
|
||||
- Multiple SDR devices can be used simultaneously
|
||||
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag, D-Star, NXDN)
|
||||
- [wsjt-x](https://wsjt.sourceforge.io/) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
|
||||
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
|
||||
FST4W)
|
||||
- [direwolf](https://github.com/wb2osz/direwolf) based demodulation of APRS packets
|
||||
- [JS8Call](http://js8call.com/) support
|
||||
|
12
bands.json
12
bands.json
@ -177,8 +177,7 @@
|
||||
"jt9": 50312000,
|
||||
"ft4": 50318000,
|
||||
"js8": 50318000,
|
||||
"q65": [50211000, 50275000],
|
||||
"msk144": 50260000
|
||||
"q65": [50211000, 50275000]
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
@ -187,8 +186,7 @@
|
||||
"lower_bound": 70150000,
|
||||
"upper_bound": 70200000,
|
||||
"frequencies": {
|
||||
"wspr": 70091000,
|
||||
"msk144": 70230000
|
||||
"wspr": 70091000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
@ -202,8 +200,7 @@
|
||||
"ft4": 144170000,
|
||||
"jt65": 144120000,
|
||||
"packet": 144800000,
|
||||
"q65": 144116000,
|
||||
"msk144": 144360000
|
||||
"q65": 144116000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
@ -213,8 +210,7 @@
|
||||
"upper_bound": 440000000,
|
||||
"frequencies": {
|
||||
"pocsag": 439987500,
|
||||
"q65": 432065000,
|
||||
"msk144": 432360000
|
||||
"q65": 432065000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
|
@ -1,5 +1,4 @@
|
||||
from csdr.chain.demodulator import ServiceDemodulator, SecondaryDemodulator, DialFrequencyReceiver, SecondarySelectorChain
|
||||
from csdr.module.msk144 import Msk144Module, ParserAdapter
|
||||
from owrx.audio.chopper import AudioChopper, AudioChopperParser
|
||||
from owrx.aprs.kiss import KissDeframer
|
||||
from owrx.aprs import Ax25Parser, AprsParser
|
||||
@ -21,23 +20,6 @@ class AudioChopperDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
||||
self.chopper.setDialFrequency(frequency)
|
||||
|
||||
|
||||
class Msk144Demodulator(ServiceDemodulator, DialFrequencyReceiver):
|
||||
def __init__(self):
|
||||
self.parser = ParserAdapter()
|
||||
workers = [
|
||||
Convert(Format.FLOAT, Format.SHORT),
|
||||
Msk144Module(),
|
||||
self.parser,
|
||||
]
|
||||
super().__init__(workers)
|
||||
|
||||
def getFixedAudioRate(self) -> int:
|
||||
return 12000
|
||||
|
||||
def setDialFrequency(self, frequency: int) -> None:
|
||||
self.parser.setDialFrequency(frequency)
|
||||
|
||||
|
||||
class PacketDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
||||
def __init__(self, service: bool = False):
|
||||
self.parser = AprsParser()
|
||||
|
@ -126,7 +126,7 @@ class PopenModule(AutoStartModule, metaclass=ABCMeta):
|
||||
# resume in case the reader has been stop()ed before
|
||||
self.reader.resume()
|
||||
Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start()
|
||||
Thread(target=self.pump(partial(self.process.stdout.read1, 1024), self.writer.write)).start()
|
||||
Thread(target=self.pump(partial(self.process.stdout.read, 1024), self.writer.write)).start()
|
||||
|
||||
def stop(self):
|
||||
if self.process is not None:
|
||||
|
@ -1,57 +0,0 @@
|
||||
from pycsdr.types import Format
|
||||
from csdr.module import PopenModule, ThreadModule
|
||||
from owrx.wsjt import WsjtParser, Msk144Profile
|
||||
import pickle
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Msk144Module(PopenModule):
|
||||
def getCommand(self):
|
||||
return ["msk144decoder"]
|
||||
|
||||
def getInputFormat(self) -> Format:
|
||||
return Format.SHORT
|
||||
|
||||
def getOutputFormat(self) -> Format:
|
||||
return Format.CHAR
|
||||
|
||||
|
||||
class ParserAdapter(ThreadModule):
|
||||
def __init__(self):
|
||||
self.retained = bytes()
|
||||
self.parser = WsjtParser()
|
||||
self.dialFrequency = 0
|
||||
super().__init__()
|
||||
|
||||
def run(self):
|
||||
profile = Msk144Profile()
|
||||
|
||||
while self.doRun:
|
||||
data = self.reader.read()
|
||||
if data is None:
|
||||
self.doRun = False
|
||||
else:
|
||||
self.retained += data
|
||||
lines = self.retained.split(b"\n")
|
||||
|
||||
# keep the last line
|
||||
# this should either be empty if the last char was \n
|
||||
# or an incomplete line if the read returned early
|
||||
self.retained = lines[-1]
|
||||
|
||||
# parse all completed lines
|
||||
for line in lines[0:-1]:
|
||||
# actual messages from msk144decoder should start with "*** "
|
||||
if line[0:4] == b"*** ":
|
||||
self.writer.write(pickle.dumps(self.parser.parse(profile, self.dialFrequency, line[4:])))
|
||||
|
||||
def getInputFormat(self) -> Format:
|
||||
return Format.CHAR
|
||||
|
||||
def getOutputFormat(self) -> Format:
|
||||
return Format.CHAR
|
||||
|
||||
def setDialFrequency(self, frequency: int) -> None:
|
||||
self.dialFrequency = frequency
|
1
debian/changelog
vendored
1
debian/changelog
vendored
@ -1,7 +1,6 @@
|
||||
openwebrx (1.3.0) UNRELEASED; urgency=low
|
||||
* SDR device log messages are now available in the web configuration to
|
||||
simplify troubleshooting
|
||||
* Added support for the MSK144 digimode
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Fri, 30 Sep 2022 16:47:00 +0000
|
||||
|
||||
|
2
debian/control
vendored
2
debian/control
vendored
@ -11,6 +11,6 @@ Vcs-Git: https://github.com/jketterl/openwebrx.git
|
||||
Package: openwebrx
|
||||
Architecture: all
|
||||
Depends: adduser, python3 (>= 3.5), python3-pkg-resources, owrx-connector (>= 0.5), soapysdr-tools, python3-csdr (>= 0.18), ${python3:Depends}, ${misc:Depends}
|
||||
Recommends: python3-digiham (>= 0.6), direwolf (>= 1.4), wsjtx, js8call, runds-connector (>= 0.2), hpsdrconnector, aprs-symbols, m17-demod, js8call, python3-js8py (>= 0.2), nmux (>= 0.18), codecserver (>= 0.1), msk144decoder
|
||||
Recommends: python3-digiham (>= 0.6), direwolf (>= 1.4), wsjtx, js8call, runds-connector (>= 0.2), hpsdrconnector, aprs-symbols, m17-demod, js8call, python3-js8py (>= 0.2), nmux (>= 0.18), codecserver (>= 0.1)
|
||||
Description: multi-user web sdr
|
||||
Open source, multi-user SDR receiver with a web interface
|
||||
|
@ -1,341 +1,310 @@
|
||||
diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
--- wsjtx-orig/CMakeLists.txt 2023-01-28 17:43:05.586124507 +0100
|
||||
+++ wsjtx/CMakeLists.txt 2023-01-28 17:56:07.108634912 +0100
|
||||
--- wsjtx-orig/CMakeLists.txt 2021-11-02 16:34:09.361811689 +0100
|
||||
+++ wsjtx/CMakeLists.txt 2021-11-02 16:38:36.696088115 +0100
|
||||
@@ -122,7 +122,7 @@
|
||||
option (WSJT_QDEBUG_TO_FILE "Redirect Qt debuging messages to a trace file.")
|
||||
option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients." ON)
|
||||
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
|
||||
-option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||
+option (WSJT_GENERATE_DOCS "Generate documentation files.")
|
||||
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
||||
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
|
||||
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
||||
@@ -170,77 +170,7 @@
|
||||
)
|
||||
|
||||
set (wsjt_qt_CXXSRCS
|
||||
- helper_functions.cpp
|
||||
- qt_helpers.cpp
|
||||
- widgets/MessageBox.cpp
|
||||
- MetaDataRegistry.cpp
|
||||
- Network/NetworkServerLookup.cpp
|
||||
revision_utils.cpp
|
||||
- L10nLoader.cpp
|
||||
- WFPalette.cpp
|
||||
- Radio.cpp
|
||||
- RadioMetaType.cpp
|
||||
- NonInheritingProcess.cpp
|
||||
- models/IARURegions.cpp
|
||||
- models/Bands.cpp
|
||||
- models/Modes.cpp
|
||||
- models/FrequencyList.cpp
|
||||
- models/StationList.cpp
|
||||
- widgets/FrequencyLineEdit.cpp
|
||||
- widgets/FrequencyDeltaLineEdit.cpp
|
||||
- item_delegates/CandidateKeyFilter.cpp
|
||||
- item_delegates/ForeignKeyDelegate.cpp
|
||||
- item_delegates/MessageItemDelegate.cpp
|
||||
- validators/LiveFrequencyValidator.cpp
|
||||
- GetUserId.cpp
|
||||
- Audio/AudioDevice.cpp
|
||||
- Transceiver/Transceiver.cpp
|
||||
- Transceiver/TransceiverBase.cpp
|
||||
- Transceiver/EmulateSplitTransceiver.cpp
|
||||
- Transceiver/TransceiverFactory.cpp
|
||||
- Transceiver/PollingTransceiver.cpp
|
||||
- Transceiver/HamlibTransceiver.cpp
|
||||
- Transceiver/HRDTransceiver.cpp
|
||||
- Transceiver/DXLabSuiteCommanderTransceiver.cpp
|
||||
- Network/NetworkMessage.cpp
|
||||
- Network/MessageClient.cpp
|
||||
- widgets/LettersSpinBox.cpp
|
||||
- widgets/HintedSpinBox.cpp
|
||||
- widgets/RestrictedSpinBox.cpp
|
||||
- widgets/HelpTextWindow.cpp
|
||||
- SampleDownloader.cpp
|
||||
- SampleDownloader/DirectoryDelegate.cpp
|
||||
- SampleDownloader/Directory.cpp
|
||||
- SampleDownloader/FileNode.cpp
|
||||
- SampleDownloader/RemoteFile.cpp
|
||||
- DisplayManual.cpp
|
||||
- MultiSettings.cpp
|
||||
- validators/MaidenheadLocatorValidator.cpp
|
||||
- validators/CallsignValidator.cpp
|
||||
- widgets/SplashScreen.cpp
|
||||
- EqualizationToolsDialog.cpp
|
||||
- widgets/DoubleClickablePushButton.cpp
|
||||
- widgets/DoubleClickableRadioButton.cpp
|
||||
- Network/LotWUsers.cpp
|
||||
- models/DecodeHighlightingModel.cpp
|
||||
- widgets/DecodeHighlightingListView.cpp
|
||||
- models/FoxLog.cpp
|
||||
- widgets/AbstractLogWindow.cpp
|
||||
- widgets/FoxLogWindow.cpp
|
||||
- widgets/CabrilloLogWindow.cpp
|
||||
- item_delegates/CallsignDelegate.cpp
|
||||
- item_delegates/MaidenheadLocatorDelegate.cpp
|
||||
- item_delegates/FrequencyDelegate.cpp
|
||||
- item_delegates/FrequencyDeltaDelegate.cpp
|
||||
- item_delegates/SQLiteDateTimeDelegate.cpp
|
||||
- models/CabrilloLog.cpp
|
||||
- logbook/AD1CCty.cpp
|
||||
- logbook/WorkedBefore.cpp
|
||||
- logbook/Multiplier.cpp
|
||||
- Network/NetworkAccessManager.cpp
|
||||
- widgets/LazyFillComboBox.cpp
|
||||
- widgets/CheckableItemComboBox.cpp
|
||||
- widgets/BandComboBox.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
@@ -1089,9 +1019,6 @@
|
||||
if (WSJT_GENERATE_DOCS)
|
||||
add_subdirectory (doc)
|
||||
endif (WSJT_GENERATE_DOCS)
|
||||
-if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests)
|
||||
- add_subdirectory (tests)
|
||||
-endif ()
|
||||
|
||||
# build a library of package functionality (without and optionally with OpenMP support)
|
||||
add_library (wsjt_cxx STATIC ${wsjt_CSRCS} ${wsjt_CXXSRCS})
|
||||
@@ -1357,10 +1284,7 @@
|
||||
add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${wsjt_qt_GENUISRCS} ${GENAXSRCS})
|
||||
# set wsjtx_udp exports to static variants
|
||||
target_compile_definitions (wsjt_qt PUBLIC UDP_STATIC_DEFINE)
|
||||
-target_link_libraries (wsjt_qt Hamlib::Hamlib Boost::log qcp Qt5::Widgets Qt5::Network Qt5::Sql)
|
||||
-if (WIN32)
|
||||
- target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase)
|
||||
-endif (WIN32)
|
||||
+target_link_libraries (wsjt_qt Qt5::Core)
|
||||
|
||||
# build a library of package Qt functionality used in Fortran utilities
|
||||
add_library (fort_qt STATIC ${fort_qt_CXXSRCS})
|
||||
@@ -1425,90 +1349,6 @@
|
||||
add_subdirectory (map65)
|
||||
endif ()
|
||||
|
||||
-# build the main application
|
||||
-generate_version_info (wsjtx_VERSION_RESOURCES
|
||||
- NAME wsjtx
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- )
|
||||
-
|
||||
-add_executable (wsjtx MACOSX_BUNDLE
|
||||
- ${wsjtx_CXXSRCS}
|
||||
- ${wsjtx_GENUISRCS}
|
||||
- ${WSJTX_ICON_FILE}
|
||||
- ${wsjtx_RESOURCES_RCC}
|
||||
- ${wsjtx_VERSION_RESOURCES}
|
||||
- )
|
||||
-
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-set_target_properties (wsjtx PROPERTIES
|
||||
- MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
|
||||
- MACOSX_BUNDLE_INFO_STRING "${PROJECT_DESCRIPTION}"
|
||||
- MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||
- MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
|
||||
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
|
||||
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${SCS_VERSION_STR}"
|
||||
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_BUNDLE_NAME}"
|
||||
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
||||
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
||||
- MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
||||
- )
|
||||
-
|
||||
-target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
-if ((NOT ${OPENMP_FOUND}) OR APPLE)
|
||||
- target_link_libraries (wsjtx wsjt_fort)
|
||||
-else ()
|
||||
- target_link_libraries (wsjtx wsjt_fort_omp)
|
||||
- if (OpenMP_C_FLAGS)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- LINK_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- )
|
||||
- endif ()
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
|
||||
- )
|
||||
- if (WIN32)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- LINK_FLAGS -Wl,--stack,0x1000000,--heap,0x20000000
|
||||
- )
|
||||
- endif ()
|
||||
-endif ()
|
||||
-target_link_libraries (wsjtx Qt5::SerialPort wsjt_cxx wsjt_qt wsjt_qtmm ${FFTW3_LIBRARIES} ${LIBM_LIBRARIES})
|
||||
-
|
||||
-# make a library for WSJT-X UDP servers
|
||||
-# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
||||
-add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
|
||||
-#target_include_directories (wsjtx_udp
|
||||
-# INTERFACE
|
||||
-# $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/wsjtx>
|
||||
-# )
|
||||
-target_include_directories (wsjtx_udp-static
|
||||
- INTERFACE
|
||||
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/wsjtx>
|
||||
- )
|
||||
-#set_target_properties (wsjtx_udp PROPERTIES
|
||||
-# PUBLIC_HEADER "${UDP_library_HEADERS}"
|
||||
-# )
|
||||
-set_target_properties (wsjtx_udp-static PROPERTIES
|
||||
- OUTPUT_NAME wsjtx_udp
|
||||
- )
|
||||
-target_compile_definitions (wsjtx_udp-static PUBLIC UDP_STATIC_DEFINE)
|
||||
-target_link_libraries (wsjtx_udp-static Qt5::Network Qt5::Gui)
|
||||
-generate_export_header (wsjtx_udp-static BASE_NAME udp)
|
||||
-
|
||||
-generate_version_info (udp_daemon_VERSION_RESOURCES
|
||||
- NAME udp_daemon
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- FILE_DESCRIPTION "Example WSJT-X UDP Message Protocol daemon"
|
||||
- )
|
||||
-add_executable (udp_daemon UDPExamples/UDPDaemon.cpp ${udp_daemon_VERSION_RESOURCES})
|
||||
-target_link_libraries (udp_daemon wsjtx_udp-static)
|
||||
-
|
||||
generate_version_info (wsjtx_app_version_VERSION_RESOURCES
|
||||
NAME wsjtx_app_version
|
||||
BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
@@ -1518,47 +1358,9 @@
|
||||
add_executable (wsjtx_app_version AppVersion/AppVersion.cpp ${wsjtx_app_version_VERSION_RESOURCES})
|
||||
target_link_libraries (wsjtx_app_version wsjt_qt)
|
||||
|
||||
-generate_version_info (message_aggregator_VERSION_RESOURCES
|
||||
- NAME message_aggregator
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- FILE_DESCRIPTION "Example WSJT-X UDP Message Protocol application"
|
||||
- )
|
||||
-add_resources (message_aggregator_RESOURCES /qss ${message_aggregator_STYLESHEETS})
|
||||
-configure_file (UDPExamples/message_aggregator.qrc.in message_aggregator.qrc @ONLY)
|
||||
-qt5_add_resources (message_aggregator_RESOURCES_RCC
|
||||
- ${CMAKE_CURRENT_BINARY_DIR}/message_aggregator.qrc
|
||||
- contrib/QDarkStyleSheet/qdarkstyle/style.qrc
|
||||
- )
|
||||
-add_executable (message_aggregator
|
||||
- ${message_aggregator_CXXSRCS}
|
||||
- ${message_aggregator_RESOURCES_RCC}
|
||||
- ${message_aggregator_VERSION_RESOURCES}
|
||||
- )
|
||||
-target_link_libraries (message_aggregator wsjt_qt Qt5::Widgets wsjtx_udp-static)
|
||||
-
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-if (UNIX)
|
||||
- if (NOT WSJT_SKIP_MANPAGES)
|
||||
- add_subdirectory (manpages)
|
||||
- add_dependencies (wsjtx manpages)
|
||||
- endif (NOT WSJT_SKIP_MANPAGES)
|
||||
- if (NOT APPLE)
|
||||
- add_subdirectory (debian)
|
||||
- add_dependencies (wsjtx debian)
|
||||
- endif (NOT APPLE)
|
||||
-endif (UNIX)
|
||||
-
|
||||
#
|
||||
# installation
|
||||
#
|
||||
-install (TARGETS wsjtx
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION . COMPONENT runtime
|
||||
- )
|
||||
|
||||
# install (TARGETS wsjtx_udp EXPORT udp
|
||||
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@@ -1577,12 +1379,7 @@
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
|
||||
# )
|
||||
|
||||
-install (TARGETS udp_daemon message_aggregator wsjtx_app_version
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
-install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
+install (TARGETS wsjtx_app_version jt9 wsprd
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
@@ -1595,38 +1392,6 @@
|
||||
)
|
||||
endif(WSJT_BUILD_UTILS)
|
||||
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTL_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctl-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTLD_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctld-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTLCOM_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctlcom-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (FILES
|
||||
- README
|
||||
- COPYING
|
||||
- AUTHORS
|
||||
- THANKS
|
||||
- NEWS
|
||||
- BUGS
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
install (FILES
|
||||
cty.dat
|
||||
cty.dat_copyright.txt
|
||||
@@ -1635,13 +1400,6 @@
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
-install (DIRECTORY
|
||||
- example_log_configurations
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- FILES_MATCHING REGEX "^.*[^~]$"
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
#
|
||||
# Mac installer files
|
||||
#
|
||||
@@ -1693,22 +1451,6 @@
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/wsjtx_config.h"
|
||||
)
|
||||
|
||||
-
|
||||
-if (NOT WIN32 AND NOT APPLE)
|
||||
- # install a desktop file so wsjtx appears in the application start
|
||||
- # menu with an icon
|
||||
- install (
|
||||
- FILES wsjtx.desktop message_aggregator.desktop
|
||||
- DESTINATION share/applications
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
- install (
|
||||
- FILES icons/Unix/wsjtx_icon.png
|
||||
- DESTINATION share/pixmaps
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-endif (NOT WIN32 AND NOT APPLE)
|
||||
-
|
||||
if (APPLE)
|
||||
set (CMAKE_POSTFLIGHT_SCRIPT
|
||||
"${wsjtx_BINARY_DIR}/postflight.sh")
|
||||
option (WSJT_QDEBUG_TO_FILE "Redirect Qt debuging messages to a trace file.")
|
||||
option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients." ON)
|
||||
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
|
||||
-option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||
+option (WSJT_GENERATE_DOCS "Generate documentation files.")
|
||||
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
||||
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
|
||||
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
||||
@@ -169,76 +169,7 @@
|
||||
)
|
||||
|
||||
set (wsjt_qt_CXXSRCS
|
||||
- helper_functions.cpp
|
||||
- qt_helpers.cpp
|
||||
- widgets/MessageBox.cpp
|
||||
- MetaDataRegistry.cpp
|
||||
- Network/NetworkServerLookup.cpp
|
||||
revision_utils.cpp
|
||||
- L10nLoader.cpp
|
||||
- WFPalette.cpp
|
||||
- Radio.cpp
|
||||
- RadioMetaType.cpp
|
||||
- NonInheritingProcess.cpp
|
||||
- models/IARURegions.cpp
|
||||
- models/Bands.cpp
|
||||
- models/Modes.cpp
|
||||
- models/FrequencyList.cpp
|
||||
- models/StationList.cpp
|
||||
- widgets/FrequencyLineEdit.cpp
|
||||
- widgets/FrequencyDeltaLineEdit.cpp
|
||||
- item_delegates/CandidateKeyFilter.cpp
|
||||
- item_delegates/ForeignKeyDelegate.cpp
|
||||
- validators/LiveFrequencyValidator.cpp
|
||||
- GetUserId.cpp
|
||||
- Audio/AudioDevice.cpp
|
||||
- Transceiver/Transceiver.cpp
|
||||
- Transceiver/TransceiverBase.cpp
|
||||
- Transceiver/EmulateSplitTransceiver.cpp
|
||||
- Transceiver/TransceiverFactory.cpp
|
||||
- Transceiver/PollingTransceiver.cpp
|
||||
- Transceiver/HamlibTransceiver.cpp
|
||||
- Transceiver/HRDTransceiver.cpp
|
||||
- Transceiver/DXLabSuiteCommanderTransceiver.cpp
|
||||
- Network/NetworkMessage.cpp
|
||||
- Network/MessageClient.cpp
|
||||
- widgets/LettersSpinBox.cpp
|
||||
- widgets/HintedSpinBox.cpp
|
||||
- widgets/RestrictedSpinBox.cpp
|
||||
- widgets/HelpTextWindow.cpp
|
||||
- SampleDownloader.cpp
|
||||
- SampleDownloader/DirectoryDelegate.cpp
|
||||
- SampleDownloader/Directory.cpp
|
||||
- SampleDownloader/FileNode.cpp
|
||||
- SampleDownloader/RemoteFile.cpp
|
||||
- DisplayManual.cpp
|
||||
- MultiSettings.cpp
|
||||
- validators/MaidenheadLocatorValidator.cpp
|
||||
- validators/CallsignValidator.cpp
|
||||
- widgets/SplashScreen.cpp
|
||||
- EqualizationToolsDialog.cpp
|
||||
- widgets/DoubleClickablePushButton.cpp
|
||||
- widgets/DoubleClickableRadioButton.cpp
|
||||
- Network/LotWUsers.cpp
|
||||
- models/DecodeHighlightingModel.cpp
|
||||
- widgets/DecodeHighlightingListView.cpp
|
||||
- models/FoxLog.cpp
|
||||
- widgets/AbstractLogWindow.cpp
|
||||
- widgets/FoxLogWindow.cpp
|
||||
- widgets/CabrilloLogWindow.cpp
|
||||
- item_delegates/CallsignDelegate.cpp
|
||||
- item_delegates/MaidenheadLocatorDelegate.cpp
|
||||
- item_delegates/FrequencyDelegate.cpp
|
||||
- item_delegates/FrequencyDeltaDelegate.cpp
|
||||
- item_delegates/SQLiteDateTimeDelegate.cpp
|
||||
- models/CabrilloLog.cpp
|
||||
- logbook/AD1CCty.cpp
|
||||
- logbook/WorkedBefore.cpp
|
||||
- logbook/Multiplier.cpp
|
||||
- Network/NetworkAccessManager.cpp
|
||||
- widgets/LazyFillComboBox.cpp
|
||||
- widgets/CheckableItemComboBox.cpp
|
||||
- widgets/BandComboBox.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
@@ -1079,9 +1010,6 @@
|
||||
if (WSJT_GENERATE_DOCS)
|
||||
add_subdirectory (doc)
|
||||
endif (WSJT_GENERATE_DOCS)
|
||||
-if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests)
|
||||
- add_subdirectory (tests)
|
||||
-endif ()
|
||||
|
||||
# build a library of package functionality (without and optionally with OpenMP support)
|
||||
add_library (wsjt_cxx STATIC ${wsjt_CSRCS} ${wsjt_CXXSRCS})
|
||||
@@ -1340,10 +1268,7 @@
|
||||
add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${wsjt_qt_GENUISRCS} ${GENAXSRCS})
|
||||
# set wsjtx_udp exports to static variants
|
||||
target_compile_definitions (wsjt_qt PUBLIC UDP_STATIC_DEFINE)
|
||||
-target_link_libraries (wsjt_qt Hamlib::Hamlib Boost::log qcp Qt5::Widgets Qt5::Network Qt5::Sql)
|
||||
-if (WIN32)
|
||||
- target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase)
|
||||
-endif (WIN32)
|
||||
+target_link_libraries (wsjt_qt Qt5::Core)
|
||||
|
||||
# build a library of package Qt functionality used in Fortran utilities
|
||||
add_library (fort_qt STATIC ${fort_qt_CXXSRCS})
|
||||
@@ -1408,60 +1333,6 @@
|
||||
add_subdirectory (map65)
|
||||
endif ()
|
||||
|
||||
-# build the main application
|
||||
-generate_version_info (wsjtx_VERSION_RESOURCES
|
||||
- NAME wsjtx
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- )
|
||||
-
|
||||
-add_executable (wsjtx MACOSX_BUNDLE
|
||||
- ${wsjtx_CXXSRCS}
|
||||
- ${wsjtx_GENUISRCS}
|
||||
- ${WSJTX_ICON_FILE}
|
||||
- ${wsjtx_RESOURCES_RCC}
|
||||
- ${wsjtx_VERSION_RESOURCES}
|
||||
- )
|
||||
-
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-set_target_properties (wsjtx PROPERTIES
|
||||
- MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
|
||||
- MACOSX_BUNDLE_INFO_STRING "${PROJECT_DESCRIPTION}"
|
||||
- MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||
- MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
|
||||
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
|
||||
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${SCS_VERSION_STR}"
|
||||
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_BUNDLE_NAME}"
|
||||
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
||||
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
||||
- MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
||||
- )
|
||||
-
|
||||
-target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
-if (APPLE)
|
||||
- target_link_libraries (wsjtx wsjt_fort)
|
||||
-else ()
|
||||
- target_link_libraries (wsjtx wsjt_fort_omp)
|
||||
- if (OpenMP_C_FLAGS)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- LINK_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- )
|
||||
- endif ()
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
|
||||
- )
|
||||
- if (WIN32)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- LINK_FLAGS -Wl,--stack,0x1000000,--heap,0x20000000
|
||||
- )
|
||||
- endif ()
|
||||
-endif ()
|
||||
-target_link_libraries (wsjtx Qt5::SerialPort wsjt_cxx wsjt_qt wsjt_qtmm ${FFTW3_LIBRARIES} ${LIBM_LIBRARIES})
|
||||
-
|
||||
# make a library for WSJT-X UDP servers
|
||||
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
||||
add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
|
||||
@@ -1501,47 +1372,9 @@
|
||||
add_executable (wsjtx_app_version AppVersion/AppVersion.cpp ${wsjtx_app_version_VERSION_RESOURCES})
|
||||
target_link_libraries (wsjtx_app_version wsjt_qt)
|
||||
|
||||
-generate_version_info (message_aggregator_VERSION_RESOURCES
|
||||
- NAME message_aggregator
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- FILE_DESCRIPTION "Example WSJT-X UDP Message Protocol application"
|
||||
- )
|
||||
-add_resources (message_aggregator_RESOURCES /qss ${message_aggregator_STYLESHEETS})
|
||||
-configure_file (UDPExamples/message_aggregator.qrc.in message_aggregator.qrc @ONLY)
|
||||
-qt5_add_resources (message_aggregator_RESOURCES_RCC
|
||||
- ${CMAKE_CURRENT_BINARY_DIR}/message_aggregator.qrc
|
||||
- contrib/QDarkStyleSheet/qdarkstyle/style.qrc
|
||||
- )
|
||||
-add_executable (message_aggregator
|
||||
- ${message_aggregator_CXXSRCS}
|
||||
- ${message_aggregator_RESOURCES_RCC}
|
||||
- ${message_aggregator_VERSION_RESOURCES}
|
||||
- )
|
||||
-target_link_libraries (message_aggregator wsjt_qt Qt5::Widgets wsjtx_udp-static)
|
||||
-
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-if (UNIX)
|
||||
- if (NOT WSJT_SKIP_MANPAGES)
|
||||
- add_subdirectory (manpages)
|
||||
- add_dependencies (wsjtx manpages)
|
||||
- endif (NOT WSJT_SKIP_MANPAGES)
|
||||
- if (NOT APPLE)
|
||||
- add_subdirectory (debian)
|
||||
- add_dependencies (wsjtx debian)
|
||||
- endif (NOT APPLE)
|
||||
-endif (UNIX)
|
||||
-
|
||||
#
|
||||
# installation
|
||||
#
|
||||
-install (TARGETS wsjtx
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION . COMPONENT runtime
|
||||
- )
|
||||
|
||||
# install (TARGETS wsjtx_udp EXPORT udp
|
||||
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@@ -1560,12 +1393,7 @@
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
|
||||
# )
|
||||
|
||||
-install (TARGETS udp_daemon message_aggregator wsjtx_app_version
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
-install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
+install (TARGETS wsjtx_app_version jt9 wsprd
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
@@ -1578,38 +1406,6 @@
|
||||
)
|
||||
endif(WSJT_BUILD_UTILS)
|
||||
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTL_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctl-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTLD_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctld-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTLCOM_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctlcom-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (FILES
|
||||
- README
|
||||
- COPYING
|
||||
- AUTHORS
|
||||
- THANKS
|
||||
- NEWS
|
||||
- BUGS
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
install (FILES
|
||||
cty.dat
|
||||
cty.dat_copyright.txt
|
||||
@@ -1618,13 +1414,6 @@
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
-install (DIRECTORY
|
||||
- example_log_configurations
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- FILES_MATCHING REGEX "^.*[^~]$"
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
#
|
||||
# Mac installer files
|
||||
#
|
||||
@@ -1676,22 +1465,6 @@
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/wsjtx_config.h"
|
||||
)
|
||||
|
||||
-
|
||||
-if (NOT WIN32 AND NOT APPLE)
|
||||
- # install a desktop file so wsjtx appears in the application start
|
||||
- # menu with an icon
|
||||
- install (
|
||||
- FILES wsjtx.desktop message_aggregator.desktop
|
||||
- DESTINATION share/applications
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
- install (
|
||||
- FILES icons/Unix/wsjtx_icon.png
|
||||
- DESTINATION share/pixmaps
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-endif (NOT WIN32 AND NOT APPLE)
|
||||
-
|
||||
if (APPLE)
|
||||
set (CMAKE_POSTFLIGHT_SCRIPT
|
||||
"${wsjtx_BINARY_DIR}/postflight.sh")
|
||||
|
@ -38,7 +38,7 @@ case $ARCH in
|
||||
;;
|
||||
esac
|
||||
|
||||
wget --no-http-keep-alive https://www.sdrplay.com/software/$BINARY
|
||||
wget https://www.sdrplay.com/software/$BINARY
|
||||
sh $BINARY --noexec --target sdrplay
|
||||
patch --verbose -Np0 < /install-lib.$ARCH.patch
|
||||
|
||||
|
@ -7,9 +7,6 @@ function cmakebuild() {
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
if [[ -f ".gitmodules" ]]; then
|
||||
git submodule update --init
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ${CMAKE_ARGS:-} ..
|
||||
@ -21,8 +18,8 @@ function cmakebuild() {
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline8 libgfortran5 libgomp1 libasound2 libudev1 ca-certificates libpulse0 libfaad2 libopus0 libboost-program-options1.74.0 libboost-log1.74.0 libcurl4"
|
||||
BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-qmake libfaad-dev libopus-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev libpulse-dev libcurl4-openssl-dev"
|
||||
STATIC_PACKAGES="libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline8 libgfortran5 libgomp1 libasound2 libudev1 ca-certificates libpulse0 libfaad2 libopus0 libboost-program-options1.74.0 libboost-log1.74.0"
|
||||
BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-qmake libfaad-dev libopus-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev libpulse-dev"
|
||||
apt-get update
|
||||
apt-get -y install auto-apt-proxy
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
@ -54,19 +51,15 @@ rm /js8call-hamlib.patch
|
||||
cmakebuild ${JS8CALL_DIR}
|
||||
rm ${JS8CALL_TGZ}
|
||||
|
||||
WSJT_DIR=wsjtx-2.6.1
|
||||
WSJT_DIR=wsjtx-2.5.4
|
||||
WSJT_TGZ=${WSJT_DIR}.tgz
|
||||
wget https://downloads.sourceforge.net/project/wsjt/${WSJT_DIR}/${WSJT_TGZ}
|
||||
wget http://physics.princeton.edu/pulsar/k1jt/${WSJT_TGZ}
|
||||
tar xfz ${WSJT_TGZ}
|
||||
patch -Np0 -d ${WSJT_DIR} < /wsjtx-hamlib.patch
|
||||
mv /wsjtx.patch ${WSJT_DIR}
|
||||
cmakebuild ${WSJT_DIR}
|
||||
rm ${WSJT_TGZ}
|
||||
|
||||
git clone https://github.com/alexander-sholohov/msk144decoder.git
|
||||
# latest from main as of 2023-02-21
|
||||
MAKEFLAGS="" cmakebuild msk144decoder fe2991681e455636e258e83c29fd4b2a72d16095
|
||||
|
||||
git clone --depth 1 -b 1.6 https://github.com/wb2osz/direwolf.git
|
||||
cd direwolf
|
||||
# hamlib is present (necessary for the wsjt-x and js8call builds) and would be used, but there's no real need.
|
||||
|
@ -1265,7 +1265,6 @@ img.openwebrx-mirror-img
|
||||
#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="q65"] #openwebrx-digimode-content-container,
|
||||
#openwebrx-panel-digimodes[data-mode="msk144"] #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,
|
||||
@ -1276,8 +1275,7 @@ img.openwebrx-mirror-img
|
||||
#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="fst4w"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="msk144"] #openwebrx-digimode-select-channel
|
||||
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-select-channel
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
@ -1292,8 +1290,7 @@ img.openwebrx-mirror-img
|
||||
#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="fst4w"] #openwebrx-digimode-canvas-container,
|
||||
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-canvas-container,
|
||||
#openwebrx-panel-digimodes[data-mode="msk144"] #openwebrx-digimode-canvas-container
|
||||
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-canvas-container
|
||||
{
|
||||
height: 200px;
|
||||
margin: -10px;
|
||||
|
@ -331,9 +331,7 @@ ImaAdpcmCodec.prototype.reset = function() {
|
||||
this.synchronized = 0;
|
||||
this.syncWord = "SYNC";
|
||||
this.syncCounter = 0;
|
||||
this.phase = 0;
|
||||
this.syncBuffer = new Uint8Array(4);
|
||||
this.syncBufferIndex = 0;
|
||||
this.skip = 0;
|
||||
};
|
||||
|
||||
ImaAdpcmCodec.imaIndexTable = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 ];
|
||||
@ -361,45 +359,38 @@ ImaAdpcmCodec.prototype.decode = function(data) {
|
||||
|
||||
ImaAdpcmCodec.prototype.decodeWithSync = function(data) {
|
||||
var output = new Int16Array(data.length * 2);
|
||||
var index = this.skip;
|
||||
var oi = 0;
|
||||
for (var index = 0; index < data.length; index++) {
|
||||
switch (this.phase) {
|
||||
case 0:
|
||||
// search for sync word
|
||||
if (data[index] !== this.syncWord.charCodeAt(this.synchronized++)) {
|
||||
// reset if data is unexpected
|
||||
this.synchronized = 0;
|
||||
}
|
||||
// if sync word has been found pass on to next phase
|
||||
if (this.synchronized === 4) {
|
||||
this.syncBufferIndex = 0;
|
||||
this.phase = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// read codec runtime data from stream
|
||||
this.syncBuffer[this.syncBufferIndex++] = data[index];
|
||||
// if data is complete, apply and pass on to next phase
|
||||
if (this.syncBufferIndex === 4) {
|
||||
var syncData = new Int16Array(this.syncBuffer.buffer);
|
||||
while (index < data.length) {
|
||||
while (this.synchronized < 4 && index < data.length) {
|
||||
if (data[index] === this.syncWord.charCodeAt(this.synchronized)) {
|
||||
this.synchronized++;
|
||||
} else {
|
||||
this.synchronized = 0;
|
||||
}
|
||||
index++;
|
||||
if (this.synchronized === 4) {
|
||||
if (index + 4 < data.length) {
|
||||
var syncData = new Int16Array(data.buffer.slice(index, index + 4));
|
||||
this.stepIndex = syncData[0];
|
||||
this.predictor = syncData[1];
|
||||
this.syncCounter = 1000;
|
||||
this.phase = 2;
|
||||
}
|
||||
this.syncCounter = 1000;
|
||||
index += 4;
|
||||
break;
|
||||
case 2:
|
||||
// decode actual audio data
|
||||
output[oi++] = this.decodeNibble(data[index] & 0x0F);
|
||||
output[oi++] = this.decodeNibble(data[index] >> 4);
|
||||
// if the next sync keyword is due, reset and return to phase 0
|
||||
if (this.syncCounter-- === 0) {
|
||||
this.synchronized = 0;
|
||||
this.phase = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (index < data.length) {
|
||||
if (this.syncCounter-- < 0) {
|
||||
this.synchronized = 0;
|
||||
break;
|
||||
}
|
||||
output[oi++] = this.decodeNibble(data[index] & 0x0F);
|
||||
output[oi++] = this.decodeNibble(data[index] >> 4);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
this.skip = index - data.length;
|
||||
return output.slice(0, oi);
|
||||
};
|
||||
|
||||
|
@ -158,8 +158,8 @@ DemodulatorPanel.prototype.updatePanels = function() {
|
||||
var modulation = this.getDemodulator().get_secondary_demod();
|
||||
$('#openwebrx-panel-digimodes').attr('data-mode', modulation);
|
||||
toggle_panel("openwebrx-panel-digimodes", !!modulation);
|
||||
toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4', 'fst4', 'fst4w', "q65", "msk144"].indexOf(modulation) >= 0);
|
||||
toggle_panel("openwebrx-panel-js8-message", modulation === "js8");
|
||||
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-packet-message", modulation === "packet");
|
||||
toggle_panel("openwebrx-panel-pocsag-message", modulation === "pocsag");
|
||||
|
||||
|
@ -50,7 +50,7 @@ MessagePanel.prototype.initClearButton = function() {
|
||||
function WsjtMessagePanel(el) {
|
||||
MessagePanel.call(this, el);
|
||||
this.initClearTimer();
|
||||
this.qsoModes = ['FT8', 'JT65', 'JT9', 'FT4', 'FST4', 'Q65', 'MSK144'];
|
||||
this.qsoModes = ['FT8', 'JT65', 'JT9', 'FT4', 'FST4', 'Q65'];
|
||||
this.beaconModes = ['WSPR', 'FST4W'];
|
||||
this.modes = [].concat(this.qsoModes, this.beaconModes);
|
||||
}
|
||||
|
104
owrx/active/list/__init__.py
Normal file
104
owrx/active/list/__init__.py
Normal file
@ -0,0 +1,104 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActiveListChange(ABC):
|
||||
pass
|
||||
|
||||
|
||||
class ActiveListIndexUpdated(ActiveListChange):
|
||||
def __init__(self, index: int, oldValue, newValue):
|
||||
self.index = index
|
||||
self.oldValue = oldValue
|
||||
self.newValue = newValue
|
||||
|
||||
|
||||
class ActiveListIndexAppended(ActiveListChange):
|
||||
def __init__(self, index: int, newValue):
|
||||
self.index = index
|
||||
self.newValue = newValue
|
||||
|
||||
|
||||
class ActiveListIndexDeleted(ActiveListChange):
|
||||
def __init__(self, index: int, oldValue):
|
||||
self.index = index
|
||||
self.oldValue = oldValue
|
||||
|
||||
|
||||
class ActiveListListener(ABC):
|
||||
@abstractmethod
|
||||
def onListChange(self, changes: list[ActiveListChange]):
|
||||
pass
|
||||
|
||||
|
||||
class ActiveListTransformationListener(ActiveListListener):
|
||||
def __init__(self, transformation: callable, target: "ActiveList"):
|
||||
self.transformation = transformation
|
||||
self.target = target
|
||||
|
||||
def onListChange(self, changes: list[ActiveListChange]):
|
||||
for change in changes:
|
||||
if isinstance(change, ActiveListIndexUpdated):
|
||||
self.target[change.index] = self.transformation(change.newValue)
|
||||
elif isinstance(change, ActiveListIndexAppended):
|
||||
self.target.append(self.transformation(change.newValue))
|
||||
elif isinstance(change, ActiveListIndexDeleted):
|
||||
del self.target[change.index]
|
||||
|
||||
|
||||
class ActiveList:
|
||||
def __init__(self, elements: list = None):
|
||||
self.delegate = elements.copy() if elements is not None else []
|
||||
self.listeners = []
|
||||
|
||||
def addListener(self, listener: ActiveListListener):
|
||||
if listener in self.listeners:
|
||||
return
|
||||
self.listeners.append(listener)
|
||||
|
||||
def removeListener(self, listener: ActiveListListener):
|
||||
if listener not in self.listeners:
|
||||
return
|
||||
self.listeners.remove(listener)
|
||||
|
||||
def append(self, value):
|
||||
self.delegate.append(value)
|
||||
self.__fireChanges([ActiveListIndexAppended(len(self) - 1, value)])
|
||||
|
||||
def __fireChanges(self, changes: list[ActiveListChange]):
|
||||
for listener in self.listeners:
|
||||
try:
|
||||
listener.onListChange(changes)
|
||||
except Exception:
|
||||
logger.exception("Exception during onListChange notification")
|
||||
|
||||
def remove(self, value):
|
||||
self.__delitem__(self.delegate.index(value))
|
||||
|
||||
def map(self, transform: callable):
|
||||
res = ActiveList([transform(v) for v in self])
|
||||
self.addListener(ActiveListTransformationListener(transform, res))
|
||||
return res
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if self.delegate[key] == value:
|
||||
return
|
||||
oldValue = self.delegate[key]
|
||||
self.delegate[key] = value
|
||||
self.__fireChanges([ActiveListIndexUpdated(key, oldValue, value)])
|
||||
|
||||
def __delitem__(self, key):
|
||||
oldValue = self.delegate[key]
|
||||
del self.delegate[key]
|
||||
self.__fireChanges([ActiveListIndexDeleted(key, oldValue)])
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.delegate[key]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.delegate)
|
||||
|
||||
def __iter__(self):
|
||||
return self.delegate.__iter__()
|
@ -581,9 +581,6 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient)
|
||||
from csdr.chain.digimodes import AudioChopperDemodulator
|
||||
from owrx.wsjt import WsjtParser
|
||||
return AudioChopperDemodulator(mod, WsjtParser())
|
||||
elif mod == "msk144":
|
||||
from csdr.chain.digimodes import Msk144Demodulator
|
||||
return Msk144Demodulator()
|
||||
elif mod == "js8":
|
||||
from csdr.chain.digimodes import AudioChopperDemodulator
|
||||
from owrx.js8 import Js8Parser
|
||||
|
@ -80,7 +80,6 @@ class FeatureDetector(object):
|
||||
"wsjt-x": ["wsjtx"],
|
||||
"wsjt-x-2-3": ["wsjtx_2_3"],
|
||||
"wsjt-x-2-4": ["wsjtx_2_4"],
|
||||
"msk144": ["msk144decoder"],
|
||||
"packet": ["direwolf"],
|
||||
"pocsag": ["digiham"],
|
||||
"js8call": ["js8", "js8py"],
|
||||
@ -429,7 +428,7 @@ class FeatureDetector(object):
|
||||
def has_wsjtx(self):
|
||||
"""
|
||||
To decode FT8 and other digimodes, you need to install the WSJT-X software suite. Please check the
|
||||
[WSJT-X homepage](https://wsjt.sourceforge.io/) for ready-made packages or instructions
|
||||
[WSJT-X homepage](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) for ready-made packages or instructions
|
||||
on how to build from source.
|
||||
"""
|
||||
return reduce(and_, map(self.command_is_runnable, ["jt9", "wsprd"]), True)
|
||||
@ -460,13 +459,6 @@ class FeatureDetector(object):
|
||||
"""
|
||||
return self.has_wsjtx() and self._has_wsjtx_version(LooseVersion("2.4"))
|
||||
|
||||
def has_msk144decoder(self):
|
||||
"""
|
||||
To decode the MSK144 digimode please install the "msk144decoder". See the
|
||||
[project page](https://github.com/alexander-sholohov/msk144decoder) for more details.
|
||||
"""
|
||||
return self.command_is_runnable("msk144decoder")
|
||||
|
||||
def has_js8(self):
|
||||
"""
|
||||
To decode JS8, you will need to install [JS8Call](http://js8call.com/)
|
||||
|
@ -120,7 +120,6 @@ class Modes(object):
|
||||
WsjtMode("fst4", "FST4", requirements=["wsjt-x-2-3"]),
|
||||
WsjtMode("fst4w", "FST4W", bandpass=Bandpass(1350, 1650), requirements=["wsjt-x-2-3"]),
|
||||
WsjtMode("q65", "Q65", requirements=["wsjt-x-2-4"]),
|
||||
DigitalMode("msk144", "MSK144", requirements=["msk144"], underlying=["usb"], service=True),
|
||||
Js8Mode("js8", "JS8Call"),
|
||||
DigitalMode(
|
||||
"packet",
|
||||
|
@ -27,9 +27,9 @@ class PskReporter(Reporter):
|
||||
Supports all valid MODE and SUBMODE values from the ADIF standard.
|
||||
|
||||
Current version at the time of the last change:
|
||||
https://www.adif.org/314/ADIF_314.htm#Mode_Enumeration
|
||||
https://www.adif.org/312/ADIF_312.htm#Mode_Enumeration
|
||||
"""
|
||||
return ["FT8", "FT4", "JT9", "JT65", "FST4", "JS8", "Q65", "WSPR", "FST4W", "MSK144"]
|
||||
return ["FT8", "FT4", "JT9", "JT65", "FST4", "JS8", "Q65", "WSPR", "FST4W"]
|
||||
|
||||
def stop(self):
|
||||
self.cancelTimer()
|
||||
@ -105,34 +105,27 @@ class Uploader(object):
|
||||
# filter out any erroneous encodes
|
||||
encoded = [e for e in encoded if e is not None]
|
||||
|
||||
def chunks(block, max_size):
|
||||
size = 0
|
||||
current = []
|
||||
for r in block:
|
||||
if size + len(r) > max_size:
|
||||
yield current
|
||||
current = []
|
||||
size = 0
|
||||
size += len(r)
|
||||
current.append(r)
|
||||
yield current
|
||||
def chunks(l, n):
|
||||
"""Yield successive n-sized chunks from l."""
|
||||
for i in range(0, len(l), n):
|
||||
yield l[i : i + n]
|
||||
|
||||
rHeader = self.getReceiverInformationHeader()
|
||||
rInfo = self.getReceiverInformation()
|
||||
sHeader = self.getSenderInformationHeader()
|
||||
|
||||
packets = []
|
||||
# 1200 bytes of sender data should keep the packet size below MTU for most cases
|
||||
for chunk in chunks(encoded, 1200):
|
||||
# 50 seems to be a safe bet
|
||||
for chunk in chunks(encoded, 50):
|
||||
sInfo = self.getSenderInformation(chunk)
|
||||
length = 16 + len(rHeader) + len(sHeader) + len(rInfo) + len(sInfo)
|
||||
header = self.getHeader(length)
|
||||
packets.append(header + rHeader + sHeader + rInfo + sInfo)
|
||||
self.sequence = (self.sequence + len(chunk)) % (1 << 32)
|
||||
|
||||
return packets
|
||||
|
||||
def getHeader(self, length):
|
||||
self.sequence += 1
|
||||
return bytes(
|
||||
# protocol version
|
||||
[0x00, 0x0A]
|
||||
@ -149,7 +142,7 @@ class Uploader(object):
|
||||
try:
|
||||
return bytes(
|
||||
self.encodeString(spot["source"]["callsign"])
|
||||
+ list(int(spot["freq"]).to_bytes(5, "big"))
|
||||
+ list(int(spot["freq"]).to_bytes(4, "big"))
|
||||
+ list(int(spot["db"]).to_bytes(1, "big", signed=True))
|
||||
+ self.encodeString(spot["mode"])
|
||||
+ self.encodeString(spot["locator"])
|
||||
@ -215,7 +208,7 @@ class Uploader(object):
|
||||
# senderCallsign
|
||||
+ [0x80, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F]
|
||||
# frequency
|
||||
+ [0x80, 0x05, 0x00, 0x05, 0x00, 0x00, 0x76, 0x8F]
|
||||
+ [0x80, 0x05, 0x00, 0x04, 0x00, 0x00, 0x76, 0x8F]
|
||||
# sNR
|
||||
+ [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x76, 0x8F]
|
||||
# mode
|
||||
|
@ -122,15 +122,6 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
self.startupTimer.start()
|
||||
|
||||
def updateServices(self):
|
||||
def addService(dial, source):
|
||||
mode = dial["mode"]
|
||||
frequency = dial["frequency"]
|
||||
try:
|
||||
service = self.setupService(mode, frequency, source)
|
||||
self.services.append(service)
|
||||
except Exception:
|
||||
logger.exception("Error setting up service %s on frequency %d", mode, frequency)
|
||||
|
||||
with self.lock:
|
||||
logger.debug("re-scheduling services due to sdr changes")
|
||||
self.stopServices()
|
||||
@ -155,7 +146,7 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
groups = self.optimizeResampling(dials, sr)
|
||||
if groups is None:
|
||||
for dial in dials:
|
||||
addService(dial, self.source)
|
||||
self.services.append(self.setupService(dial["mode"], dial["frequency"], self.source))
|
||||
else:
|
||||
for group in groups:
|
||||
if len(group) > 1:
|
||||
@ -166,14 +157,14 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
resampler = Resampler(resampler_props, self.source)
|
||||
|
||||
for dial in group:
|
||||
addService(dial, resampler)
|
||||
self.services.append(self.setupService(dial["mode"], dial["frequency"], resampler))
|
||||
|
||||
# resampler goes in after the services since it must not be shutdown as long as the services are
|
||||
# still running
|
||||
self.services.append(resampler)
|
||||
else:
|
||||
dial = group[0]
|
||||
addService(dial, self.source)
|
||||
self.services.append(self.setupService(dial["mode"], dial["frequency"], self.source))
|
||||
|
||||
def get_min_max(self, group):
|
||||
frequencies = sorted(group, key=lambda f: f["frequency"])
|
||||
@ -288,13 +279,11 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
def _getSecondaryDemodulator(self, mod) -> Optional[ServiceDemodulator]:
|
||||
if isinstance(mod, ServiceDemodulatorChain):
|
||||
return mod
|
||||
# TODO add remaining modes
|
||||
if mod in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]:
|
||||
from csdr.chain.digimodes import AudioChopperDemodulator
|
||||
from owrx.wsjt import WsjtParser
|
||||
return AudioChopperDemodulator(mod, WsjtParser())
|
||||
elif mod == "msk144":
|
||||
from csdr.chain.digimodes import Msk144Demodulator
|
||||
return Msk144Demodulator()
|
||||
elif mod == "js8":
|
||||
from csdr.chain.digimodes import AudioChopperDemodulator
|
||||
from owrx.js8 import Js8Parser
|
||||
@ -302,8 +291,7 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
elif mod == "packet":
|
||||
from csdr.chain.digimodes import PacketDemodulator
|
||||
return PacketDemodulator(service=True)
|
||||
|
||||
raise ValueError("unsupported service modulation: {}".format(mod))
|
||||
return None
|
||||
|
||||
|
||||
class Services(object):
|
||||
|
13
owrx/wsjt.py
13
owrx/wsjt.py
@ -245,17 +245,6 @@ class Q65Profile(WsjtProfile):
|
||||
return ["jt9", "--q65", "-p", str(self.interval), "-b", self.mode.name, "-d", str(self.decoding_depth()), file]
|
||||
|
||||
|
||||
class Msk144Profile(WsjtProfile):
|
||||
def getMode(self):
|
||||
return "MSK144"
|
||||
|
||||
def getInterval(self):
|
||||
return 15
|
||||
|
||||
def decoder_commandline(self, file):
|
||||
return None
|
||||
|
||||
|
||||
class WsjtParser(AudioChopperParser):
|
||||
def parse(self, profile: WsjtProfile, freq: int, raw_msg: bytes):
|
||||
try:
|
||||
@ -377,8 +366,6 @@ class Jt9Decoder(Decoder):
|
||||
# '0003 -4 0.4 1762 # CQ R2ABM KO85'
|
||||
# fst4 sample
|
||||
# '**** -23 0.6 3023 ` <...> <...> R 591631 BI53PV'
|
||||
# MSK144 sample
|
||||
# '221602 8 0.4 1488 & K1JT WA4CQG EM72'
|
||||
msg, timestamp = self.parse_timestamp(msg)
|
||||
wsjt_msg = msg[17:53].strip()
|
||||
|
||||
|
123
test/owrx/active/list/test_active_list.py
Normal file
123
test/owrx/active/list/test_active_list.py
Normal file
@ -0,0 +1,123 @@
|
||||
from owrx.active.list import ActiveList, ActiveListIndexUpdated, ActiveListIndexAppended, ActiveListIndexDeleted
|
||||
from unittest import TestCase
|
||||
from unittest.mock import Mock
|
||||
|
||||
|
||||
class ActiveListTest(TestCase):
|
||||
def testListIndexReadAccess(self):
|
||||
list = ActiveList(["testvalue"])
|
||||
self.assertEqual(list[0], "testvalue")
|
||||
|
||||
def testListIndexWriteAccess(self):
|
||||
list = ActiveList(["initialvalue"])
|
||||
list[0] = "testvalue"
|
||||
self.assertEqual(list[0], "testvalue")
|
||||
|
||||
def testListLength(self):
|
||||
list = ActiveList(["somevalue"])
|
||||
self.assertEqual(len(list), 1)
|
||||
|
||||
def testListIndexChangeNotification(self):
|
||||
list = ActiveList(["initialvalue"])
|
||||
listenerMock = Mock()
|
||||
list.addListener(listenerMock)
|
||||
list[0] = "testvalue"
|
||||
listenerMock.onListChange.assert_called_once()
|
||||
changes, = listenerMock.onListChange.call_args.args
|
||||
self.assertEqual(len(changes), 1)
|
||||
self.assertIsInstance(changes[0], ActiveListIndexUpdated)
|
||||
self.assertEqual(changes[0].index, 0)
|
||||
self.assertEqual(changes[0].oldValue, "initialvalue")
|
||||
self.assertEqual(changes[0].newValue, "testvalue")
|
||||
|
||||
def testListIndexChangeNotficationNotDisturbedByException(self):
|
||||
list = ActiveList(["initialvalue"])
|
||||
throwingMock = Mock()
|
||||
throwingMock.onListChange.side_effect = RuntimeError("this is a drill")
|
||||
list.addListener(throwingMock)
|
||||
listenerMock = Mock()
|
||||
list.addListener(listenerMock)
|
||||
list[0] = "testvalue"
|
||||
listenerMock.onListChange.assert_called_once()
|
||||
|
||||
def testListAppend(self):
|
||||
list = ActiveList()
|
||||
list.append("testvalue")
|
||||
self.assertEqual(len(list), 1)
|
||||
self.assertEqual(list[0], "testvalue")
|
||||
|
||||
def testListAppendNotification(self):
|
||||
list = ActiveList()
|
||||
listenerMock = Mock()
|
||||
list.addListener(listenerMock)
|
||||
list.append("testvalue")
|
||||
listenerMock.onListChange.assert_called_once()
|
||||
changes, = listenerMock.onListChange.call_args.args
|
||||
self.assertEqual(len(changes), 1)
|
||||
self.assertIsInstance(changes[0], ActiveListIndexAppended)
|
||||
self.assertEqual(changes[0].index, 0)
|
||||
self.assertEqual(changes[0].newValue, "testvalue")
|
||||
|
||||
def testListDelete(self):
|
||||
list = ActiveList(["value1", "value2"])
|
||||
del list[0]
|
||||
self.assertEqual(len(list), 1)
|
||||
self.assertEqual(list[0], "value2")
|
||||
|
||||
def testListDeleteNotification(self):
|
||||
list = ActiveList(["value1", "value2"])
|
||||
listenerMock = Mock()
|
||||
list.addListener(listenerMock)
|
||||
del list[0]
|
||||
listenerMock.onListChange.assert_called_once()
|
||||
changes, = listenerMock.onListChange.call_args.args
|
||||
self.assertEqual(len(changes), 1)
|
||||
self.assertIsInstance(changes[0], ActiveListIndexDeleted)
|
||||
self.assertEqual(changes[0].index, 0)
|
||||
self.assertEqual(changes[0].oldValue, 'value1')
|
||||
|
||||
def testListDeleteByValue(self):
|
||||
list = ActiveList(["value1", "value2"])
|
||||
list.remove("value1")
|
||||
self.assertEqual(len(list), 1)
|
||||
self.assertEqual(list[0], "value2")
|
||||
|
||||
def testListComprehension(self):
|
||||
list = ActiveList(["initialvalue"])
|
||||
x = [m for m in list]
|
||||
self.assertEqual(len(x), 1)
|
||||
self.assertEqual(x[0], "initialvalue")
|
||||
|
||||
def testListenerRemoval(self):
|
||||
list = ActiveList(["initialvalue"])
|
||||
listenerMock = Mock()
|
||||
list.addListener(listenerMock)
|
||||
list[0] = "testvalue"
|
||||
listenerMock.onListChange.assert_called_once()
|
||||
listenerMock.reset_mock()
|
||||
list.removeListener(listenerMock)
|
||||
list[0] = "someothervalue"
|
||||
listenerMock.onListChange.assert_not_called()
|
||||
|
||||
def testListMapTransformation(self):
|
||||
list = ActiveList(["somevalue"])
|
||||
transformedList = list.map(lambda x: "prefix-{}".format(x))
|
||||
self.assertEqual(transformedList[0], "prefix-somevalue")
|
||||
|
||||
def testActiveTransformationUpdate(self):
|
||||
list = ActiveList(["initialvalue"])
|
||||
transformedList = list.map(lambda x: "prefix-{}".format(x))
|
||||
list[0] = "testvalue"
|
||||
self.assertEqual(transformedList[0], "prefix-testvalue")
|
||||
|
||||
def testActiveTransformationAppend(self):
|
||||
list = ActiveList(["initialvalue"])
|
||||
transformedList = list.map(lambda x: "prefix-{}".format(x))
|
||||
list.append("newvalue")
|
||||
self.assertEqual(transformedList[1], "prefix-newvalue")
|
||||
|
||||
def testActiveTransformationDelete(self):
|
||||
list = ActiveList(["value1", "value2"])
|
||||
transformedList = list.map(lambda x: "prefix-{}".format(x))
|
||||
del list[0]
|
||||
self.assertEqual(transformedList[0], "prefix-value2")
|
0
test/owrx/property/__init__.py
Normal file
0
test/owrx/property/__init__.py
Normal file
0
test/owrx/property/filter/__init__.py
Normal file
0
test/owrx/property/filter/__init__.py
Normal file
0
test/owrx/property/validators/__init__.py
Normal file
0
test/owrx/property/validators/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user