mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-07-19 10:05:20 -04:00
Compare commits
487 Commits
master
...
wsjtx-2.7.
Author | SHA1 | Date | |
---|---|---|---|
|
bf4aa5f4e9 | ||
|
25ae16af1a | ||
|
ac406a1559 | ||
|
656793f2d7 | ||
|
043b721ad7 | ||
|
7cfafa7846 | ||
|
999caa9e99 | ||
|
eaa47122d8 | ||
|
c75574339b | ||
|
7b27757c2a | ||
|
761bf83069 | ||
|
5172c1da52 | ||
|
6d0b47f129 | ||
|
c2cf7d3353 | ||
|
9f7a6a4988 | ||
|
f01239c000 | ||
|
3fc573f4e1 | ||
|
9ea6d8d3b9 | ||
|
197d7cb7a9 | ||
|
4eceffa9a2 | ||
|
4b37a41dc6 | ||
|
33637034af | ||
|
b571f63d98 | ||
|
37d71f4af7 | ||
|
b1c7b732e6 | ||
|
aa9e625c23 | ||
|
2ab23d18ab | ||
|
69629c3748 | ||
|
fbe0fe216b | ||
|
86dfd480af | ||
|
1c37576885 | ||
|
0b5cfb26eb | ||
|
24ea7d0e6a | ||
|
be021f0d01 | ||
|
8304c9f3cd | ||
|
a87fd4b6a1 | ||
|
3a9c1256bd | ||
|
131aca18dc | ||
|
24db8a23eb | ||
|
2c5aaca6ab | ||
|
16d85d0867 | ||
|
6a154b4e6f | ||
|
bf242d03e5 | ||
|
37f5abc35c | ||
|
77e93a81e1 | ||
|
f8079fbcbe | ||
|
e1f455d821 | ||
|
9b65b6c4e5 | ||
|
2c54019a4b | ||
|
2e5ef07a72 | ||
|
0f3b451c87 | ||
|
6723004254 | ||
|
0b32418727 | ||
|
a958874d3b | ||
|
4dfc1cc98f | ||
|
cbd79b24e6 | ||
|
5e370438c3 | ||
|
959b93bf61 | ||
|
57b524db51 | ||
|
ed19a92e2a | ||
|
8e0df8c0ea | ||
|
4f9d0da8c6 | ||
|
2458468411 | ||
|
10aead3962 | ||
|
f60db58372 | ||
|
2b2d790da2 | ||
|
5053ddf063 | ||
|
2ab36d0a13 | ||
|
885691e170 | ||
|
ab8917d66a | ||
|
acbc3095e9 | ||
|
6b98c85473 | ||
|
463f655236 | ||
|
8eb0f8a50c | ||
|
bc480ede6d | ||
|
e027c9ea3c | ||
|
5c2d01d8b4 | ||
|
c826220c01 | ||
|
d15f992864 | ||
|
75c66390ea | ||
|
e7c0cde160 | ||
|
3446b45b2b | ||
|
7895172d3f | ||
|
3c4450cdc2 | ||
|
11749ebef9 | ||
|
f0a329c4d2 | ||
|
dcb8c6ce6b | ||
|
4400f7464c | ||
|
1621ec61e5 | ||
|
eb500cbe87 | ||
|
a18f1a5f66 | ||
|
eca508faf9 | ||
|
ecde7e8cc9 | ||
|
0aee7e747b | ||
|
d845bd0466 | ||
|
073e644f12 | ||
|
9a8e43c1d5 | ||
|
398a2dc671 | ||
|
5f06e6d535 | ||
|
712cf59fbb | ||
|
19ccf338af | ||
|
d8f42ec965 | ||
|
49eac1dbd3 | ||
|
46595d45e8 | ||
|
b4d8f47bab | ||
|
827e8e37b5 | ||
|
a52559758a | ||
|
223d9f5d63 | ||
|
521a0e1a0d | ||
|
4c0eaece7e | ||
|
f8c31aea3e | ||
|
4298a000a0 | ||
|
ec72810451 | ||
|
ea11259c27 | ||
|
869cff683f | ||
|
bd00c25ca2 | ||
|
f9906120d3 | ||
|
91661c1d95 | ||
|
fe833b26ce | ||
|
6997682425 | ||
|
b0979968f3 | ||
|
991cdd1912 | ||
|
ab5f75192b | ||
|
3f4f88e712 | ||
|
7040d69a46 | ||
|
6a52bb1f69 | ||
|
2886979717 | ||
|
ffd5dd1db2 | ||
|
30c87ea019 | ||
|
85437c4e9d | ||
|
467451e37d | ||
|
764c64a829 | ||
|
157642d7cb | ||
|
39dd848b66 | ||
|
4cbc957593 | ||
|
9c7316226a | ||
|
4916c77d10 | ||
|
cc4d56691f | ||
|
3e76477a61 | ||
|
69cdb486cf | ||
|
4a549b9a3b | ||
|
9c3a0d5e1c | ||
|
e26d2cb02c | ||
|
56f862287a | ||
|
a8eaa66f2a | ||
|
3efa42cb65 | ||
|
d1d0d8a0d0 | ||
|
fb1a75e81f | ||
|
1186b0bb8b | ||
|
8066947c53 | ||
|
d7981738fe | ||
|
0d7612218f | ||
|
2e6a4f597b | ||
|
3fdd69d021 | ||
|
a304177491 | ||
|
f40b2c255c | ||
|
08866b0d75 | ||
|
914c6f3e7b | ||
|
6ddc7cf7f9 | ||
|
c2531f675e | ||
|
8e6ca93259 | ||
|
9a7ae401e7 | ||
|
875602975b | ||
|
458641f827 | ||
|
e94d243d61 | ||
|
c9f90dcb06 | ||
|
a6f8237dac | ||
|
13b66c111f | ||
|
3935c4997e | ||
|
c79d24ca61 | ||
|
867d2fe1d9 | ||
|
b0bd2b6310 | ||
|
743e187729 | ||
|
1e7c92fe76 | ||
|
52022e507e | ||
|
9cb2eae76e | ||
|
12c1b4d976 | ||
|
ab1669b6f2 | ||
|
66d1b6640e | ||
|
d8b17cff83 | ||
|
be0923b68d | ||
|
a8e7c08c93 | ||
|
9cec90e44e | ||
|
716027de6e | ||
|
67639f2294 | ||
|
4c84aab38e | ||
|
354d3bcb1a | ||
|
1dbc8ac18f | ||
|
86891c0b00 | ||
|
194d9999a3 | ||
|
a3b5b6b2ab | ||
|
ec712007d9 | ||
|
4063fe2285 | ||
|
2768e87618 | ||
|
66880b29c0 | ||
|
024b799ebb | ||
|
98ee149be6 | ||
|
149c177d5f | ||
|
25097b6baa | ||
|
322efdd681 | ||
|
59aa8c1632 | ||
|
532994d48d | ||
|
897abe611a | ||
|
bccfda16e7 | ||
|
4c5efb0961 | ||
|
c24f0402ef | ||
|
e93c6b5955 | ||
|
44432d7b1c | ||
|
6518f52a80 | ||
|
d57d22556a | ||
|
e3fe59a7b4 | ||
|
fde7df8c1c | ||
|
46976e7fcd | ||
|
7f3fa166a6 | ||
|
036b3eb24e | ||
|
e439a005f1 | ||
|
4c07429ddb | ||
|
365b3b09c4 | ||
|
6fad818965 | ||
|
0b1b50db2e | ||
|
20056f0c4a | ||
|
f8d11f6894 | ||
|
b11514c54b | ||
|
d68ef69e9e | ||
|
e83290b1c9 | ||
|
647b6e231f | ||
|
bb95fbf405 | ||
|
e1118390be | ||
|
1b68336edb | ||
|
ec880ffe4c | ||
|
3b36cb99e2 | ||
|
21bacaced2 | ||
|
405c5c164c | ||
|
fb44b4fbd9 | ||
|
c8e03b7505 | ||
|
67c4c34ea2 | ||
|
6eb07a94a7 | ||
|
e7f2d56cd2 | ||
|
4506b76671 | ||
|
3372fac76b | ||
|
574f6988e3 | ||
|
9779c16446 | ||
|
6f02013694 | ||
|
82afc82dd1 | ||
|
77b779b7b7 | ||
|
e56e617707 | ||
|
e65d797159 | ||
|
41b5b1f6b7 | ||
|
11a1fbf027 | ||
|
7e133b43e9 | ||
|
9f97d94a05 | ||
|
517980ac3c | ||
|
da5e072d73 | ||
|
9b2efd1649 | ||
|
b4e7e6fcb0 | ||
|
3a09a4c452 | ||
|
9d857e4768 | ||
|
b991bdfd13 | ||
|
4535997837 | ||
|
cb7efff3fc | ||
|
2bad1fbf5d | ||
|
cdd4b9c4c3 | ||
|
f9bdef41e2 | ||
|
e4f89e3cf6 | ||
|
253505ff5d | ||
|
e269130cff | ||
|
24254175be | ||
|
92fe13154a | ||
|
560a22393d | ||
|
f28d6f277b | ||
|
e83258b812 | ||
|
d180d65ced | ||
|
491d450968 | ||
|
cc82b1e4b7 | ||
|
d4552213ce | ||
|
c8d109b0a0 | ||
|
b9c364fbca | ||
|
d9e042d13b | ||
|
4509b12937 | ||
|
5dcc224252 | ||
|
ef09479168 | ||
|
0788cc50cb | ||
|
f591043030 | ||
|
255aa671af | ||
|
6bac88d491 | ||
|
895067929d | ||
|
8b6744ec7f | ||
|
e1446e3ac5 | ||
|
fa5a5b8b64 | ||
|
96955a5351 | ||
|
69dfc83417 | ||
|
65cb809241 | ||
|
13cd962a64 | ||
|
eefacf34f1 | ||
|
38eb22469b | ||
|
98e0ed133b | ||
|
43845a7f21 | ||
|
5d65264e9a | ||
|
651006748d | ||
|
026569e653 | ||
|
2817a66d55 | ||
|
47fdcb9c28 | ||
|
c8f72e5eec | ||
|
db51d7f61b | ||
|
8978b81308 | ||
|
0b709251ed | ||
|
4c188eb604 | ||
|
d388ee85dd | ||
|
a003ac530b | ||
|
3812f2f9bc | ||
|
e1be3ad4e8 | ||
|
c0f71136b4 | ||
|
622ce228f2 | ||
|
830cd87489 | ||
|
a916045d40 | ||
|
673084f225 | ||
|
aab90a94e4 | ||
|
343c339de0 | ||
|
3097b20bc7 | ||
|
a1955ed1fe | ||
|
b918915614 | ||
|
076e715221 | ||
|
7f58e205a9 | ||
|
1312d238d9 | ||
|
269cb0fbf7 | ||
|
5235600d2b | ||
|
4e66d1eb9f | ||
|
da477107cc | ||
|
cf4167ea2d | ||
|
c652763932 | ||
|
76db12cff0 | ||
|
96a3eebb8a | ||
|
e7bfdbc656 | ||
|
b12d5488ff | ||
|
2ec0a54d2a | ||
|
d040026672 | ||
|
0c38d3b83f | ||
|
1cadab6e04 | ||
|
afcf0abb40 | ||
|
276657866d | ||
|
a58fa2d67d | ||
|
0148cf596f | ||
|
cd5cf5a110 | ||
|
b220643237 | ||
|
835e4936c1 | ||
|
b299700d97 | ||
|
ca18e58c77 | ||
|
ce08913e3a | ||
|
a5f68966ab | ||
|
56ce1b7441 | ||
|
05dd89c552 | ||
|
ed248eb702 | ||
|
2f600ae198 | ||
|
5948c0d024 | ||
|
027b84f047 | ||
|
b495531f78 | ||
|
16346c0c1b | ||
|
f53d864269 | ||
|
51757d474b | ||
|
69c4e4acb6 | ||
|
06d648f1d7 | ||
|
6a59223b70 | ||
|
b59ed5dd93 | ||
|
993705d581 | ||
|
376f0d1e53 | ||
|
f263a70dd3 | ||
|
cbb42e9cdd | ||
|
271c2eec6c | ||
|
391536f35a | ||
|
6d4372cafe | ||
|
4491da67f7 | ||
|
b25e7fce8c | ||
|
665e18f656 | ||
|
25b6df82fe | ||
|
7c7a985bfe | ||
|
12bda0f84e | ||
|
161f456101 | ||
|
577f6f3097 | ||
|
6d72b295c8 | ||
|
1b9071fd8c | ||
|
12bcddf366 | ||
|
532c808316 | ||
|
863ac4fd3d | ||
|
baec5dcfd2 | ||
|
fada229d83 | ||
|
8948daabb0 | ||
|
523023fe65 | ||
|
0c03b9fc00 | ||
|
b1e2a54f91 | ||
|
f1e4f998ce | ||
|
0393d7bd7c | ||
|
f99e906a59 | ||
|
f896df064d | ||
|
254a15b4f6 | ||
|
d44d00453f | ||
|
2effe7e4c7 | ||
|
d12e16c7d1 | ||
|
61711e905d | ||
|
cc6e7b1c16 | ||
|
2a95463c80 | ||
|
2346145fba | ||
|
7ce6e29a7e | ||
|
d234986165 | ||
|
fb19d27602 | ||
|
ec0c31d849 | ||
|
d438f91845 | ||
|
5c53a43171 | ||
|
cdcdedfe40 | ||
|
40331f3c1f | ||
|
faf0554cbf | ||
|
8a2e3e50d9 | ||
|
93fd8246fb | ||
|
17d9c6bf81 | ||
|
50f9c73ad3 | ||
|
33aa347e24 | ||
|
09f456d6a3 | ||
|
d7d8a70322 | ||
|
f21f37ad05 | ||
|
ce7d5b8d02 | ||
|
939eaa11ef | ||
|
a516184a3c | ||
|
8dd19ee80c | ||
|
7bf4aaef2e | ||
|
5349ba7dc5 | ||
|
d4414e3ce3 | ||
|
cc4bcfa462 | ||
|
ddbe0eb078 | ||
|
060fdf6763 | ||
|
c24a0d3c72 | ||
|
6310419a4d | ||
|
129ee5439a | ||
|
05d720201a | ||
|
b6ad4d701d | ||
|
dc6f78d50b | ||
|
05cae7b911 | ||
|
62c2e5c645 | ||
|
5e6a9d59ed | ||
|
ec535541db | ||
|
4a1e6a19fc | ||
|
56d0aac243 | ||
|
c051168a6b | ||
|
464838aa78 | ||
|
ca5bc0e86b | ||
|
8c61d303bf | ||
|
84e5fbe6d5 | ||
|
c1033e1cff | ||
|
290b34c99c | ||
|
3e27ce83e6 | ||
|
9642d41c6d | ||
|
7804716991 | ||
|
5d07f86334 | ||
|
c8f8356c28 | ||
|
ae462a9cb8 | ||
|
5cc29df68f | ||
|
347e32548c | ||
|
3bfbe4deb4 | ||
|
2535a24481 | ||
|
6b8b0e1b10 | ||
|
d805820446 | ||
|
959026aad5 | ||
|
db71f7d480 | ||
|
a382fbfe7b | ||
|
ca44347507 | ||
|
0cf544e3aa | ||
|
c228340519 | ||
|
d6d4ad3c23 | ||
|
1296134820 | ||
|
d9b6691dbf | ||
|
0c3174f9e3 | ||
|
e43e81f73f | ||
|
7201e5baab | ||
|
5ac2f4f4eb | ||
|
b0bc73e3f3 | ||
|
0531f339e8 | ||
|
3434faf84a | ||
|
42439c2b6d | ||
|
9d882e01e5 | ||
|
cc005bf69b | ||
|
181b22be67 | ||
|
245d63d980 | ||
|
a7ea051cb0 | ||
|
efedc50fe1 | ||
|
88838fca62 | ||
|
0d664e4ed1 | ||
|
d100c4e9e0 | ||
|
aedc9ec3c1 | ||
|
27824dc45d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,7 +7,6 @@ GTAGS
|
||||
*~
|
||||
junk*
|
||||
jnq*
|
||||
*.exe
|
||||
*.o
|
||||
*.mod
|
||||
*.pro.user
|
||||
|
@ -148,7 +148,6 @@ void SoundOutput::stop ()
|
||||
m_stream->reset ();
|
||||
m_stream->stop ();
|
||||
}
|
||||
m_stream.reset ();
|
||||
}
|
||||
|
||||
qreal SoundOutput::attenuation () const
|
||||
|
@ -50,6 +50,7 @@ project (wsjtx
|
||||
)
|
||||
set (PROJECT_DESCRIPTION "WSJT-X: Digital Modes for Weak Signal Communications in Amateur Radio")
|
||||
set (CMAKE_PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION})
|
||||
set (CMAKE_AUTOUIC ON)
|
||||
|
||||
#
|
||||
# Local CMake modules and support files
|
||||
@ -71,7 +72,7 @@ message (STATUS "******************************************************")
|
||||
|
||||
include (set_build_type)
|
||||
# RC 0 or omitted is a development build, GA is a General Availability release build
|
||||
set_build_type (RC 4)
|
||||
set_build_type (RC 7)
|
||||
set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}")
|
||||
|
||||
#
|
||||
@ -80,7 +81,7 @@ set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_
|
||||
set (PROJECT_BUNDLE_NAME "WSJT-X")
|
||||
set (PROJECT_VENDOR "Joe Taylor, K1JT")
|
||||
set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>")
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2023 by Joe Taylor, K1JT")
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2024 by Joe Taylor, K1JT")
|
||||
set (PROJECT_HOMEPAGE https://wsjt.sourceforge.io/wsjtx.html)
|
||||
set (PROJECT_MANUAL wsjtx-main)
|
||||
set (PROJECT_MANUAL_DIRECTORY_URL https://wsjt.sourceforge.io/wsjtx-doc/)
|
||||
@ -126,6 +127,7 @@ option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||
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)
|
||||
option (WSJT_FOX_OTP "Enable Fox OTP Verification Messages." ON)
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_QDEBUG_IN_RELEASE "Leave Qt debugging statements in Release configuration." OFF
|
||||
"NOT is_debug_build" OFF)
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_ENABLE_EXPERIMENTAL_FEATURES "Enable features not fully ready for public releases." ON
|
||||
@ -161,6 +163,12 @@ endif ()
|
||||
set (WSJT_PLUGIN_DESTINATION ${PLUGIN_DESTINATION} CACHE PATH "Path for plugins")
|
||||
set (WSJT_QT_CONF_DESTINATION ${QT_CONF_DESTINATION} CACHE PATH "Path for the qt.conf file")
|
||||
|
||||
if (WSJT_FOX_OTP)
|
||||
set (wsjt_fox_CXXSRCS
|
||||
|
||||
)
|
||||
message (STATUS "Including Fox verification code feature")
|
||||
endif ()
|
||||
|
||||
#
|
||||
# Project sources
|
||||
@ -223,6 +231,7 @@ set (wsjt_qt_CXXSRCS
|
||||
widgets/DoubleClickableRadioButton.cpp
|
||||
Network/LotWUsers.cpp
|
||||
Network/FileDownload.cpp
|
||||
Network/FoxVerifier.cpp
|
||||
models/DecodeHighlightingModel.cpp
|
||||
widgets/DecodeHighlightingListView.cpp
|
||||
models/FoxLog.cpp
|
||||
@ -242,6 +251,7 @@ set (wsjt_qt_CXXSRCS
|
||||
widgets/LazyFillComboBox.cpp
|
||||
widgets/CheckableItemComboBox.cpp
|
||||
widgets/BandComboBox.cpp
|
||||
otpgenerator.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
@ -292,6 +302,7 @@ set (wsjt_CXXSRCS
|
||||
lib/crc10.cpp
|
||||
lib/crc13.cpp
|
||||
lib/crc14.cpp
|
||||
${wsjt_fox_CXXSRCS}
|
||||
)
|
||||
# deal with a GCC v6 UB error message
|
||||
set_source_files_properties (
|
||||
@ -342,6 +353,10 @@ set (wsjt_FSRCS
|
||||
lib/wavhdr.f90
|
||||
lib/qra/q65/q65_encoding_modules.f90
|
||||
lib/ft8/ft8_a7.f90
|
||||
lib/superfox/sfox_mod.f90
|
||||
lib/superfox/julian.f90
|
||||
lib/superfox/popen_module.f90
|
||||
lib/superfox/qpc/qpc_mod.f90
|
||||
|
||||
# remaining non-module sources
|
||||
lib/addit.f90
|
||||
@ -427,8 +442,7 @@ set (wsjt_FSRCS
|
||||
lib/fspread_lorentz.f90
|
||||
lib/ft8/foxfilt.f90
|
||||
lib/ft8/foxgen.f90
|
||||
lib/superfox/foxgen2.f90
|
||||
lib/ft8/foxgen_wrap.f90
|
||||
# lib/ft8/foxgen_wrap.f90
|
||||
lib/freqcal.f90
|
||||
lib/ft8/ft8apset.f90
|
||||
lib/ft8/ft8b.f90
|
||||
@ -587,6 +601,27 @@ set (wsjt_FSRCS
|
||||
lib/fst4/get_crc24.f90
|
||||
lib/fst4/fst4_baseline.f90
|
||||
lib/77bit/hash22calc.f90
|
||||
|
||||
lib/superfox/foxgen2.f90
|
||||
lib/superfox/qpc_decode2.f90
|
||||
lib/superfox/qpc_likelihoods2.f90
|
||||
lib/superfox/qpc_snr.f90
|
||||
lib/superfox/qpc_sync.f90
|
||||
lib/superfox/sfox_ana.f90
|
||||
lib/superfox/sfox_assemble.f90
|
||||
lib/superfox/sfox_demod.f90
|
||||
lib/superfox/sfox_pack.f90
|
||||
lib/superfox/sfox_remove_ft8.f90
|
||||
lib/superfox/sfox_remove_tone.f90
|
||||
lib/superfox/sfox_unpack.f90
|
||||
lib/superfox/sfox_wave.f90
|
||||
lib/superfox/sfox_wave_gfsk.f90
|
||||
lib/superfox/sfrx_sub.f90
|
||||
lib/superfox/sftx_sub.f90
|
||||
lib/superfox/twkfreq2.f90
|
||||
lib/superfox/sfox_gen_gfsk.f90
|
||||
lib/superfox/ran1.f90
|
||||
lib/superfox/sfoxsim.f90
|
||||
)
|
||||
|
||||
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
|
||||
@ -629,6 +664,15 @@ set (wsjt_CSRCS
|
||||
lib/wrapkarn.c
|
||||
${ldpc_CSRCS}
|
||||
${qra_CSRCS}
|
||||
|
||||
lib/superfox/qpc/dbgprintf.c
|
||||
lib/superfox/qpc/nhash2.c
|
||||
lib/superfox/qpc/np_qpc.c
|
||||
lib/superfox/qpc/np_rnd.c
|
||||
lib/superfox/qpc/qpc_fwht.c
|
||||
lib/superfox/qpc/qpc_n127k50q128.c
|
||||
lib/superfox/qpc/qpc_subs.c
|
||||
|
||||
)
|
||||
|
||||
set (wsjt_qt_UISRCS
|
||||
@ -902,7 +946,9 @@ check_type_size (CACHE_ALL HAMLIB_OLD_CACHING)
|
||||
check_symbol_exists (rig_set_cache_timeout_ms "hamlib/rig.h" HAVE_HAMLIB_CACHING)
|
||||
|
||||
find_package (Usb REQUIRED)
|
||||
|
||||
if (WSJT_FOX_OTP)
|
||||
add_definitions (-DFOX_OTP)
|
||||
endif ()
|
||||
#
|
||||
# Qt5 setup
|
||||
#
|
||||
@ -1155,6 +1201,9 @@ target_link_libraries (test_snr wsjt_fort)
|
||||
add_executable (q65sim lib/qra/q65/q65sim.f90)
|
||||
target_link_libraries (q65sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (cwsim lib/cwsim.f90)
|
||||
target_link_libraries (cwsim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (q65code lib/qra/q65/q65code.f90)
|
||||
target_link_libraries (q65code wsjt_fort wsjt_cxx)
|
||||
|
||||
@ -1209,6 +1258,15 @@ target_link_libraries (echosim wsjt_fort wsjt_cxx)
|
||||
add_executable (ft8sim lib/ft8/ft8sim.f90)
|
||||
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (sfoxsim lib/superfox/sfoxsim.f90)
|
||||
target_link_libraries (sfoxsim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (sfrx lib/superfox/sfrx.f90)
|
||||
target_link_libraries (sfrx wsjt_fort wsjt_cxx)
|
||||
|
||||
#add_executable (sftx lib/superfox/sftx.f90)
|
||||
#target_link_libraries (sftx wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (msk144sim lib/msk144sim.f90)
|
||||
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)
|
||||
|
||||
@ -1293,9 +1351,7 @@ set (LANGUAGES
|
||||
ru # Russian
|
||||
#sv # Swedish
|
||||
zh # Chinese
|
||||
zh_HK # Chinese per Hong Kong
|
||||
zh_TW # Chinese traditional
|
||||
it # Italian
|
||||
)
|
||||
foreach (lang_ ${LANGUAGES})
|
||||
file (TO_NATIVE_PATH ${CMAKE_SOURCE_DIR}/translations/wsjtx_${lang_}.ts ts_)
|
||||
@ -1598,7 +1654,7 @@ install (TARGETS udp_daemon message_aggregator wsjtx_app_version
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
|
||||
install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
|
@ -193,6 +193,7 @@
|
||||
#include "models/FrequencyList.hpp"
|
||||
#include "models/StationList.hpp"
|
||||
#include "Network/NetworkServerLookup.hpp"
|
||||
#include "Network/FoxVerifier.hpp"
|
||||
#include "widgets/MessageBox.hpp"
|
||||
#include "validators/MaidenheadLocatorValidator.hpp"
|
||||
#include "validators/CallsignValidator.hpp"
|
||||
@ -584,9 +585,25 @@ private:
|
||||
Q_SLOT void on_LotW_CSV_fetch_push_button_clicked (bool);
|
||||
Q_SLOT void on_hamlib_download_button_clicked (bool);
|
||||
Q_SLOT void on_revert_update_button_clicked (bool);
|
||||
Q_SLOT void on_gbSpecialOpActivity_clicked (bool);
|
||||
Q_SLOT void on_rbFox_clicked (bool);
|
||||
Q_SLOT void on_rbHound_clicked (bool);
|
||||
Q_SLOT void on_rbNA_VHF_Contest_clicked (bool);
|
||||
Q_SLOT void on_rbEU_VHF_Contest_clicked (bool);
|
||||
Q_SLOT void on_rbWW_DIGI_clicked (bool);
|
||||
Q_SLOT void on_rbQ65pileup_clicked (bool);
|
||||
Q_SLOT void on_rbField_Day_clicked (bool);
|
||||
Q_SLOT void on_rbRTTY_Roundup_clicked (bool);
|
||||
Q_SLOT void on_rbARRL_Digi_clicked (bool);
|
||||
Q_SLOT void on_cbSuperFox_clicked (bool);
|
||||
Q_SLOT void on_cbContestName_clicked (bool);
|
||||
Q_SLOT void on_cbOTP_clicked (bool);
|
||||
Q_SLOT void on_cbShowOTP_clicked (bool);
|
||||
|
||||
void error_during_hamlib_download (QString const& reason);
|
||||
void after_hamlib_downloaded();
|
||||
void display_file_information();
|
||||
void check_visibility();
|
||||
|
||||
Q_SLOT void on_cbx2ToneSpacing_clicked(bool);
|
||||
Q_SLOT void on_cbx4ToneSpacing_clicked(bool);
|
||||
@ -594,6 +611,8 @@ private:
|
||||
Q_SLOT void on_cbAutoLog_clicked(bool);
|
||||
Q_SLOT void on_Field_Day_Exchange_textEdited (QString const&);
|
||||
Q_SLOT void on_RTTY_Exchange_textEdited (QString const&);
|
||||
Q_SLOT void on_OTPUrl_textEdited (QString const&);
|
||||
Q_SLOT void on_OTPSeed_textEdited (QString const&);
|
||||
Q_SLOT void on_Contest_Name_textEdited (QString const&);
|
||||
|
||||
// typenames used as arguments must match registered type names :(
|
||||
@ -693,6 +712,12 @@ private:
|
||||
QString Contest_Name_;
|
||||
QString hamlib_backed_up_;
|
||||
|
||||
QString OTPUrl_;
|
||||
QString OTPSeed_;
|
||||
bool OTPEnabled_;
|
||||
bool ShowOTP_;
|
||||
qint32 OTPinterval_;
|
||||
|
||||
qint32 id_interval_;
|
||||
qint32 ntrials_;
|
||||
qint32 aggressive_;
|
||||
@ -963,6 +988,26 @@ void Configuration::invalidate_audio_output_device (QString /* error */)
|
||||
m_->audio_output_device_ = QAudioDeviceInfo {};
|
||||
}
|
||||
|
||||
// OTP seed can be empty, in which case it is not used, or a valid 16 character base32 string.
|
||||
bool Configuration::validate_otp_seed(QString seed)
|
||||
{
|
||||
if (seed.isEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (seed.size() != 16)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (QChar c: seed)
|
||||
{
|
||||
if (!QString(BASE32_CHARSET).contains(c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Configuration::valid_n1mm_info () const
|
||||
{
|
||||
// do very rudimentary checking on the n1mm server name and port number.
|
||||
@ -1052,6 +1097,43 @@ void Configuration::setSpecial_None()
|
||||
m_->SelectedActivity_ = static_cast<int> (SpecialOperatingActivity::HOUND); // brings backward compatibility to versions without Q65_PILEUP
|
||||
m_->write_settings();
|
||||
}
|
||||
|
||||
void Configuration::toggle_SF()
|
||||
{
|
||||
if (m_->bSuperFox_) {
|
||||
m_->ui_->cbSuperFox->setChecked(false);
|
||||
} else {
|
||||
m_->ui_->cbSuperFox->setChecked(true);
|
||||
}
|
||||
m_->bSuperFox_ = m_->ui_->cbSuperFox->isChecked ();
|
||||
m_->write_settings();
|
||||
}
|
||||
|
||||
QString Configuration::OTPSeed() const
|
||||
{
|
||||
return m_->OTPSeed_;
|
||||
}
|
||||
|
||||
QString Configuration::OTPUrl() const
|
||||
{
|
||||
return m_->OTPUrl_;
|
||||
}
|
||||
|
||||
unsigned int Configuration::OTPinterval() const
|
||||
{
|
||||
return m_->OTPinterval_;
|
||||
}
|
||||
|
||||
bool Configuration::OTPEnabled() const
|
||||
{
|
||||
return m_->OTPSeed_.size() == 16 && m_->OTPEnabled_;
|
||||
}
|
||||
|
||||
bool Configuration::ShowOTP () const
|
||||
{
|
||||
return m_->ShowOTP_;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
#if defined (Q_OS_MAC)
|
||||
@ -1222,6 +1304,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
ui_->add_macro_line_edit->setValidator (new QRegularExpressionValidator {message_alphabet, this});
|
||||
ui_->Field_Day_Exchange->setValidator (new QRegularExpressionValidator {field_day_exchange_re, this});
|
||||
ui_->RTTY_Exchange->setValidator (new QRegularExpressionValidator {RTTY_roundup_exchange_re, this});
|
||||
QRegularExpression b32(QString("(^[") + QString(BASE32_CHARSET)+QString(BASE32_CHARSET).toLower() + QString("]{16}$)|(^$)"));
|
||||
ui_->OTPSeed->setValidator(new QRegularExpressionValidator(b32, this));
|
||||
|
||||
//
|
||||
// assign ids to radio buttons
|
||||
@ -1549,6 +1633,8 @@ void Configuration::impl::initialize_models ()
|
||||
ui_->cbHighlightDXcall->setChecked(highlight_DXcall_);
|
||||
ui_->cbHighlightDXgrid->setChecked(highlight_DXgrid_);
|
||||
|
||||
check_visibility ();
|
||||
|
||||
set_rig_invariants ();
|
||||
}
|
||||
|
||||
@ -1583,6 +1669,19 @@ void Configuration::impl::read_settings ()
|
||||
ui_->Contest_Name->setText(Contest_Name_);
|
||||
hamlib_backed_up_ = settings_->value ("HamlibBackedUp",QString {}).toString ();
|
||||
|
||||
OTPinterval_ = settings_->value ("OTPinterval", 1).toUInt ();
|
||||
OTPUrl_ = settings_->value ("OTPUrl", FoxVerifier::default_url()).toString ();
|
||||
OTPSeed_ = settings_->value ("OTPSeed", QString {}).toString ();
|
||||
OTPEnabled_ = settings_->value ("OTPEnabled", false).toBool ();
|
||||
ShowOTP_ = settings_->value ("ShowOTP", false).toBool ();
|
||||
|
||||
ui_->sbOTPinterval->setValue(OTPinterval_);
|
||||
ui_->OTPUrl->setText(OTPUrl_);
|
||||
ui_->OTPSeed->setText(OTPSeed_);
|
||||
ui_->cbOTP->setChecked(OTPEnabled_);
|
||||
ui_->cbShowOTP->setChecked(ShowOTP_);
|
||||
|
||||
|
||||
if (next_font_.fromString (settings_->value ("Font", QGuiApplication::font ().toString ()).toString ())
|
||||
&& next_font_ != font_)
|
||||
{
|
||||
@ -1908,6 +2007,11 @@ void Configuration::impl::write_settings ()
|
||||
settings_->setValue ("AutoGrid", use_dynamic_grid_);
|
||||
settings_->setValue ("highlight_DXcall", highlight_DXcall_);
|
||||
settings_->setValue ("highlight_DXgrid", highlight_DXgrid_);
|
||||
settings_->setValue ("OTPinterval", OTPinterval_);
|
||||
settings_->setValue ("OTPUrl", OTPUrl_);
|
||||
settings_->setValue ("OTPSeed", OTPSeed_);
|
||||
settings_->setValue ("OTPEnabled", OTPEnabled_);
|
||||
settings_->setValue ("ShowOTP", ShowOTP_);
|
||||
settings_->sync ();
|
||||
}
|
||||
|
||||
@ -2324,6 +2428,11 @@ void Configuration::impl::accept ()
|
||||
pwrBandTxMemory_ = ui_->checkBoxPwrBandTxMemory->isChecked ();
|
||||
pwrBandTuneMemory_ = ui_->checkBoxPwrBandTuneMemory->isChecked ();
|
||||
opCall_=ui_->opCallEntry->text();
|
||||
OTPinterval_=ui_->sbOTPinterval->value();
|
||||
OTPSeed_=ui_->OTPSeed->text();
|
||||
OTPUrl_=ui_->OTPUrl->text();
|
||||
OTPEnabled_=ui_->cbOTP->isChecked();
|
||||
ShowOTP_=ui_->cbShowOTP->isChecked();
|
||||
|
||||
auto new_server = ui_->udp_server_line_edit->text ().trimmed ();
|
||||
auto new_interfaces = get_selected_network_interfaces (ui_->udp_interfaces_combo_box);
|
||||
@ -3113,6 +3222,160 @@ void Configuration::impl::on_cbx4ToneSpacing_clicked(bool b)
|
||||
if(b) ui_->cbx2ToneSpacing->setChecked(false);
|
||||
}
|
||||
|
||||
void Configuration::impl::on_gbSpecialOpActivity_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbFox_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbHound_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbNA_VHF_Contest_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbEU_VHF_Contest_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbWW_DIGI_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbQ65pileup_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbField_Day_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbRTTY_Roundup_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_rbARRL_Digi_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_cbSuperFox_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_cbContestName_clicked (bool)
|
||||
{
|
||||
check_visibility ();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_cbOTP_clicked(bool)
|
||||
{
|
||||
check_visibility();
|
||||
}
|
||||
|
||||
void Configuration::impl::on_cbShowOTP_clicked(bool)
|
||||
{
|
||||
check_visibility();
|
||||
}
|
||||
|
||||
void Configuration::impl::check_visibility ()
|
||||
{
|
||||
if (ui_->rbField_Day->isChecked() and ui_->gbSpecialOpActivity->isChecked()) {
|
||||
ui_->labFD->setEnabled (true);
|
||||
ui_->Field_Day_Exchange->setEnabled (true);
|
||||
} else {
|
||||
ui_->labFD->setEnabled (false);
|
||||
ui_->Field_Day_Exchange->setEnabled (false);
|
||||
}
|
||||
if (ui_->rbRTTY_Roundup->isChecked() and ui_->gbSpecialOpActivity->isChecked()) {
|
||||
ui_->labRTTY->setEnabled (true);
|
||||
ui_->RTTY_Exchange->setEnabled (true);
|
||||
} else {
|
||||
ui_->labRTTY->setEnabled (false);
|
||||
ui_->RTTY_Exchange->setEnabled (false);
|
||||
}
|
||||
if (ui_->cbContestName->isChecked() and !ui_->rbFox->isChecked() and !ui_->rbHound->isChecked()
|
||||
and !ui_->rbQ65pileup->isChecked() and ui_->gbSpecialOpActivity->isChecked()) {
|
||||
ui_->labCN->setEnabled (true);
|
||||
ui_->Contest_Name->setEnabled (true);
|
||||
} else {
|
||||
ui_->labCN->setEnabled (false);
|
||||
ui_->Contest_Name->setEnabled (false);
|
||||
}
|
||||
if ((ui_->rbFox->isChecked() or ui_->rbHound->isChecked()) and ui_->gbSpecialOpActivity->isChecked()) {
|
||||
ui_->cbSuperFox->setEnabled (true);
|
||||
ui_->cbOTP->setEnabled (true);
|
||||
} else {
|
||||
ui_->cbSuperFox->setEnabled (false);
|
||||
ui_->cbOTP->setEnabled (false);
|
||||
ui_->cbShowOTP->setEnabled(false);
|
||||
}
|
||||
if (!ui_->rbFox->isChecked() and !ui_->rbHound->isChecked() and !ui_->rbQ65pileup->isChecked()
|
||||
and ui_->gbSpecialOpActivity->isChecked()) {
|
||||
ui_->cbContestName->setEnabled (true);
|
||||
} else {
|
||||
ui_->cbContestName->setEnabled (false);
|
||||
}
|
||||
if (!ui_->cbOTP->isChecked() or !ui_->gbSpecialOpActivity->isChecked()) {
|
||||
ui_->OTPSeed->setEnabled(false);
|
||||
ui_->OTPUrl->setEnabled(false);
|
||||
ui_->sbOTPinterval->setEnabled(false);
|
||||
ui_->lblOTPSeed->setEnabled(false);
|
||||
ui_->lblOTPUrl->setEnabled(false);
|
||||
ui_->lblOTPEvery->setEnabled(false);
|
||||
ui_->cbShowOTP->setEnabled(false);
|
||||
} else {
|
||||
if (ui_->rbHound->isChecked()) {
|
||||
if (ui_->OTPUrl->text().isEmpty())
|
||||
{
|
||||
ui_->OTPUrl->setText(FoxVerifier::default_url());
|
||||
}
|
||||
ui_->OTPUrl->setEnabled(true);
|
||||
ui_->lblOTPUrl->setEnabled(true);
|
||||
ui_->cbShowOTP->setEnabled(true);
|
||||
} else {
|
||||
ui_->OTPUrl->setEnabled(false);
|
||||
ui_->lblOTPUrl->setEnabled(false);
|
||||
}
|
||||
if (ui_->rbFox->isChecked()) {
|
||||
ui_->sbOTPinterval->setEnabled(true);
|
||||
ui_->OTPSeed->setEnabled(true);
|
||||
ui_->lblOTPSeed->setEnabled(true);
|
||||
ui_->lblOTPEvery->setEnabled(true);
|
||||
ui_->cbShowOTP->setEnabled(false);
|
||||
} else {
|
||||
ui_->OTPSeed->setEnabled(false);
|
||||
ui_->lblOTPSeed->setEnabled(false);
|
||||
ui_->lblOTPEvery->setEnabled(false);
|
||||
ui_->sbOTPinterval->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
void Configuration::impl::on_OTPUrl_textEdited (QString const& url){
|
||||
auto text = url;
|
||||
if (text.size() == 0)
|
||||
{
|
||||
ui_->OTPUrl->setText(FoxVerifier::default_url());
|
||||
}
|
||||
}
|
||||
void Configuration::impl::on_OTPSeed_textEdited (QString const& url){
|
||||
ui_->OTPSeed->setText(url.toUpper());
|
||||
}
|
||||
|
||||
void Configuration::impl::on_Field_Day_Exchange_textEdited (QString const& exchange)
|
||||
{
|
||||
auto text = exchange.simplified ().toUpper ();
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "models/IARURegions.hpp"
|
||||
#include "Audio/AudioDevice.hpp"
|
||||
#include "Transceiver/Transceiver.hpp"
|
||||
#include "otpgenerator.h"
|
||||
|
||||
#include "pimpl_h.hpp"
|
||||
|
||||
@ -188,10 +189,16 @@ public:
|
||||
void setSpecial_Hound();
|
||||
void setSpecial_Fox();
|
||||
void setSpecial_None();
|
||||
void toggle_SF();
|
||||
bool highlight_DXcall () const;
|
||||
bool highlight_DXgrid () const;
|
||||
bool Individual_Contest_Name() const;
|
||||
|
||||
bool validate_otp_seed(QString);
|
||||
QString OTPSeed() const;
|
||||
QString OTPUrl() const;
|
||||
bool OTPEnabled() const;
|
||||
bool ShowOTP() const;
|
||||
unsigned int OTPinterval() const;
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, FOX, HOUND, ARRL_DIGI, Q65_PILEUP};
|
||||
SpecialOperatingActivity special_op_id () const;
|
||||
|
731
Configuration.ui
731
Configuration.ui
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
<width>760</width>
|
||||
<height>648</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -2907,267 +2907,8 @@ Right click for insert and delete options.</string>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,0,0,0,0">
|
||||
<item row="0" column="2" rowspan="3">
|
||||
<spacer name="horizontalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QRadioButton" name="rbQ65pileup">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Exchange 4-character locator instead of signal report. Provides q3-level sensitivities for the DX operator. Especially useful for 6m EME DXpeditions.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Q65 Pileup</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="rbNA_VHF_Contest">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>NA VHF Contest</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>NA VHF</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QRadioButton" name="rbWW_DIGI">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>World-Wide Digi-mode contest</p><p><br/></p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>WW Digital Contest</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>WW Digi Contest</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbRTTY_Roundup">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>R T T Y Roundup</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FT Roundup</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_17">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labRTTY">
|
||||
<property name="accessibleName">
|
||||
<string>RTTY Roundup exchange</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FT RU Exch:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>RTTY_Exchange</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="RTTY_Exchange">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>NJ</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_24">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbContestName">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Call CQ with an individual contest name instead of TEST, RU, or WW. </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>CQ with individual contest name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_12">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_25">
|
||||
<item>
|
||||
<widget class="QLabel" name="labCN">
|
||||
<property name="text">
|
||||
<string>Contest name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="Contest_Name">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="cursorPosition">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QRadioButton" name="rbARRL_Digi">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>ARRL International Digital Contest</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ARRL Digi Contest</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="rbEU_VHF_Contest">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>European VHF+ contests requiring a signal report, serial number, and 6-character locator.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>EU VHF Contest</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>EU VHF Contest</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="rbFox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT8 DXpedition mode: Fox (DXpedition) operator.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Fox</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fox</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,1,0,2">
|
||||
<item row="2" column="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_17" stretch="2,1,1">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbField_Day">
|
||||
@ -3236,19 +2977,119 @@ Right click for insert and delete options.</string>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QRadioButton" name="rbHound">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html></string>
|
||||
<item row="1" column="3">
|
||||
<layout class="QHBoxLayout" name="OTP_Layout_2" stretch="0,0,0,1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbShowOTP">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Show OTP messages in the Band Activity window.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show OTP messages</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_17">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblOTPUrl">
|
||||
<property name="text">
|
||||
<string>OTP URL:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="OTPUrl">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>110</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>URL used to verify OTP codes.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>https://www.9dx.cc</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QRadioButton" name="rbQ65pileup">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Hound</string>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Exchange 4-character locator instead of signal report. Provides q3-level sensitivities for the DX operator. Especially useful for 6m EME DXpeditions.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Hound</string>
|
||||
<string>Q65 Pileup</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="rbNA_VHF_Contest">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>NA VHF Contest</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>NA VHF</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QRadioButton" name="rbEU_VHF_Contest">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>European VHF+ contests requiring a signal report, serial number, and 6-character locator.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>EU VHF Contest</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>EU VHF Contest</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
@ -3257,11 +3098,338 @@ Right click for insert and delete options.</string>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="cbSuperFox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Check this box to transmit (Fox) or receive (Hound) the SuperFox waveform.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SuperFox</string>
|
||||
<string>SuperFox mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="rbFox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT8 DXpedition mode: Fox (DXpedition) operator.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Fox</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fox</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QRadioButton" name="rbARRL_Digi">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>ARRL International Digital Contest</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ARRL Digi Contest</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_24">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbContestName">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Call CQ with an individual contest name instead of TEST, RU, or WW. </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>CQ with individual contest name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_12">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_25">
|
||||
<item>
|
||||
<widget class="QLabel" name="labCN">
|
||||
<property name="text">
|
||||
<string>Contest name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="Contest_Name">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="cursorPosition">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbRTTY_Roundup">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>R T T Y Roundup</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FT Roundup</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_17">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labRTTY">
|
||||
<property name="accessibleName">
|
||||
<string>RTTY Roundup exchange</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FT RU Exch:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>RTTY_Exchange</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="RTTY_Exchange">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>NJ</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QRadioButton" name="rbWW_DIGI">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>World-Wide Digi-mode contest</p><p><br/></p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>WW Digital Contest</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>WW Digi Contest</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_27" stretch="0,1">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbHound">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html></string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Hound</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Hound</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">special_op_activity_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_15">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<layout class="QHBoxLayout" name="OTP_Layout" stretch="0,0,0,1,0,0,0,1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbOTP">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Click to enable OTP method of Fox verification. Requires internet.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>OTP</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>7</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblOTPSeed">
|
||||
<property name="text">
|
||||
<string>Key:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="OTPSeed">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>110</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Fox's key to generate OTP Codes.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>M2ZUU5CW6EVOY2HU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_14">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblOTPEvery">
|
||||
<property name="text">
|
||||
<string>Interval</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbOTPinterval">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Interval at which the OTP messages are sent. Select 1 to sign every message.</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_15">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -3427,13 +3595,8 @@ Right click for insert and delete options.</string>
|
||||
<tabstop>rbLowSidelobes</tabstop>
|
||||
<tabstop>rbMaxSensitivity</tabstop>
|
||||
<tabstop>gbSpecialOpActivity</tabstop>
|
||||
<tabstop>rbFox</tabstop>
|
||||
<tabstop>rbHound</tabstop>
|
||||
<tabstop>rbNA_VHF_Contest</tabstop>
|
||||
<tabstop>rbField_Day</tabstop>
|
||||
<tabstop>rbEU_VHF_Contest</tabstop>
|
||||
<tabstop>rbRTTY_Roundup</tabstop>
|
||||
<tabstop>rbWW_DIGI</tabstop>
|
||||
<tabstop>Field_Day_Exchange</tabstop>
|
||||
<tabstop>RTTY_Exchange</tabstop>
|
||||
</tabstops>
|
||||
@ -3505,13 +3668,13 @@ Right click for insert and delete options.</string>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="split_mode_button_group"/>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="CAT_handshake_button_group"/>
|
||||
<buttongroup name="special_op_activity_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="split_mode_button_group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
@ -1,122 +1,132 @@
|
||||
Notes on WSJT-X Installation for Mac OS X
|
||||
-----------------------------------------
|
||||
|
||||
If you have already downloaded a previous version of WSJT-X then I suggest
|
||||
you change the name in the Applications folder from WSJT-X to WSJT-X_previous
|
||||
before proceeding.
|
||||
|
||||
I recommend that you follow the installation instructions especially if you
|
||||
are moving from v2.5 to v2.6 or later, of WSJT-X or you have upgraded macOS.
|
||||
|
||||
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from K1JT's web-site.
|
||||
Make sure that you leave this window open for the remaining installation steps.
|
||||
|
||||
Now open a Terminal window by going to Applications->Utilities and clicking on Terminal.
|
||||
|
||||
Along with this ReadMe file there is a file: com.wsjtx.sysctl.plist which must be copied to a
|
||||
system area by typing these lines in the Terminal window and then pressing the Return key after
|
||||
each line.
|
||||
|
||||
sudo cp /Volumes/WSJT-X/com.wsjtx.sysctl.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/com.wsjtx.sysctl.plist
|
||||
|
||||
you will be asked for your normal password because authorisation is needed to copy this file.
|
||||
(Your password will not be echoed but press the Return key when completed.)
|
||||
|
||||
IMPORTANT: Now re-boot your Mac otherwise these changes will not take effect.
|
||||
|
||||
After the reboot you should re-open the Terminal window as before and you can check
|
||||
that the change has been made by typing:
|
||||
|
||||
sysctl -a | grep sysv.shm
|
||||
|
||||
If shmmax is not shown as 52428800 then contact me since WSJT-X will fail to load with
|
||||
an error message: "Unable to create shared memory segment". If the value of shmmax
|
||||
is shown as 20971520 then it is probable that you have download JTDX. WSJT-X and JTDX
|
||||
cannot both control the shmmax paramter. Contact me for advice.
|
||||
|
||||
You can now close the Terminal window. It will not be necessary to repeat this procedure
|
||||
again, even when you download an updated version of WSJT-X. It might be necessary if you
|
||||
upgrade macOS.
|
||||
|
||||
Drag the WSJT-X app to your preferred location, such as Applications.
|
||||
|
||||
You need to configure your sound card. Visit Applications > Utilities > Audio MIDI
|
||||
Setup and select your sound card and then set Format to be "48000Hz 2ch-16bit" for
|
||||
input and output.
|
||||
|
||||
Now double-click on the WSJT-X app and two windows will appear. Select Preferences
|
||||
under the WSJT-X Menu and fill in various station details on the General panel.
|
||||
I recommend checking the 4 boxes under the Display heading and the first 4 boxes under
|
||||
the Behaviour heading.
|
||||
|
||||
Depending on your macOS you might see a pop-up window suggesting that wsjtx wants to use the
|
||||
microphone. What this means is that audio input must be allowed. Agree.
|
||||
|
||||
Next visit the Audio panel and select the Audio Codec you use to communicate between
|
||||
WSJT-X and your rig. There are so many audio interfaces available that it is not
|
||||
possible to give detailed advice on selection. If you have difficulties contact me.
|
||||
Note the location of the Save Directory. Decoded wave forms are located here.
|
||||
|
||||
Look at the Reporting panel. If you check the "Prompt me" box, a logging panel will appear
|
||||
at the end of the QSO. Visit Section 11 of the User Guide for information about log files
|
||||
and how to access them.
|
||||
|
||||
Finally, visit the Radio panel. WSJT-X is most effective when operated with CAT
|
||||
control. You will need to install the relevant Mac device driver for your rig,
|
||||
and then re-launch WSJT-X. Return to the Radio panel in Preferences and in
|
||||
the "Serial port" panel select your driver from the list that is presented.
|
||||
|
||||
You may need a device driver for your Mac. The USB/UART Bridge chip inside the Icom,
|
||||
Yaesu and Kenwood radios is a Silicon Labs USB to UART Bridge Controller and the Mac
|
||||
drivers are available here:
|
||||
|
||||
https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers
|
||||
|
||||
Visit the SiLabs site and download v6 for a Mac. Then in WSJT-X if you use the drop-down menu
|
||||
for Serial Port you should see something like /dev/tty.SLAB_USBtoUART if the driver has been
|
||||
installed correctly. Make sure you read the release notes that come with the driver.
|
||||
|
||||
WSJT-X needs the Mac clock to be accurate. Visit System Preferences > Date & Time
|
||||
and make sure that Date and Time are set automatically. The drop-down menu will
|
||||
normally offer you several time servers to choose from.
|
||||
|
||||
On the Help menu, have a look at the new Online User's Guide for operational hints
|
||||
and tips and possible solutions to any problem you might have.
|
||||
|
||||
Please email me if you have problems.
|
||||
|
||||
--- John G4KLA (g4kla@rmnjmn.co.uk)
|
||||
|
||||
Addendum: Information about com.wsjtx.sysctl.plist and multiple instances of WSJT-X.
|
||||
|
||||
WSJT-X makes use of a block of memory which is shared between different parts of
|
||||
the code. The normal allocation of shared memory on a Mac is insufficient and this
|
||||
has to be increased. The com.wsjtx.sysctl.plist file is used for this purpose. You can
|
||||
use a Mac editor to examine the file. (Do not use another editor - the file
|
||||
would probably be corrupted.)
|
||||
|
||||
It is possible to run two instances of WSJT-X simultaneously. See "Section 16.2
|
||||
Frequently asked Questions" in the User Guide. If you wish to run more than two instances
|
||||
simultaneously, the shmall parameter in the com.wsjtx.sysctl.plist file needs to be modified as follows.
|
||||
|
||||
The shmall parameter determines the amount of shared memory which is allocated in 4096 byte pages
|
||||
with 50MB (52428800) required for each instance. The shmall parameter is calculated as:
|
||||
(n * 52428800)/4096 where 'n' is the number of instances required to run simultaneously.
|
||||
Replace your new version of this file in /Library/LaunchDaemons and remember to reboot your
|
||||
Mac afterwards.
|
||||
|
||||
Note that the shmmax parameter remains unchanged. This is the maximum amount of shared memory that
|
||||
any one instance is allowed to request from the total shared memory allocation and should not
|
||||
be changed.
|
||||
|
||||
If two instances of WSJT-X are running, it is likely that you might need additional
|
||||
audio devices, from two rigs for example. Visit Audio MIDI Setup and create an Aggregate Device
|
||||
which will allow you to specify more than one interface. I recommend you consult Apple's guide
|
||||
on combining multiple audio interfaces which is at https://support.apple.com/en-us/HT202000.
|
||||
|
||||
2. Preventing WSJT-X from being put into 'sleep' mode (App Nap).
|
||||
|
||||
In normal circumstances an application which has not been directly accessed for a while can be
|
||||
subject to App Nap which means it is suspended until such time as its windows are accessed. If
|
||||
|
||||
Notes on WSJT-X Installation for Mac OS X
|
||||
-----------------------------------------
|
||||
|
||||
If you have already downloaded a previous version of WSJT-X then I suggest
|
||||
you change the name in the Applications folder from WSJT-X to WSJT-X_previous
|
||||
before proceeding.
|
||||
|
||||
I recommend that you follow the installation instructions especially if you
|
||||
are moving from v2.5 to v2.6 or later, of WSJT-X or you have upgraded macOS.
|
||||
|
||||
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from the main web-site.
|
||||
Make sure that you leave this window open for the remaining installation steps.
|
||||
|
||||
Now open a Terminal window by going to Applications->Utilities and clicking on Terminal.
|
||||
|
||||
Along with this ReadMe file there is a file: com.wsjtx.sysctl.plist which must be copied to a
|
||||
system area by typing these lines in the Terminal window and then pressing the Return key after
|
||||
each line.
|
||||
|
||||
sudo cp /Volumes/WSJT-X/com.wsjtx.sysctl.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/com.wsjtx.sysctl.plist
|
||||
|
||||
you will be asked for your normal password because authorisation is needed to copy this file.
|
||||
(Your password will not be echoed but press the Return key when completed.)
|
||||
|
||||
If your Mac is using Sonoma 14.6 or later then in addition to these two commands you must visit:
|
||||
|
||||
System Settings > General > Login Items > sysctl and select ON for sysctl.
|
||||
|
||||
IMPORTANT: Now re-boot your Mac otherwise these changes will not take effect.
|
||||
|
||||
After the reboot you should re-open the Terminal window as before and you can check
|
||||
that the change has been made by typing:
|
||||
|
||||
sysctl -a | grep sysv.shm
|
||||
|
||||
If shmmax is not shown as 52428800 then contact me since WSJT-X will fail to load with
|
||||
an error message: "Unable to create shared memory segment". If the value of shmmax
|
||||
is shown as 20971520 then it is probable that you have download JTDX. WSJT-X and JTDX
|
||||
cannot both control the shmmax parameter. Contact me for advice.
|
||||
|
||||
You can now close the Terminal window. It will not be necessary to repeat this procedure
|
||||
again, even when you download an updated version of WSJT-X. It might be necessary if you
|
||||
upgrade macOS.
|
||||
|
||||
Drag the WSJT-X app to your preferred location, such as Applications, and close the window.
|
||||
|
||||
You need to configure your sound card. Visit Applications > Utilities > Audio MIDI
|
||||
Setup and select your sound card and then set Format to be "48000Hz 2ch-16bit" for
|
||||
input and output. On rare occasions problems with audio output to your rig can be
|
||||
corrected if you select 44100Hz for output format.
|
||||
|
||||
Now double-click on the WSJT-X app and two windows will appear. Select Preferences
|
||||
under the WSJT-X Menu and fill in various station details on the General panel.
|
||||
I recommend checking the 4 boxes under the Display heading and the first 4 boxes under
|
||||
the Behaviour heading.
|
||||
|
||||
Depending on your macOS you might see a pop-up window suggesting that wsjtx wants to use the
|
||||
microphone. What this means is that audio input must be allowed. Agree.
|
||||
|
||||
Next visit the Audio panel and select the Audio Codec you use to communicate between
|
||||
WSJT-X and your rig. There are so many audio interfaces available that it is not
|
||||
possible to give detailed advice on selection. If you have difficulties contact me.
|
||||
Note the location of the Save Directory. Decoded wave forms are located here.
|
||||
|
||||
Look at the Reporting panel. If you check the "Prompt me" box, a logging panel will appear
|
||||
at the end of the QSO. Visit Section 11 of the User Guide for information about log files
|
||||
and how to access them.
|
||||
|
||||
Finally, visit the Radio panel. WSJT-X is most effective when operated with CAT
|
||||
control. You will need to install the relevant Mac device driver for your rig,
|
||||
and then re-launch WSJT-X. Return to the Radio panel in Preferences and in
|
||||
the "Serial port" panel select your driver from the list that is presented.
|
||||
|
||||
You may need a device driver for your Mac. The USB/UART Bridge chip inside the Icom,
|
||||
Yaesu and Kenwood radios is a Silicon Labs USB to UART Bridge Controller and the Mac
|
||||
drivers are available here:
|
||||
|
||||
https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers
|
||||
|
||||
Visit the SiLabs site and download v6 for a Mac. Then in WSJT-X if you use the drop-down menu
|
||||
for Serial Port you should see something like /dev/tty.SLAB_USBtoUART if the driver has been
|
||||
installed correctly. Make sure you read the release notes that come with the driver.
|
||||
|
||||
WSJT-X needs the Mac clock to be accurate. Visit System Preferences > Date & Time
|
||||
and make sure that Date and Time are set automatically. The drop-down menu will
|
||||
normally offer you several time servers to choose from.
|
||||
|
||||
On the Help menu, have a look at the new Online User's Guide for operational hints
|
||||
and tips and possible solutions to any problem you might have.
|
||||
|
||||
Please email me if you have problems.
|
||||
|
||||
--- John G4KLA (g4kla@rmnjmn.co.uk)
|
||||
|
||||
Addendum: Information about com.wsjtx.sysctl.plist and multiple instances of WSJT-X.
|
||||
|
||||
WSJT-X makes use of a block of memory which is shared between different parts of
|
||||
the code. The normal allocation of shared memory on a Mac is insufficient and this
|
||||
has to be increased. The com.wsjtx.sysctl.plist file is used for this purpose. You can
|
||||
use a Mac editor to examine the file. (Do not use another editor - the file
|
||||
would probably be corrupted.)
|
||||
|
||||
It is possible to run two instances of WSJT-X simultaneously. See "Section 16.2
|
||||
Frequently asked Questions" in the User Guide. If you wish to run more than two instances
|
||||
simultaneously, the shmall parameter in the com.wsjtx.sysctl.plist file needs to be modified as follows.
|
||||
|
||||
The shmall parameter determines the amount of shared memory which is allocated in 4096 byte pages
|
||||
with 50MB (52428800) required for each instance. The shmall parameter is calculated as:
|
||||
(n * 52428800)/4096 where 'n' is the number of instances required to run simultaneously.
|
||||
Replace your new version of this file in /Library/LaunchDaemons and remember to reboot your
|
||||
Mac afterwards.
|
||||
|
||||
Note that the shmmax parameter remains unchanged. This is the maximum amount of shared memory that
|
||||
any one instance is allowed to request from the total shared memory allocation and should not
|
||||
be changed.
|
||||
|
||||
If two instances of WSJT-X are running, it is likely that you might need additional
|
||||
audio devices, from two rigs for example. Visit Audio MIDI Setup and create an Aggregate Device
|
||||
which will allow you to specify more than one interface. I recommend you consult Apple's guide
|
||||
on combining multiple audio interfaces which is at https://support.apple.com/en-us/HT202000.
|
||||
|
||||
2. Preventing WSJT-X from being put into 'sleep' mode (App Nap).
|
||||
|
||||
In normal circumstances an application which has not been directly accessed for a while can be
|
||||
subject to App Nap which means it is suspended until such time as its windows are accessed. If
|
||||
you find that WSJT-X seems disabled check this by opening Applications > Utilities > Activity Monitor and
|
||||
then select Energy and look at the column marked App Nap. If you see wsjtx marked "Yes" then you need
|
||||
to disable App Nap by opening a Terminal window and typing:
|
||||
defaults write NSGlobalDomain NSAppSleepDisabled -bool YES
|
||||
This will disable App Nap for all applications. If you wish to reverse this type:
|
||||
defaults delete NSGlobalDomain NSAppSleepDisabled
|
||||
|
@ -70,9 +70,10 @@ void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSym
|
||||
m_bFastMode=fastMode;
|
||||
m_TRperiod=TRperiod;
|
||||
unsigned delay_ms=1000;
|
||||
if(mode=="FT8" or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15
|
||||
if(mode=="Q65" and m_nsps<=3600) delay_ms=500; //Q65-15 and Q65-30
|
||||
if(mode=="FT4") delay_ms=300; //FT4
|
||||
if((mode=="FT8" and m_nsps==1920) or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15
|
||||
if((mode=="FT8" and m_nsps==1024)) delay_ms=400; //SuperFox Qary Polar Code transmission
|
||||
if(mode=="Q65" and m_nsps<=3600) delay_ms=500; //Q65-15 and Q65-30
|
||||
if(mode=="FT4") delay_ms=300; //FT4
|
||||
|
||||
// noise generator parameters
|
||||
if (m_addNoise) {
|
||||
|
244
NEWS
244
NEWS
@ -11,6 +11,250 @@
|
||||
|
||||
Copyright 2001 - 2024 by Joe Taylor, K1JT, and the WSJT Development Team
|
||||
|
||||
|
||||
Release: WSJT-X 2.7.0-rc7
|
||||
September 30, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 7 brings significant improvements for
|
||||
the new SuperFox mode. It introduces a new verification system which
|
||||
replaces the previous one, and works for both the SuperFox mode and
|
||||
for old-style Fox and Hound operation. All code for SuperFox
|
||||
operation is now open source.
|
||||
|
||||
IMPORTANT: OpenSSL v1.1.1 or higher is required for the real-time
|
||||
verification of Fox and SuperFox messages.
|
||||
|
||||
Enhancements to the SuperFox decoder:
|
||||
|
||||
- Performance of the SuperFox decoder has been further improved.
|
||||
|
||||
- You can now set individual FTol values and tune the decoder to
|
||||
the exact sync frequency of the SuperFox signal if it is not exactly
|
||||
750 Hz. Both result in a better decodability in certain situations.
|
||||
|
||||
- Important: The Rx frequency must be set close to the sync frequency
|
||||
+/- FTol, for example 750 +/- 50 Hz.
|
||||
|
||||
Introduction of a new Fox verification system:
|
||||
|
||||
- The new Fox verification system uses one time passwords (OTPs), and
|
||||
works for the SuperFox mode as well as for old-style Fox and Hound
|
||||
operation. It can be enabled by the new OTP checkbox on the Advanced
|
||||
tab of the Settings dialog.
|
||||
|
||||
- Fox or SuperFox stations send individual OTPs via radio. Hounds
|
||||
automatically check the validity of the received OTPs in real time
|
||||
from a server when there is an internet connection. Otherwise, the
|
||||
validity can also be queried manually later. OTP verifications can
|
||||
only be retrieved once the transmission has already taken place.
|
||||
|
||||
- You may optionally display the received OTP values by checking
|
||||
the box "Show OTP messages".
|
||||
|
||||
- If the Fox or SuperFox callsign is verified by receipt of the
|
||||
correct OTP, the background color of the Hound or Super Hound label
|
||||
switches to green.
|
||||
|
||||
- Theoretically, DXpeditions can set up their own OTP server, however,
|
||||
we recommend using the server at https://www.9dx.cc.
|
||||
|
||||
- Use of the new Fox verification system requires an OTP key. The
|
||||
system uses open source code and standard encryption
|
||||
technology. For testing purposes, non-verified SuperFox
|
||||
transmissions are now possible without a key.
|
||||
|
||||
Improvements to SuperFox/Hound operation:
|
||||
|
||||
- SuperHounds must now first decode the SuperFox before they can
|
||||
call, and a QSO must be started by double-clicking on a SuperFox
|
||||
decode. (Note that calling the Fox blindly not only leads to
|
||||
unnecessary band utilization, but can also significantly reduce the
|
||||
QSO rate due to unanswered (Super)Fox replies.)
|
||||
|
||||
- Switching to SuperHound mode automatically sets the Rx frequency to
|
||||
750 Hz. The previously selected frequency is saved and restored
|
||||
afterwards.
|
||||
|
||||
- Right-clicking on the H button now activates/deactivates SuperFox mode.
|
||||
|
||||
- A flaw resulting in sub-optimal SuperFox QSO rates has been
|
||||
corrected.
|
||||
|
||||
- SuperFox decoder now does a more thorough job of rejecting QRM from
|
||||
non-SuperFox signals.
|
||||
|
||||
- Fields in the SuperFox payload not otherwise used in a particular
|
||||
transmission are now set to known nonzero values. Do NOT use RC6 or
|
||||
earlier versions to decode SuperFox transmissions from RC7 or
|
||||
later.
|
||||
|
||||
- Old-style Fox stations can now transmit free text messages (up to
|
||||
13 characters) by using an available stream.
|
||||
|
||||
- Some enhancements useful for Fox operators: Active Station Window now
|
||||
shows band activity. Hound callsigns can be highlighted via UDP API, and
|
||||
assigned a score for sorting via UDP API. Fox Tx frequency is preserved
|
||||
when switching in/out of Fox mode.
|
||||
|
||||
- UDP Status Update messages now include information on how many callsigns
|
||||
have highlighting applied, and how many callsigns have a score assigned.
|
||||
|
||||
Other enhancements and fixes:
|
||||
|
||||
- In FT8 mode, the Settings dialog no longer resets the VFO frequency
|
||||
to band/mode default unless really needed.
|
||||
|
||||
- Several code improvements specifically for macOS.
|
||||
|
||||
- Updated CTY.DAT and Hamlib.
|
||||
|
||||
|
||||
Release: WSJT-X 2.7.0-rc6
|
||||
July 19, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 6 is a bug-fix release primarily
|
||||
affecting the new SuperFox mode. The following bugs have been fixed:
|
||||
|
||||
- Strong signals from Superfox too frequently failed to decode.
|
||||
|
||||
- SuperFox sometimes sent incorrect signal reports and an invalid
|
||||
digital signature.
|
||||
|
||||
- A Fortran bounds error could sometimes occur in the SuperFox
|
||||
decoder.
|
||||
|
||||
- For SuperFox operator, the "age" displayed for Hound callers
|
||||
became garbled after the 0000 UTC date change.
|
||||
|
||||
- Decodes of SuperFox transmissions were not posted to PSK Reporter.
|
||||
|
||||
- Some SuperFox-related messages were posted incorrectly to ALL.TXT.
|
||||
|
||||
- Logic for turning the SuperHound label green was flawed in some
|
||||
circumstances.
|
||||
|
||||
Release Candidate 6 also includes updates to Hamlib and the Chinese
|
||||
user interface translation.
|
||||
|
||||
Release: WSJT-X 2.7.0-rc5
|
||||
July 1, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 5 introduces "SuperFox" mode, a
|
||||
powerful new tool designed to help DXpeditions make digital QSOs at
|
||||
very high rates. RC5 also brings several other improvements and bug
|
||||
fixes.
|
||||
|
||||
SuperFox mode:
|
||||
|
||||
- The SuperFox mode behaves operationally like the present Fox and
|
||||
Hounds mode but uses a constant envelope waveform for Fox's
|
||||
transmissions rather than sending concurrent streams of up to five
|
||||
normal FT8 signals. This approach means that up to 9 messages can
|
||||
be transmitted simultaneously with no signal-strength penalty,
|
||||
resulting in a system gain of about +10 dB compared to the
|
||||
conventional Fox/Hound operation with 5 slots.
|
||||
|
||||
- IMPORTANT: Older revisions of WSJT-X and derivative programs will
|
||||
not be able to decode SuperFox transmissions. Hounds must use
|
||||
WSJT-X 2.7.0-rc5 (or a later release, when available) to receive
|
||||
SuperFox messages.
|
||||
|
||||
- Hounds chasing the DX station will transmit normal FT8 signals, as
|
||||
in the old-style Fox and Hound mode. QSOs will be logged as FT8
|
||||
mode.
|
||||
|
||||
- When using SuperFox mode, Hound stations may call at any frequency
|
||||
in Fox's received passband, including the range 0 - 1000 Hz.
|
||||
Hounds do not QSY to a lower frequency for their final
|
||||
transmission.
|
||||
|
||||
- SuperFox Operation requires the Fox operator to use a valid digital
|
||||
key. Keys will be issued in advance to legitimate DXpeditions by
|
||||
the Northern California DX Foundation, and will be kept secret.
|
||||
|
||||
- Every SuperFox transmission includes a unique digital signature.
|
||||
Hounds receiving a SuperFox message will see a "<callsign> verified"
|
||||
flag if the transmitted signature is valid, and the on-screen
|
||||
"Super Hound" label will turn from red to green.
|
||||
|
||||
- Hound operation should begin by selecting "Special operating
|
||||
activity", "Hound", and "SuperFox mode" on the Settings -> Advanced
|
||||
tab. Alternatively, right-clicking on the FT8 button toggles
|
||||
SuperFox mode on/off for either Fox or Hound, allowing quick
|
||||
transitions between SuperFox and old-style Fox and Hound operation.
|
||||
|
||||
- SuperFox stations can send free text messages of up to 26 characters
|
||||
together with messages to as many as 4 Hounds.
|
||||
|
||||
Other enhancements:
|
||||
|
||||
- Corrected a flaw that caused "Log automatically" to not work for
|
||||
the ARRL Digi Contest.
|
||||
|
||||
- Control elements for special operating activities are now disabled
|
||||
(grayed out) if the respective function is not applicable.
|
||||
|
||||
- Corrected a longstanding flaw that caused "Start new period
|
||||
decodes at top" to stop working properly after some time.
|
||||
|
||||
- Right-click mouse press events are now less error-prone.
|
||||
|
||||
- Improved the readability of the first line when "Start new period
|
||||
decodes at top" is checked.
|
||||
|
||||
- 4-digit grids are now logged for certain contest modes to ensure that
|
||||
the log complies with contest rules.
|
||||
|
||||
- The Fox Tx frequency is now saved and restored separately.
|
||||
|
||||
|
||||
Release: WSJT-X 2.7.0-rc4
|
||||
March 11, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 4 brings some improvements for Fox-mode
|
||||
operators, new features for companion program QMAP, and a number of
|
||||
relatively minor enhancements and bug fixes.
|
||||
|
||||
QMAP enhancements -- of particular interest to EME operators:
|
||||
|
||||
- QMAP now decodes Q65 submodes with both 60-second and 30-second T/R
|
||||
sequence lengths. Clicking on a resulting line in the WSJT-X Active
|
||||
Stations window automatically sets dial frequency and working
|
||||
submode as needed to call that station.
|
||||
|
||||
- QMAP operates in 60-second receive sequences, and its Q65 decoder
|
||||
starts at t=19.5, 30.0, 49.5, and 58.5 s into the sequence. Most
|
||||
decoded messages are displayed well before the end of the relevant
|
||||
time slot.
|
||||
|
||||
- A new, more compact file format is now used for wideband data
|
||||
files. A "Save decoded" option has been added to the Save menu.
|
||||
|
||||
- An option has been added to allow exporting a 3 kHz portion of a
|
||||
wideband data file as a standard WSJT-X *.wav file.
|
||||
|
||||
- CTRL+click on QMAP's upper waterfall sends an integer kHz dial
|
||||
frequency request to WSJT-X.
|
||||
|
||||
- With focus on the WSJT-X main window, hit Alt+A on the keyboard to
|
||||
clear the Active Stations window.
|
||||
|
||||
- Many minor enhancements to the User Interface.
|
||||
|
||||
WSJT-X:
|
||||
|
||||
- Enable decoding of MSK144 from the jt9[.exe] executable.
|
||||
|
||||
- Several changes to reduce problems experienced when (contrary to
|
||||
our recommendations) messages with short (10-bit) callsign hashes
|
||||
are used in standard FT4/FT8 sub-bands.
|
||||
|
||||
- Enhancements useful for Fox operators.
|
||||
|
||||
Release: WSJT-X 2.7.0-rc3
|
||||
January 1, 2024
|
||||
-------------------------
|
||||
|
125
Network/FoxVerifier.cpp
Normal file
125
Network/FoxVerifier.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include "FoxVerifier.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
FoxVerifier::FoxVerifier(QString user_agent, QNetworkAccessManager *manager,QString base_url, QString callsign, QDateTime timestamp, QString code, unsigned int hz=750) : QObject(nullptr)
|
||||
{
|
||||
manager_ = manager;
|
||||
finished_ = false;
|
||||
errored_ = false;
|
||||
callsign_ = callsign;
|
||||
code_ = code;
|
||||
ts_ = timestamp;
|
||||
hz_ = hz;
|
||||
|
||||
// make sure we URLencode the callsign, for things like E51D/MM
|
||||
QString encodedCall = QString::fromUtf8(QUrl::toPercentEncoding(callsign));
|
||||
QString url = QString("%1/check/").arg(base_url) + encodedCall + QString("/%1/%2.text").arg(timestamp.toString(Qt::ISODate)).arg(code);
|
||||
LOG_INFO(QString("FoxVerifier: url %1").arg(url).toStdString());
|
||||
q_url_ = QUrl(url);
|
||||
if (manager_ == nullptr) {
|
||||
LOG_INFO("FoxVerifier: manager is null, creating new one");
|
||||
manager_ = new QNetworkAccessManager(this);
|
||||
manager_->deleteLater();
|
||||
}
|
||||
if (q_url_.isValid()) {
|
||||
request_ = QNetworkRequest(q_url_);
|
||||
request_.setRawHeader( "User-Agent" , user_agent.toUtf8());
|
||||
request_.setRawHeader( "Accept" , "*/*" );
|
||||
request_.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
request_.setTransferTimeout(FOXVERIFIER_DEFAULT_TIMEOUT_MSEC);
|
||||
#endif
|
||||
|
||||
reply_ = manager_->get(request_);
|
||||
connect(reply_, &QNetworkReply::finished, this, &FoxVerifier::httpFinished);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
connect(reply_, &QNetworkReply::errorOccurred, this, &FoxVerifier::errorOccurred);
|
||||
#endif
|
||||
connect(reply_, &QNetworkReply::redirected, this, &FoxVerifier::httpRedirected);
|
||||
connect(reply_, &QNetworkReply::encrypted, this, &FoxVerifier::httpEncrypted);
|
||||
#if QT_CONFIG(ssl)
|
||||
connect(reply_, &QNetworkReply::sslErrors, this, &FoxVerifier::sslErrors);
|
||||
#else
|
||||
LOG_INFO("FoxVerifier: ssl not supported");
|
||||
#endif
|
||||
|
||||
} else {
|
||||
LOG_INFO(QString("FoxVerifier: url invalid ! %1").arg(url).toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
FoxVerifier::~FoxVerifier() {
|
||||
}
|
||||
|
||||
bool FoxVerifier::finished() {
|
||||
return finished_;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
void FoxVerifier::errorOccurred(QNetworkReply::NetworkError code)
|
||||
{
|
||||
int status = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString reason = reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||
errored_ = true;
|
||||
error_reason_ = reply_->errorString();
|
||||
if (reply_->error() != QNetworkReply::NoError) {
|
||||
|
||||
LOG_INFO(QString("FoxVerifier: errorOccurred status %1 error [%2][%3] isFinished %4 isrunning %5 code %6").arg(status).arg(
|
||||
reason).arg(error_reason_).arg(reply_->isFinished()).arg(reply_->isRunning()).arg(code).toStdString());
|
||||
return;
|
||||
}
|
||||
// TODO emit
|
||||
}
|
||||
#endif
|
||||
|
||||
void FoxVerifier::httpFinished()
|
||||
{
|
||||
int status = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString reason = reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||
if (reply_->error() != QNetworkReply::NoError) {
|
||||
LOG_INFO(QString("FoxVerifier: httpFinished error:[%1 - %2] msg:[%3]").arg(status).arg(reason).arg(reply_->errorString()).toStdString());
|
||||
reply_->abort();
|
||||
emit verifyError(status, ts_, callsign_, code_, hz_, reply_->errorString());
|
||||
}
|
||||
return_value = reply_->read(1024); // limit amount we get
|
||||
LOG_INFO(QString("FoxVerifier: httpFinished status:[%1 - %2] body:[%3] ").arg(status).arg(reason).arg(return_value).toStdString());
|
||||
finished_ = true;
|
||||
reply_->deleteLater();
|
||||
if (status >= 200 && status <= 299) {
|
||||
emit verifyComplete(status, ts_, callsign_, code_, hz_, return_value);
|
||||
}
|
||||
}
|
||||
|
||||
void FoxVerifier::sslErrors(const QList<QSslError> &)
|
||||
{
|
||||
LOG_INFO(QString("FoxVerifier: sslErrors").toStdString());
|
||||
reply_->ignoreSslErrors();
|
||||
}
|
||||
|
||||
void FoxVerifier::httpRedirected(const QUrl &url) {
|
||||
LOG_INFO(QString("FoxVerifier: redirected to %1").arg(url.toString()).toStdString());
|
||||
}
|
||||
|
||||
void FoxVerifier::httpEncrypted() {
|
||||
LOG_INFO("FoxVerifier: httpEncrypted");
|
||||
}
|
||||
|
||||
QString FoxVerifier::formatDecodeMessage(QDateTime ts, QString callsign, unsigned int hz_, QString const& verify_message) {
|
||||
//"172100 -00 0.0 750 ~ K8R VERIFIED"
|
||||
QTime rx_time = ts.time();
|
||||
QString hz=QString("%1").arg(hz_, 4, 10 ); // insert Hz
|
||||
if (verify_message.endsWith(" VERIFIED")) {
|
||||
return QString("%1 0 0.0 %2 ~ %3 verified").arg(rx_time.toString("hhmmss")).arg(hz).arg(callsign);
|
||||
} else
|
||||
if (verify_message.endsWith(" INVALID"))
|
||||
{
|
||||
return QString("%1 0 0.0 %2 ~ %3 invalid").arg(rx_time.toString("hhmmss")).arg(hz).arg(callsign);
|
||||
}
|
||||
else
|
||||
return QString{};
|
||||
}
|
||||
|
||||
QString FoxVerifier::default_url() {
|
||||
return QString(FOXVERIFIER_DEFAULT_BASE_URL);
|
||||
}
|
63
Network/FoxVerifier.hpp
Normal file
63
Network/FoxVerifier.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
#ifndef WSJTX2_FOXVERIFIER_HPP
|
||||
#define WSJTX2_FOXVERIFIER_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QPointer>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QMutex>
|
||||
|
||||
#define FOXVERIFIER_DEFAULT_TIMEOUT_MSEC 5000
|
||||
#define FOXVERIFIER_DEFAULT_BASE_URL "https://www.9dx.cc"
|
||||
|
||||
class FoxVerifier : public QObject {
|
||||
Q_OBJECT
|
||||
QMutex mutex_;
|
||||
|
||||
public:
|
||||
explicit FoxVerifier(QString user_agent, QNetworkAccessManager *manager, QString base_url, QString callsign, QDateTime timestamp, QString code, unsigned int);
|
||||
~FoxVerifier();
|
||||
|
||||
QString return_value;
|
||||
bool finished();
|
||||
static QString formatDecodeMessage(QDateTime ts, QString callsign, unsigned int hz, QString const& verify_message);
|
||||
static QString default_url();
|
||||
|
||||
private:
|
||||
QNetworkAccessManager* manager_;
|
||||
QNetworkReply* reply_;
|
||||
QNetworkRequest request_;
|
||||
QUrl q_url_;
|
||||
bool finished_;
|
||||
bool errored_;
|
||||
unsigned int hz_;
|
||||
QString error_reason_;
|
||||
QDateTime ts_;
|
||||
QString callsign_;
|
||||
QString code_;
|
||||
|
||||
private slots:
|
||||
void httpFinished();
|
||||
void httpRedirected(const QUrl &url);
|
||||
void httpEncrypted();
|
||||
#ifndef QT_NO_SSL
|
||||
void sslErrors(const QList<QSslError> &);
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
void errorOccurred(QNetworkReply::NetworkError code);
|
||||
#endif
|
||||
//signals:
|
||||
//void results(QString verify_response);
|
||||
//void error(QString const& reason) const;
|
||||
|
||||
public slots:
|
||||
signals:
|
||||
void verifyComplete(int status, QDateTime ts, QString callsign, QString code, unsigned int hz, QString const& response);
|
||||
void verifyError(int status, QDateTime ts, QString callsign, QString code, unsigned int hz, QString const& response);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //WSJTX2_FOXVERIFIER_HPP
|
@ -392,7 +392,22 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case NetworkMessage::AnnotationInfo: {
|
||||
QByteArray dx_call;
|
||||
bool sort_order_provided{false};
|
||||
quint32 sort_order{std::numeric_limits<quint32>::max()};
|
||||
in >> dx_call >> sort_order_provided >> sort_order;
|
||||
TRACE_UDP ("External Callsign Info:" << dx_call << "sort_order_provided:" << sort_order_provided
|
||||
<< "sort_order:" << sort_order);
|
||||
if (sort_order > 50000) sort_order = 50000;
|
||||
if (check_status(in) != Fail) {
|
||||
Q_EMIT
|
||||
self_->annotation_info(QString::fromUtf8(dx_call), sort_order_provided, sort_order);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore
|
||||
//
|
||||
// Note that although server heartbeat messages are not
|
||||
|
@ -123,7 +123,10 @@ public:
|
||||
, bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call
|
||||
, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
// this signal is emitted when network errors occur or if a host
|
||||
// this signal is emitted if the server has sent information about a callsign
|
||||
Q_SIGNAL void annotation_info (QString const& dx_call, bool sort_order_provided, quint32 sort_order);
|
||||
|
||||
// this signal is emitted when network errors occur or if a host
|
||||
// lookup fails
|
||||
Q_SIGNAL void error (QString const&) const;
|
||||
|
||||
|
21
Network/Network.pri
Normal file
21
Network/Network.pri
Normal file
@ -0,0 +1,21 @@
|
||||
SOURCES += \
|
||||
Network/FileDownload.cpp \
|
||||
Network/FoxVerifier.cpp \
|
||||
Network/LotWUsers.cpp \
|
||||
Network/MessageClient.cpp \
|
||||
Network/NetworkAccessManager.cpp \
|
||||
Network/NetworkMessage.cpp \
|
||||
Network/NetworkServerLookup.cpp \
|
||||
Network/PSKReporter.cpp \
|
||||
Network/wsprnet.cpp
|
||||
|
||||
HEADERS += \
|
||||
Network/FileDownload.hpp \
|
||||
Network/FoxVerifier.hpp \
|
||||
Network/LotWUsers.hpp \
|
||||
Network/MessageClient.hpp \
|
||||
Network/NetworkAccessManager.hpp \
|
||||
Network/NetworkMessage.hpp \
|
||||
Network/NetworkServerLookup.hpp \
|
||||
Network/PSKReporter.hpp \
|
||||
Network/wsprnet.h
|
@ -462,6 +462,14 @@
|
||||
* decoding may be impacted. A rough rule of thumb might be too
|
||||
* limit the number of active highlighting requests to no more
|
||||
* than 100.
|
||||
*
|
||||
* Using a callsign of "CLEARALL!" and anything for the
|
||||
* color values will clear the internal highlighting data. It will
|
||||
* NOT remove the highlighting on the screen, however. The exclamation
|
||||
* symbol is used to avoid accidental clearing of all highlighting
|
||||
* data via a decoded callsign, since an exclamation symbol is not
|
||||
* a valid character in a callsign.
|
||||
|
||||
*
|
||||
* The "Highlight last" field allows the sender to request that
|
||||
* all instances of "Callsign" in the last period only, instead
|
||||
@ -494,7 +502,33 @@
|
||||
* fields an empty value implies no change, for the quint32 Rx DF
|
||||
* and Frequency Tolerance fields the maximum quint32 value
|
||||
* implies no change. Invalid or unrecognized values will be
|
||||
* silently ignored.
|
||||
* silently ignored. NOTE that if a mode/submode change occurs and
|
||||
* the current frequency is NOT in the frequency table for that
|
||||
* mode, a frequency change (to the default frequency for that band
|
||||
* and mode) may occur.
|
||||
*
|
||||
* AnnotationInfo In 16 quint32
|
||||
* Id (unique key) utf8
|
||||
* DX Call utf8
|
||||
* Sort Order Provided bool
|
||||
* Sort Order quint32
|
||||
*
|
||||
* The server may send this message at any time. Sort orders can be used
|
||||
* for sorting hound callers when in Fox mode. A typical usage is to
|
||||
* "score" callsigns based on number of bands and/or modes worked using
|
||||
* an external logging program during a DXpedition, to be able to give
|
||||
* preference to calls that have not been worked before on any other
|
||||
* band or mode. An external program can watch decodes from wsjt-x,
|
||||
* then use this message to annotate the calls with a sort order. The
|
||||
* hound queue can be displayed by that sort order. *
|
||||
*
|
||||
* If 'sort order provided' is true, the message also specifies a numeric
|
||||
* sort order for the DX call.
|
||||
*
|
||||
* Invalid or unrecognized values will be silently ignored. A sort-order of
|
||||
* ffffffff will remove the sort-order value from the internal table.
|
||||
* Callsigns without a sort order will be valued at zero for sorting purposes
|
||||
* in the hound display.
|
||||
*/
|
||||
|
||||
#include <QDataStream>
|
||||
@ -526,6 +560,7 @@ namespace NetworkMessage
|
||||
HighlightCallsign,
|
||||
SwitchConfiguration,
|
||||
Configure,
|
||||
AnnotationInfo,
|
||||
maximum_message_type_ // ONLY add new message types
|
||||
// immediately before here
|
||||
};
|
||||
|
@ -11,6 +11,251 @@
|
||||
|
||||
Copyright 2001 - 2024 by Joe Taylor, K1JT, and the WSJT Development Team
|
||||
|
||||
|
||||
Release: WSJT-X 2.7.0-rc7
|
||||
September 30, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 7 brings significant improvements for
|
||||
the new SuperFox mode. It introduces a new verification system which
|
||||
replaces the previous one, and works for both the SuperFox mode and
|
||||
for old-style Fox and Hound operation. All code for SuperFox
|
||||
operation is now open source.
|
||||
|
||||
IMPORTANT: OpenSSL v1.1.1 or higher is required for the real-time
|
||||
verification of Fox and SuperFox messages.
|
||||
|
||||
Enhancements to the SuperFox decoder:
|
||||
|
||||
- Performance of the SuperFox decoder has been further improved.
|
||||
|
||||
- You can now set individual FTol values and tune the decoder to
|
||||
the exact sync frequency of the SuperFox signal if it is not exactly
|
||||
750 Hz. Both result in a better decodability in certain situations.
|
||||
|
||||
- Important: The Rx frequency must be set close to the sync frequency
|
||||
+/- FTol, for example 750 +/- 50 Hz.
|
||||
|
||||
Introduction of a new Fox verification system:
|
||||
|
||||
- The new Fox verification system uses one time passwords (OTPs), and
|
||||
works for the SuperFox mode as well as for old-style Fox and Hound
|
||||
operation. It can be enabled by the new OTP checkbox on the Advanced
|
||||
tab of the Settings dialog.
|
||||
|
||||
- Fox or SuperFox stations send individual OTPs via radio. Hounds
|
||||
automatically check the validity of the received OTPs in real time
|
||||
from a server when there is an internet connection. Otherwise, the
|
||||
validity can also be queried manually later. OTP verifications can
|
||||
only be retrieved once the transmission has already taken place.
|
||||
|
||||
- You may optionally display the received OTP values by checking
|
||||
the box "Show OTP messages".
|
||||
|
||||
- If the Fox or SuperFox callsign is verified by receipt of the
|
||||
correct OTP, the background color of the Hound or Super Hound label
|
||||
switches to green.
|
||||
|
||||
- Theoretically, DXpeditions can set up their own OTP server, however,
|
||||
we recommend using the server at https://www.9dx.cc.
|
||||
|
||||
- Use of the new Fox verification system requires an OTP key. The
|
||||
system uses open source code and standard encryption
|
||||
technology. For testing purposes, non-verified SuperFox
|
||||
transmissions are now possible without a key.
|
||||
|
||||
Improvements to SuperFox/Hound operation:
|
||||
|
||||
- SuperHounds must now first decode the SuperFox before they can
|
||||
call, and a QSO must be started by double-clicking on a SuperFox
|
||||
decode. (Note that calling the Fox blindly not only leads to
|
||||
unnecessary band utilization, but can also significantly reduce the
|
||||
QSO rate due to unanswered (Super)Fox replies.)
|
||||
|
||||
- Switching to SuperHound mode automatically sets the Rx frequency to
|
||||
750 Hz. The previously selected frequency is saved and restored
|
||||
afterwards.
|
||||
|
||||
- Right-clicking on the H button now activates/deactivates SuperFox mode.
|
||||
|
||||
- A flaw resulting in sub-optimal SuperFox QSO rates has been
|
||||
corrected.
|
||||
|
||||
- SuperFox decoder now does a more thorough job of rejecting QRM from
|
||||
non-SuperFox signals.
|
||||
|
||||
- Fields in the SuperFox payload not otherwise used in a particular
|
||||
transmission are now set to known nonzero values. Do NOT use RC6 or
|
||||
earlier versions to decode SuperFox transmissions from RC7 or
|
||||
later.
|
||||
|
||||
- Old-style Fox stations can now transmit free text messages (up to
|
||||
13 characters) by using an available stream.
|
||||
|
||||
- Some enhancements useful for Fox operators: Active Station Window now
|
||||
shows band activity. Hound callsigns can be highlighted via UDP API, and
|
||||
assigned a score for sorting via UDP API. Fox Tx frequency is preserved
|
||||
when switching in/out of Fox mode.
|
||||
|
||||
- UDP Status Update messages now include information on how many callsigns
|
||||
have highlighting applied, and how many callsigns have a score assigned.
|
||||
|
||||
Other enhancements and fixes:
|
||||
|
||||
- In FT8 mode, the Settings dialog no longer resets the VFO frequency
|
||||
to band/mode default unless really needed.
|
||||
|
||||
- Several code improvements specifically for macOS.
|
||||
|
||||
- Updated CTY.DAT and Hamlib.
|
||||
|
||||
|
||||
Release: WSJT-X 2.7.0-rc6
|
||||
July 19, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 6 is a bug-fix release primarily
|
||||
affecting the new SuperFox mode. The following bugs have been fixed:
|
||||
|
||||
- Strong signals from Superfox too frequently failed to decode.
|
||||
|
||||
- SuperFox sometimes sent incorrect signal reports and an invalid
|
||||
digital signature.
|
||||
|
||||
- A Fortran bounds error could sometimes occur in the SuperFox
|
||||
decoder.
|
||||
|
||||
- For SuperFox operator, the "age" displayed for Hound callers
|
||||
became garbled after the 0000 UTC date change.
|
||||
|
||||
- Decodes of SuperFox transmissions were not posted to PSK Reporter.
|
||||
|
||||
- Some SuperFox-related messages were posted incorrectly to ALL.TXT.
|
||||
|
||||
- Logic for turning the SuperHound label green was flawed in some
|
||||
circumstances.
|
||||
|
||||
Release Candidate 6 also includes updates to Hamlib and the Chinese
|
||||
user interface translation.
|
||||
|
||||
Release: WSJT-X 2.7.0-rc5
|
||||
July 1, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 5 introduces "SuperFox" mode, a
|
||||
powerful new tool designed to help DXpeditions make digital QSOs at
|
||||
very high rates. RC5 also brings several other improvements and bug
|
||||
fixes.
|
||||
|
||||
SuperFox mode:
|
||||
|
||||
- The SuperFox mode behaves operationally like the present Fox and
|
||||
Hounds mode but uses a constant envelope waveform for Fox's
|
||||
transmissions rather than sending concurrent streams of up to five
|
||||
normal FT8 signals. This approach means that up to 9 messages can
|
||||
be transmitted simultaneously with no signal-strength penalty,
|
||||
resulting in a system gain of about +10 dB compared to the
|
||||
conventional Fox/Hound operation with 5 slots.
|
||||
|
||||
- IMPORTANT: Older revisions of WSJT-X and derivative programs will
|
||||
not be able to decode SuperFox transmissions. Hounds must use
|
||||
WSJT-X 2.7.0-rc5 (or a later release, when available) to receive
|
||||
SuperFox messages.
|
||||
|
||||
- Hounds chasing the DX station will transmit normal FT8 signals, as
|
||||
in the old-style Fox and Hound mode. QSOs will be logged as FT8
|
||||
mode.
|
||||
|
||||
- When using SuperFox mode, Hound stations may call at any frequency
|
||||
in Fox's received passband, including the range 0 - 1000 Hz.
|
||||
Hounds do not QSY to a lower frequency for their final
|
||||
transmission.
|
||||
|
||||
- SuperFox Operation requires the Fox operator to use a valid digital
|
||||
key. Keys will be issued in advance to legitimate DXpeditions by
|
||||
the Northern California DX Foundation, and will be kept secret.
|
||||
|
||||
- Every SuperFox transmission includes a unique digital signature.
|
||||
Hounds receiving a SuperFox message will see a "<callsign> verified"
|
||||
flag if the transmitted signature is valid, and the on-screen
|
||||
"Super Hound" label will turn from red to green.
|
||||
|
||||
- Hound operation should begin by selecting "Special operating
|
||||
activity", "Hound", and "SuperFox mode" on the Settings -> Advanced
|
||||
tab. Alternatively, right-clicking on the FT8 button toggles
|
||||
SuperFox mode on/off for either Fox or Hound, allowing quick
|
||||
transitions between SuperFox and old-style Fox and Hound operation.
|
||||
|
||||
- SuperFox stations can send free text messages of up to 26 characters
|
||||
together with messages to as many as 4 Hounds.
|
||||
|
||||
Other enhancements:
|
||||
|
||||
- Corrected a flaw that caused "Log automatically" to not work for
|
||||
the ARRL Digi Contest.
|
||||
|
||||
- Control elements for special operating activities are now disabled
|
||||
(grayed out) if the respective function is not applicable.
|
||||
|
||||
- Corrected a longstanding flaw that caused "Start new period
|
||||
decodes at top" to stop working properly after some time.
|
||||
|
||||
- Right-click mouse press events are now less error-prone.
|
||||
|
||||
- Improved the readability of the first line when "Start new period
|
||||
decodes at top" is checked.
|
||||
|
||||
- 4-digit grids are now logged for certain contest modes to ensure that
|
||||
the log complies with contest rules.
|
||||
|
||||
- The Fox Tx frequency is now saved and restored separately.
|
||||
|
||||
|
||||
Release: WSJT-X 2.7.0-rc4
|
||||
March 11, 2024
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.7.0 Release Candidate 4 brings some improvements for Fox-mode
|
||||
operators, new features for companion program QMAP, and a number of
|
||||
relatively minor enhancements and bug fixes.
|
||||
|
||||
QMAP enhancements -- of particular interest to EME operators:
|
||||
|
||||
- QMAP now decodes Q65 submodes with both 60-second and 30-second T/R
|
||||
sequence lengths. Clicking on a resulting line in the WSJT-X Active
|
||||
Stations window automatically sets dial frequency and working
|
||||
submode as needed to call that station.
|
||||
|
||||
- QMAP operates in 60-second receive sequences, and its Q65 decoder
|
||||
starts at t=19.5, 30.0, 49.5, and 58.5 s into the sequence. Most
|
||||
decoded messages are displayed well before the end of the relevant
|
||||
time slot.
|
||||
|
||||
- A new, more compact file format is now used for wideband data
|
||||
files. A "Save decoded" option has been added to the Save menu.
|
||||
|
||||
- An option has been added to allow exporting a 3 kHz portion of a
|
||||
wideband data file as a standard WSJT-X *.wav file.
|
||||
|
||||
- CTRL+click on QMAP's upper waterfall sends an integer kHz dial
|
||||
frequency request to WSJT-X.
|
||||
|
||||
- With focus on the WSJT-X main window, hit Alt+A on the keyboard to
|
||||
clear the Active Stations window.
|
||||
|
||||
- Many minor enhancements to the User Interface.
|
||||
|
||||
WSJT-X:
|
||||
|
||||
- Enable decoding of MSK144 from the jt9[.exe] executable.
|
||||
|
||||
- Several changes to reduce problems experienced when (contrary to
|
||||
our recommendations) messages with short (10-bit) callsign hashes
|
||||
are used in standard FT4/FT8 sub-bands.
|
||||
|
||||
- Enhancements useful for Fox operators.
|
||||
|
||||
|
||||
Release: WSJT-X 2.7.0-rc3
|
||||
January 1, 2024
|
||||
-------------------------
|
||||
|
@ -619,6 +619,12 @@ int HamlibTransceiver::do_start ()
|
||||
CAT_TRACE ("starting: " << rig_get_caps_cptr (m_->model_, RIG_CAPS_MFG_NAME_CPTR)
|
||||
<< ": " << rig_get_caps_cptr (m_->model_, RIG_CAPS_MODEL_NAME_CPTR));
|
||||
|
||||
token_t token = rig_token_lookup (m_->rig_.data (), "client");
|
||||
if (RIG_CONF_END != token) // only set if valid for rig model
|
||||
{
|
||||
rig_set_conf (m_->rig_.data (), token, "WSJTX");
|
||||
}
|
||||
|
||||
m_->error_check (rig_open (m_->rig_.data ()), tr ("opening connection to rig"));
|
||||
|
||||
// reset dynamic state
|
||||
|
@ -64,6 +64,9 @@ typedef struct dec_data {
|
||||
char mygrid[6];
|
||||
char hiscall[12];
|
||||
char hisgrid[6];
|
||||
bool b_even_seq;
|
||||
bool b_superfox;
|
||||
int yymmdd;
|
||||
} params;
|
||||
} dec_data_t;
|
||||
|
||||
@ -91,6 +94,9 @@ extern struct {
|
||||
int i3bit[5];
|
||||
char cmsg[5][40];
|
||||
char mycall[12];
|
||||
char textMsg[26];
|
||||
bool bMoreCQs;
|
||||
bool bSendMsg;
|
||||
} foxcom_;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -21,6 +21,7 @@ FT8 11101000010011100001000010011000100000
|
||||
FT8/VHF 11101000010011100001000010011000100000
|
||||
FT8/Fox 11101000010011100001000000000010000000
|
||||
FT8/Hound 11101000010011100001000000000011000000
|
||||
FT8/SupHou 11111000010011100001000000000011000000
|
||||
-------------------------------------------------
|
||||
1 2 3
|
||||
01234567890123456789012345678901234567
|
||||
|
@ -29,8 +29,8 @@ the following copyright notice prominently:
|
||||
*The algorithms, source code, look-and-feel of _{prog}_ and related
|
||||
programs, and protocol specifications for the modes FSK441, FST4,
|
||||
FST4W, FT4, FT8, JT4, JT6M, JT9, JT44, JT65, JTMS, Q65, QRA64, ISCAT,
|
||||
and MSK144 are Copyright (C) 2001-2021 by one or more of the following
|
||||
and MSK144 are Copyright (C) 2001-2024 by one or more of the following
|
||||
authors: Joseph Taylor, K1JT; Bill Somerville, G4WJS; Steven Franke,
|
||||
K9AN; Nico Palermo, IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB;
|
||||
Edson Pereira, PY2SDR; Philip Karn, KA9Q; and other members of the
|
||||
WSJT Development Group.*
|
||||
K9AN; Nico Palermo, IV3NWV; Uwe Risse, DG2YCB; Brian Moran, N9ADG;
|
||||
Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; Philip
|
||||
Karn, KA9Q; and other members of the WSJT Development Group.*
|
||||
|
@ -94,8 +94,8 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes.
|
||||
:sourceforge-jtsdk: https://sourceforge.net/projects/jtsdk[SourceForge JTSDK]
|
||||
:ubuntu_sdk: https://launchpad.net/~ubuntu-sdk-team/+archive/ppa[Ubuntu SDK Notice]
|
||||
:win_openssl_packages: https://slproweb.com/products/Win32OpenSSL.html[Windows OpenSSL Packages]
|
||||
:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_1_1s.msi[Win32 OpenSSL Light Package]
|
||||
:win64_openssl: https://slproweb.com/download/Win64OpenSSL_Light-1_1_1s.msi[Win64 OpenSSL Light Package]
|
||||
:win32_openssl: https://sourceforge.net/projects/wsjt-x-improved/files/Additional%20Files/OpenSSL/Win32OpenSSL_Light-1_1_1a.msi/download[Win32 OpenSSL Light Package]
|
||||
:win64_openssl: https://sourceforge.net/projects/wsjt-x-improved/files/Additional%20Files/OpenSSL/Win64OpenSSL_Light-1_1_1a.msi[Win64 OpenSSL Light Package]
|
||||
:writelog: https://writelog.com/[Writelog]
|
||||
:wsjtx_group: https://groups.io/g/wsjtgroup[WSJT GROUP User Forum]
|
||||
:wsjtx_group2: https://groups.io/g/wsjtgroup/join[join the group]
|
||||
|
@ -4,8 +4,10 @@ Download and execute the package file {win32} (Windows 7 or later,
|
||||
32-bit) or {win64} (Windows 7 or later, 64-bit) following these
|
||||
instructions:
|
||||
|
||||
* Install _WSJT-X_ into its own directory, for example `C:\WSJTX` or `C:\WSJT\WSJTX`, rather than the conventional location `C:\Program
|
||||
Files ...\WSJTX`.
|
||||
* Install _WSJT-X_ into its own directory, for example
|
||||
`C:\WSJTX` or `C:\WSJT\WSJTX`, rather than the conventional location
|
||||
`C:\Program Files ...\WSJTX`. Do not use a directory path that
|
||||
includes an embedded blank.
|
||||
|
||||
* All program files relating to _WSJT-X_ are stored in the chosen
|
||||
installation directory and its subdirectories.
|
||||
|
@ -1,11 +1,12 @@
|
||||
[[NEW_FEATURES]]
|
||||
=== New in Version {VERSION_MAJOR}.{VERSION_MINOR}
|
||||
|
||||
_WSJT-X 2.7_ introduces a new program called *QMAP*, a new Special
|
||||
Operating Activity *Q65 Pileup*, an option to *Update Hamlib* at the
|
||||
click of a button, and a number of other enhancements and bug fixes.
|
||||
_WSJT-X 2.7_ introduces a new program called *QMAP*, new Special
|
||||
Operating Activities *Q65 Pileup* and *SuperFox mode*, an option to
|
||||
*Update Hamlib* at the click of a button, and a number of other
|
||||
enhancements and bug fixes.
|
||||
|
||||
- QMAP and Q65 Pileup mode are of particular interest to those engaged
|
||||
- *QMAP* and *Q65 Pileup* mode are of particular interest to those engaged
|
||||
in Earth-Moon-Earth (EME) communication, but other applications may
|
||||
be found for them as well. QMAP is currently available for Windows
|
||||
only; it is derived from MAP65, an older program used since 2007 for
|
||||
@ -19,6 +20,15 @@ click of a button, and a number of other enhancements and bug fixes.
|
||||
Quick-Start guide posted here:
|
||||
https://wsjt.sourceforge.io/Quick_Start_WSJT-X_2.7_QMAP.pdf
|
||||
|
||||
- *SuperFox mode* behaves operationally like the old-style Fox and
|
||||
Hounds mode but uses a new constant envelope waveform for Fox's
|
||||
transmissions. Messages can be transmitted simultaneously to as many
|
||||
as 9 Hounds with no signal-strength penalty, resulting in a system
|
||||
gain of about +10 dB compared to the older Fox-and-Hound operation
|
||||
with 5 slots. Further details on SuperFox mode can be found in the
|
||||
Quick-Start guide posted here:
|
||||
https://wsjt.sourceforge.io/SuperFox_User_Guide.pdf
|
||||
|
||||
- A button *Update Hamlib* now appears on the *Settings -> Radio* tab.
|
||||
On Windows it allows the user to automatically download and install
|
||||
the latest version of the rig-control features in Hamlib. The
|
||||
|
@ -330,7 +330,7 @@ comparable to tone spacing.
|
||||
[width="100%",cols="h,5*^",frame=topbot,options="header"]
|
||||
|===
|
||||
|T/R Period (s) |A Spacing Width (Hz)|B Spacing Width (Hz)|C Spacing Width (Hz)|D Spacing Width (Hz)|E Spacing Width (Hz)
|
||||
|15|6.67     4.33|13.33     867|26.67     1733|N/A|N/A
|
||||
|15|6.67     433|13.33     867|26.67     1733|N/A|N/A
|
||||
|30|3.33     217|6.67     433|13.33     867| 26.67     1733| N/A
|
||||
|60|1.67     108|3.33     217|6.67     433|13.33     867|26.67     1733
|
||||
|120|0.75     49|1.50     98|3.00     195|6.00     390| 12.00     780
|
||||
|
235
lib/cwsim.f90
Normal file
235
lib/cwsim.f90
Normal file
@ -0,0 +1,235 @@
|
||||
program cwsim
|
||||
|
||||
! Generate simulated audio for a CW message sent repeatedly for 60 seconds
|
||||
|
||||
use wavhdr
|
||||
parameter (NMAX=60*12000)
|
||||
type(hdr) h !Header for the .wav file
|
||||
integer*2 iwave(NMAX) !Generated waveform (no noise)
|
||||
integer icw(500) !Encoded CW message bits
|
||||
complex cspread(0:NMAX-1) !Complex amplitude for Rayleigh fading
|
||||
complex cdat(0:NMAX-1) !Complex waveform
|
||||
real dat(NMAX) !Audio waveform
|
||||
real*4 xnoise(NMAX) !Generated random noise
|
||||
character*60 message
|
||||
character*12 arg
|
||||
|
||||
nargs=iargc()
|
||||
if(nargs.ne.6) then
|
||||
print*,'Usage: cwsim "message" freq bw wpm fspread snr'
|
||||
print*,'Example: cwsim "CQ CQ CQ DE K1JT K1JT K1JT" 700 100 20 100 -10'
|
||||
go to 999
|
||||
endif
|
||||
|
||||
call getarg(1,message)
|
||||
call getarg(2,arg)
|
||||
read(arg,*) ifreq !Audio frequency (Hz)
|
||||
call getarg(3,arg)
|
||||
read(arg,*) bw !Bandwidth (Hz)
|
||||
call getarg(4,arg)
|
||||
read(arg,*) wpm !CW speed, words per minute
|
||||
call getarg(5,arg)
|
||||
read(arg,*) fspread !Doppler spread in Hz
|
||||
call getarg(6,arg)
|
||||
read(arg,*) snrdb !S/N in dB (2500 hz reference BW)
|
||||
|
||||
rms=500.0
|
||||
bandwidth_ratio=2500.0/6000.0
|
||||
sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb)
|
||||
twopi=8.0*atan(1.0)
|
||||
|
||||
h=default_header(12000,NMAX)
|
||||
open(10,file='000000_0000.wav',access='stream',status='unknown')
|
||||
do i=1,NMAX !Generate gaussian noise
|
||||
xnoise(i)=gran()
|
||||
enddo
|
||||
|
||||
itone=0
|
||||
call morse(message,icw,ncw)
|
||||
call cwsig(icw,ncw,ifreq,wpm,sig,cdat)
|
||||
nfft=NMAX
|
||||
|
||||
if(fspread.ne.0) then !Apply specified Doppler spread
|
||||
nh=nfft/2
|
||||
df=12000.0/nfft
|
||||
cspread(0)=1.0
|
||||
cspread(nh)=0.
|
||||
b=6.0 !Use truncated Lorenzian shape for fspread
|
||||
do i=1,nh
|
||||
f=i*df
|
||||
x=b*f/fspread
|
||||
z=0.
|
||||
a=0.
|
||||
if(x.lt.3.0) then !Cutoff beyond x=3
|
||||
a=sqrt(1.111/(1.0+x*x)-0.1) !Lorentzian amplitude
|
||||
phi1=twopi*rran() !Random phase
|
||||
z=a*cmplx(cos(phi1),sin(phi1))
|
||||
endif
|
||||
cspread(i)=z
|
||||
z=0.
|
||||
if(x.lt.3.0) then !Same thing for negative freqs
|
||||
phi2=twopi*rran()
|
||||
z=a*cmplx(cos(phi2),sin(phi2))
|
||||
endif
|
||||
cspread(nfft-i)=z
|
||||
enddo
|
||||
|
||||
call four2a(cspread,nfft,1,1,1) !Transform to time domain
|
||||
sum=0.
|
||||
do i=0,nfft-1
|
||||
p=real(cspread(i))**2 + aimag(cspread(i))**2
|
||||
sum=sum+p
|
||||
enddo
|
||||
avep=sum/nfft
|
||||
fac=sqrt(1.0/avep)
|
||||
cspread=fac*cspread !Normalize to constant avg power
|
||||
cdat=cspread*cdat !Apply Rayleigh fading
|
||||
endif
|
||||
|
||||
dat=aimag(cdat) + xnoise
|
||||
|
||||
cdat=dat
|
||||
call four2a(cdat,nfft,1,-1,1) !c2c to frequency domain
|
||||
ia=max(250/df,(ifreq-0.5*bw)/df)
|
||||
ib=ia+bw/df
|
||||
cdat(0:ia)=0.
|
||||
cdat(ib:)=0.
|
||||
call four2a(cdat,nfft,1,+1,1) !c2c to time domain
|
||||
fac=sqrt(5000/bw)/nfft
|
||||
dat=fac*real(cdat)
|
||||
|
||||
iwave=nint(rms*dat)
|
||||
write(10) h,iwave
|
||||
close(10)
|
||||
|
||||
999 end program cwsim
|
||||
|
||||
subroutine cwsig(icw,ncw,ifreq,wpm,sig,cdat)
|
||||
|
||||
parameter(NMAX=60*12000)
|
||||
integer icw(ncw)
|
||||
complex cdat(NMAX)
|
||||
complex z(NMAX)
|
||||
real x(NMAX)
|
||||
real y(NMAX)
|
||||
real*8 dt,twopi,phi,dphi,fsample,tdit,t
|
||||
|
||||
nspd=nint(1.2*12000.0/wpm)
|
||||
fsample=12000.d0 !Sample rate (Hz)
|
||||
dt=1.d0/fsample !Sample interval (s)
|
||||
tdit=nspd*dt
|
||||
twopi=8.d0*atan(1.d0)
|
||||
dphi=twopi*ifreq*dt
|
||||
phi=0.
|
||||
k=12000 !Start audio at t = 1.0 s
|
||||
t=0.
|
||||
npts=59*12000
|
||||
x=0.
|
||||
do i=1,npts
|
||||
t=t+dt
|
||||
j=nint(t/tdit) + 1
|
||||
j=mod(j-1,ncw) + 1
|
||||
phi=phi + dphi
|
||||
if(phi.gt.twopi) phi=phi-twopi
|
||||
xphi=phi
|
||||
k=k+1
|
||||
x(k)=icw(j)
|
||||
z(k)=cmplx(cos(xphi),sin(xphi))
|
||||
if(t.ge.59.5) exit
|
||||
enddo
|
||||
|
||||
nadd=0.004/dt
|
||||
call smo(x,npts,y,nadd)
|
||||
y=y/nadd
|
||||
cdat=sig*y*z
|
||||
|
||||
return
|
||||
end subroutine cwsig
|
||||
|
||||
subroutine morse(msg,idat,n)
|
||||
|
||||
! Convert ascii message to a Morse code bit string.
|
||||
! Dash = 3 dots
|
||||
! Space between dots, dashes = 1 dot
|
||||
! Space between letters = 3 dots
|
||||
! Space between words = 7 dots
|
||||
|
||||
character*(*) msg
|
||||
integer idat(500)
|
||||
integer*1 ic(21,38)
|
||||
data ic/ &
|
||||
1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,20, &
|
||||
1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,18, &
|
||||
1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,16, &
|
||||
1,0,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,14, &
|
||||
1,0,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,12, &
|
||||
1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,1,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,12, &
|
||||
1,1,1,0,1,1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,14, &
|
||||
1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,0,0,0,0,16, &
|
||||
1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,0,0,18, &
|
||||
1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 6, &
|
||||
1,1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,12, &
|
||||
1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
|
||||
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2, &
|
||||
1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
|
||||
1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4, &
|
||||
1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,14, &
|
||||
1,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
|
||||
1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 6, &
|
||||
1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,12, &
|
||||
1,0,1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,12, &
|
||||
1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0,14, &
|
||||
1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
|
||||
1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 6, &
|
||||
1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4, &
|
||||
1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
|
||||
1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,10, &
|
||||
1,1,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,12, &
|
||||
1,1,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,14, &
|
||||
1,1,1,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,12, &
|
||||
1,1,1,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,14, &
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2/ !Incremental word space
|
||||
save
|
||||
|
||||
msglen=len(trim(msg))
|
||||
idat=0
|
||||
n=6
|
||||
do k=1,msglen
|
||||
jj=ichar(msg(k:k))
|
||||
if(jj.ge.97 .and. jj.le.122) jj=jj-32 !Convert lower to upper case
|
||||
if(jj.ge.48 .and. jj.le.57) j=jj-48 !Numbers
|
||||
if(jj.ge.65 .and. jj.le.90) j=jj-55 !Letters
|
||||
if(jj.eq.47) j=36 !Slash (/)
|
||||
if(jj.eq.32) j=37 !Word space
|
||||
j=j+1
|
||||
|
||||
! Insert this character
|
||||
nmax=ic(21,j)
|
||||
if (n + nmax + 4 .gt. size (idat)) exit
|
||||
do i=1,nmax
|
||||
n=n+1
|
||||
idat(n)=ic(i,j)
|
||||
enddo
|
||||
|
||||
! Insert character space of 2 dit lengths:
|
||||
n=n+1
|
||||
idat(n)=0
|
||||
n=n+1
|
||||
idat(n)=0
|
||||
enddo
|
||||
|
||||
! Insert word space at end of message
|
||||
do j=1,4
|
||||
n=n+1
|
||||
idat(n)=0
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine morse
|
@ -67,7 +67,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
|
||||
ntr0=params%ntr
|
||||
rms=sqrt(dot_product(float(id2(1:180000)), &
|
||||
float(id2(1:180000)))/180000.0)
|
||||
if(rms.lt.3.0) go to 800
|
||||
if(rms.lt.0.5) go to 800
|
||||
|
||||
!cast C character arrays to Fortran character strings
|
||||
datetime=transfer(params%datetime, datetime)
|
||||
@ -124,8 +124,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
|
||||
|
||||
if(params%nmode.eq.8) then
|
||||
! We're in FT8 mode
|
||||
|
||||
if(ncontest.eq.6) then
|
||||
if(ncontest.eq.6) then !Fox=6, Hound=7
|
||||
! Fox mode: initialize and open houndcallers.txt
|
||||
inquire(file=trim(temp_dir)//'/houndcallers.txt',exist=ex)
|
||||
if(.not.ex) then
|
||||
@ -140,27 +139,36 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
|
||||
open(19,file=trim(temp_dir)//'/houndcallers.txt',status='unknown')
|
||||
endif
|
||||
|
||||
call timer('decft8 ',0)
|
||||
newdat=params%newdat
|
||||
if(params%emedelay.ne.0.0) then
|
||||
id2(1:156000)=id2(24001:180000) ! Drop the first 2 seconds of data
|
||||
id2(156001:180000)=0
|
||||
endif
|
||||
call my_ft8%decode(ft8_decoded,id2,params%nQSOProgress,params%nfqso, &
|
||||
params%nftx,newdat,params%nutc,params%nfa,params%nfb, &
|
||||
params%nzhsym,params%ndepth,params%emedelay,ncontest, &
|
||||
logical(params%nagain),logical(params%lft8apon), &
|
||||
logical(params%lapcqonly),params%napwid,mycall,hiscall, &
|
||||
params%ndiskdat)
|
||||
call timer('decft8 ',1)
|
||||
if(nfox.gt.0) then
|
||||
n30min=minval(n30fox(1:nfox))
|
||||
n30max=maxval(n30fox(1:nfox))
|
||||
if(ncontest.eq.7 .and. params%b_superfox .and. params%b_even_seq) then
|
||||
if(params%nzhsym.lt.50) go to 800
|
||||
! Call the superFox decoder
|
||||
call sfrx_sub(params%yymmdd,params%nutc,params%nfqso,params%ntol,id2)
|
||||
else
|
||||
call timer('decft8 ',0)
|
||||
newdat=params%newdat
|
||||
if(params%emedelay.ne.0.0) then
|
||||
id2(1:156000)=id2(24001:180000) ! Drop the first 2 seconds of data
|
||||
id2(156001:180000)=0
|
||||
endif
|
||||
call my_ft8%decode(ft8_decoded,id2,params%nQSOProgress,params%nfqso, &
|
||||
params%nftx,newdat,params%nutc,params%nfa,params%nfb, &
|
||||
params%nzhsym,params%ndepth,params%emedelay,ncontest, &
|
||||
logical(params%nagain),logical(params%lft8apon), &
|
||||
logical(params%lapcqonly),params%napwid,mycall,hiscall, &
|
||||
params%ndiskdat)
|
||||
call timer('decft8 ',1)
|
||||
endif
|
||||
j=0
|
||||
|
||||
if(ncontest.eq.6) then
|
||||
! Fox mode: save decoded Hound calls for possible selection by FoxOp
|
||||
|
||||
n=params%nutc
|
||||
n30=(3600*(n/10000) + 60*mod((n/100),100) + mod(n,100))/30
|
||||
if(n30.lt.n30z) nwrap=nwrap+2880 !New UTC day, handle the wrap
|
||||
n30z=n30
|
||||
n30=n30+nwrap
|
||||
|
||||
rewind 19
|
||||
if(nfox.eq.0) then
|
||||
endfile 19
|
||||
@ -168,21 +176,23 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
|
||||
else
|
||||
do i=1,nfox
|
||||
n=n30fox(i)
|
||||
if(n30max-n30fox(i).le.4) then
|
||||
nage=min(99,mod(n30-n+288000,2880))
|
||||
if(nage.le.4) then
|
||||
j=j+1
|
||||
c2fox(j)=c2fox(i)
|
||||
g2fox(j)=g2fox(i)
|
||||
nsnrfox(j)=nsnrfox(i)
|
||||
nfreqfox(j)=nfreqfox(i)
|
||||
n30fox(j)=n
|
||||
m=n30max-n
|
||||
! nage=min(99,mod(n30-n+288000,2880))
|
||||
if(len(trim(g2fox(j))).eq.4) then
|
||||
call azdist(mygrid,g2fox(j)//' ',0.d0,nAz,nEl,nDmiles, &
|
||||
nDkm,nHotAz,nHotABetter)
|
||||
else
|
||||
nDkm=9999
|
||||
endif
|
||||
write(19,1004) c2fox(j),g2fox(j),nsnrfox(j),nfreqfox(j),nDkm,m
|
||||
write(19,1004) c2fox(j),g2fox(j),nsnrfox(j),nfreqfox(j), &
|
||||
nDkm,nage
|
||||
1004 format(a12,1x,a4,i5,i6,i7,i3)
|
||||
endif
|
||||
enddo
|
||||
@ -661,10 +671,10 @@ contains
|
||||
endif
|
||||
b1=i3-i2.eq.5 .and. isgrid4(g2)
|
||||
b2=i3-i2.eq.1
|
||||
if(b0 .and. (b1.or.b2) .and. nint(freq).ge.1000) then
|
||||
if(b0 .and. (b1.or.b2) .and. (nint(freq).ge.1000 .or. params%b_superfox)) then
|
||||
n=params%nutc
|
||||
n30=(3600*(n/10000) + 60*mod((n/100),100) + mod(n,100))/30
|
||||
if(n30.lt.n30z) nwrap=nwrap+5760 !New UTC day, handle the wrap
|
||||
if(n30.lt.n30z) nwrap=nwrap+2880 !New UTC day, handle the wrap
|
||||
n30z=n30
|
||||
n30=n30+nwrap
|
||||
if(nfox.lt.MAXFOX) nfox=nfox+1
|
||||
|
@ -26,8 +26,8 @@ program ft4code
|
||||
'LDPC(174,91) encoding,'
|
||||
print*,'bit and symbol ordering, and other details of the FT4 protocol.'
|
||||
print*
|
||||
print*,'Usage: ft4code [-c grid] "message" # Results for specified message'
|
||||
print*,' ft4code -t # Examples of all message types'
|
||||
print*,'Usage: ft4code "message" # Results for specified message'
|
||||
print*,' ft4code -t # Examples of all message types'
|
||||
go to 999
|
||||
endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
subroutine foxgen(bSuperFox)
|
||||
subroutine foxgen(bSuperFox,fname)
|
||||
|
||||
! Called from MainWindow::foxTxSequencer() to generate the Tx waveform in
|
||||
! FT8 Fox mode. The Tx message can contain up to 5 "slots", each carrying
|
||||
@ -17,8 +17,10 @@ subroutine foxgen(bSuperFox)
|
||||
parameter (NN=79,ND=58,NSPS=4*1920)
|
||||
parameter (NWAVE=(160+2)*134400*4) !the biggest waveform we generate (FST4-1800 at 48kHz)
|
||||
parameter (NFFT=614400,NH=NFFT/2)
|
||||
logical*1 bSuperFox
|
||||
character*40 cmsg
|
||||
logical*1 bSuperFox,bMoreCQs,bSendMsg
|
||||
character*(*) fname
|
||||
character*40 cmsg,cmsg2
|
||||
character*26 textMsg
|
||||
character*37 msg,msgsent
|
||||
integer itone(79)
|
||||
integer*1 msgbits(77),msgbits2
|
||||
@ -26,15 +28,26 @@ subroutine foxgen(bSuperFox)
|
||||
real x(NFFT)
|
||||
real*8 dt,twopi,f0,fstep,dfreq,phi,dphi
|
||||
complex cx(0:NH)
|
||||
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall(12)
|
||||
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall(12), &
|
||||
textMsg,bMoreCQs,bSendMsg
|
||||
common/foxcom2/itone2(NN),msgbits2(77)
|
||||
common/foxcom3/nslots2,cmsg2(5),itone3(151)
|
||||
equivalence (x,cx),(y,cy)
|
||||
|
||||
if(bSuperFox) then
|
||||
call foxgen2(nslots,cmsg)
|
||||
return
|
||||
n=nslots
|
||||
if(bMoreCQs) cmsg(1)(40:40)='1' !Set flag to include a CQ
|
||||
if(bSendMsg) then
|
||||
n=min(nslots+1,3)
|
||||
cmsg(n)=textMsg
|
||||
cmsg(n)(39:39)='1' !Set flag for text message
|
||||
nslots=n
|
||||
endif
|
||||
nslots2=nslots
|
||||
cmsg2=cmsg
|
||||
go to 999
|
||||
endif
|
||||
|
||||
|
||||
fstep=60.d0
|
||||
dfreq=6.25d0
|
||||
dt=1.d0/48000.d0
|
||||
@ -72,7 +85,7 @@ subroutine foxgen(bSuperFox)
|
||||
peak3=maxval(abs(wave))
|
||||
wave=wave/peak3
|
||||
|
||||
return
|
||||
999 return
|
||||
end subroutine foxgen
|
||||
|
||||
! include 'plotspec.f90'
|
||||
|
@ -2,12 +2,12 @@ subroutine foxgen_wrap(msg40,msgbits,itone)
|
||||
|
||||
parameter (NN=79,ND=58,KK=77,NSPS=4*1920)
|
||||
parameter (NWAVE=(160+2)*134400*4) !the biggest waveform we generate (FST4-1800)
|
||||
|
||||
logical*1 bMoreCQs
|
||||
character*40 msg40,cmsg
|
||||
character*12 mycall12
|
||||
integer*1 msgbits(KK),msgbits2
|
||||
integer itone(NN)
|
||||
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall12
|
||||
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall12,bMoreCQs
|
||||
common/foxcom2/itone2(NN),msgbits2(KK)
|
||||
|
||||
nslots=1
|
||||
|
@ -1,6 +1,6 @@
|
||||
module ft8_a7
|
||||
|
||||
parameter(MAXDEC=100)
|
||||
parameter(MAXDEC=200)
|
||||
|
||||
! For the following three arrays
|
||||
! First index i=decode number in this sequence
|
||||
@ -43,7 +43,7 @@ subroutine ft8_a7_save(nutc,dt,f,msg)
|
||||
! Add this decode to current table for this sequence
|
||||
ndec(j,1)=ndec(j,1)+1 !Number of decodes in this sequence
|
||||
i=ndec(j,1) !i is index of a new table entry
|
||||
if(i.ge.MAXDEC-1) return !Prevent table overflow
|
||||
if(i.gt.MAXDEC) return !Prevent table overflow (indexes start at 1)
|
||||
|
||||
dt0(i,j,1)=dt !Save dt in table
|
||||
f0(i,j,1)=f !Save f in table
|
||||
|
@ -8,10 +8,10 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
|
||||
logical newdat,first
|
||||
complex c1(0:NFFT2-1)
|
||||
complex cx(0:NFFT1/2)
|
||||
real dd(NMAX),x(NFFT1),taper(0:100)
|
||||
equivalence (x,cx)
|
||||
real dd(NMAX),x(NFFT1+2),taper(0:100)
|
||||
data first/.true./
|
||||
save cx,first,taper
|
||||
save x,cx,first,taper
|
||||
equivalence (x,cx)
|
||||
|
||||
if(first) then
|
||||
pi=4.0*atan(1.0)
|
||||
@ -23,11 +23,10 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
|
||||
if(newdat) then
|
||||
! Data in dd have changed, recompute the long FFT
|
||||
x(1:NMAX)=dd
|
||||
x(NMAX+1:NFFT1)=0. !Zero-pad the x array
|
||||
x(NMAX+1:NFFT1+2)=0. !Zero-pad the x array
|
||||
call four2a(cx,NFFT1,1,-1,0) !r2c FFT to freq domain
|
||||
newdat=.false.
|
||||
endif
|
||||
|
||||
df=12000.0/NFFT1
|
||||
baud=12000.0/NSPS
|
||||
i0=nint(f0/df)
|
||||
|
@ -23,9 +23,9 @@ program ft8code
|
||||
'LDPC(174,91) encoding,'
|
||||
print*,'bit and symbol ordering, and other details of the FT8 protocol.'
|
||||
print*
|
||||
print*,'Usage: ft8code [-c grid] "message" # Results for specified message'
|
||||
print*,' ft8code -T # Examples of all message types'
|
||||
print*,' ft8code -t # Short format examples'
|
||||
print*,'Usage: ft8code "message" # Results for specified message'
|
||||
print*,' ft8code -T # Examples of all message types'
|
||||
print*,' ft8code -t # Short format examples'
|
||||
go to 999
|
||||
endif
|
||||
|
||||
|
@ -42,7 +42,7 @@ program ft8d
|
||||
j2=index(infile,'.wav')
|
||||
read(infile(j2-6:j2-1),*) nutc
|
||||
datetime=infile(j2-13:j2-1)
|
||||
call sync8(iwave,nfa,nfb,nfqso,s,candidate,ncand)
|
||||
call sync8(iwave,NMAX,nfa,nfb,nfqso,s,candidate,ncand)
|
||||
syncmin=2.0
|
||||
dd=iwave
|
||||
do icand=1,ncand
|
||||
|
@ -101,14 +101,24 @@ program ft8sim_gfsk
|
||||
wave=imag(c)
|
||||
peak=maxval(abs(wave))
|
||||
nslots=1
|
||||
|
||||
|
||||
psig=0.
|
||||
pnoise=0.
|
||||
if(snrdb.lt.90) then
|
||||
do i=1,NMAX !Add gaussian noise at specified SNR
|
||||
xnoise=gran()
|
||||
if(i.ge.6001 .and. i.le.157692) then
|
||||
psig=psig + wave(i)*wave(i) !Signal power
|
||||
pnoise=pnoise + xnoise*xnoise !Noise power in signal interval
|
||||
endif
|
||||
wave(i)=wave(i) + xnoise
|
||||
enddo
|
||||
endif
|
||||
|
||||
! Noise power in signal interval and 2500 Hz bandwidth:
|
||||
pnoise=bandwidth_ratio*pnoise
|
||||
snr_2500=db(psig/pnoise) !SNR in 2500 Hz bandwidth
|
||||
|
||||
gain=100.0
|
||||
if(snrdb.lt.90.0) then
|
||||
wave=gain*wave
|
||||
@ -125,7 +135,7 @@ program ft8sim_gfsk
|
||||
open(10,file=fname,status='unknown',access='stream')
|
||||
write(10) h,iwave !Save to *.wav file
|
||||
close(10)
|
||||
write(*,1110) ifile,xdt,f0,snrdb,fname
|
||||
1110 format(i4,f7.2,f8.2,f7.1,2x,a17)
|
||||
write(*,1110) ifile,xdt,f0,snrdb,fname,snr_2500
|
||||
1110 format(i4,f7.2,f8.2,f7.1,2x,a17,f8.2)
|
||||
enddo
|
||||
999 end program ft8sim_gfsk
|
||||
|
@ -1,4 +1,4 @@
|
||||
subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,candidate,ncand,sbase)
|
||||
subroutine sync8(dd,npts,nfa,nfb,syncmin,nfqso,maxcand,candidate,ncand,sbase)
|
||||
|
||||
include 'ft8_params.f90'
|
||||
parameter (MAXPRECAND=1000)
|
||||
@ -9,13 +9,13 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,candidate,ncand,sbase)
|
||||
real s(NH1,NHSYM)
|
||||
real savg(NH1)
|
||||
real sbase(NH1)
|
||||
real x(NFFT1)
|
||||
real x(NFFT1+2)
|
||||
real sync2d(NH1,-JZ:JZ)
|
||||
real red(NH1)
|
||||
real red2(NH1)
|
||||
real candidate0(3,MAXPRECAND)
|
||||
real candidate(3,maxcand)
|
||||
real dd(NMAX)
|
||||
real dd(npts)
|
||||
integer jpeak(NH1)
|
||||
integer jpeak2(NH1)
|
||||
integer indx(NH1)
|
||||
|
@ -24,7 +24,7 @@ subroutine watterson(c,npts,nsig,fs,delay,fspread)
|
||||
do i=0,npts-1
|
||||
f=i*df
|
||||
if(i.gt.npts/2) f=(i-npts)*df
|
||||
x=(f/(0.5*fspread))**2
|
||||
x=(f/fspread)**2
|
||||
a=0.
|
||||
if(x.le.50.0) then
|
||||
a=exp(-x)
|
||||
|
@ -44,23 +44,23 @@ contains
|
||||
|
||||
class(ft8_decoder), intent(inout) :: this
|
||||
procedure(ft8_decode_callback) :: callback
|
||||
parameter (MAXCAND=600,MAX_EARLY=100)
|
||||
parameter (MAXCAND=600,MAX_EARLY=200,NPTS=15*12000)
|
||||
real*8 tsec,tseq
|
||||
real sbase(NH1)
|
||||
real candidate(3,MAXCAND)
|
||||
real dd(15*12000),dd1(15*12000)
|
||||
real dd(NPTS),dd1(NPTS)
|
||||
logical, intent(in) :: lft8apon,lapcqonly,nagain
|
||||
logical newdat,lsubtract,ldupe,lrefinedt
|
||||
logical*1 ldiskdat
|
||||
logical lsubtracted(MAX_EARLY)
|
||||
character*12 mycall12,hiscall12,call_1,call_2
|
||||
character*4 grid4
|
||||
integer*2 iwave(15*12000)
|
||||
integer*2 iwave(NPTS)
|
||||
integer apsym2(58),aph10(10)
|
||||
character datetime*13,msg37*37
|
||||
character*37 allmessages(200)
|
||||
character*37 allmessages(MAX_EARLY)
|
||||
character*12 ctime
|
||||
integer allsnrs(200)
|
||||
integer allsnrs(MAX_EARLY)
|
||||
integer itone(NN)
|
||||
integer itone_save(NN,MAX_EARLY)
|
||||
real f1_save(MAX_EARLY)
|
||||
@ -192,7 +192,7 @@ contains
|
||||
endif
|
||||
call timer('sync8 ',0)
|
||||
maxc=MAXCAND
|
||||
call sync8(dd,ifa,ifb,syncmin,nfqso,maxc,candidate,ncand,sbase)
|
||||
call sync8(dd,NPTS,ifa,ifb,syncmin,nfqso,maxc,candidate,ncand,sbase)
|
||||
call timer('sync8 ',1)
|
||||
do icand=1,ncand
|
||||
sync=candidate(3,icand)
|
||||
@ -215,6 +215,9 @@ contains
|
||||
if(msg37.eq.allmessages(id)) ldupe=.true.
|
||||
enddo
|
||||
if(.not.ldupe) then
|
||||
if(ndecodes.ge.MAX_EARLY) then
|
||||
cycle
|
||||
endif
|
||||
ndecodes=ndecodes+1
|
||||
allmessages(ndecodes)=msg37
|
||||
allsnrs(ndecodes)=nsnr
|
||||
|
@ -19,9 +19,10 @@ subroutine hspec(id2,k,nutc0,ntrpdepth,nrxfreq,ntol,bmsk144, &
|
||||
! jh index of most recent data in green(), s()
|
||||
|
||||
parameter (JZ=703)
|
||||
character*80 line1
|
||||
character*(*) line1
|
||||
character*80 line0
|
||||
character*(*) datadir
|
||||
character*12 mycall,hiscall
|
||||
character*(*) mycall,hiscall
|
||||
integer*2 id2(0:120*12000-1)
|
||||
logical*1 bmsk144,bshmsg,btrain,bswl
|
||||
real green(0:JZ-1)
|
||||
@ -96,7 +97,12 @@ subroutine hspec(id2,k,nutc0,ntrpdepth,nrxfreq,ntol,bmsk144, &
|
||||
tt2=sum(float(abs(id2(k0:k0+3583))))
|
||||
if(tt1.ne.0.0 .and. tt2.ne.0) then
|
||||
call mskrtd(id2(k-7168+1:k),nutc0,tsec,ntol,nrxfreq,ndepth, &
|
||||
mycall,hiscall,bshmsg,btrain,pcoeffs,bswl,datadir,line1)
|
||||
mycall,hiscall,bshmsg,btrain,pcoeffs,bswl,datadir,line0)
|
||||
if(line0(1:1).eq.char(0)) then
|
||||
line1(1:1)=char(0)
|
||||
else
|
||||
line1(1:62)=line0(1:62)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -47,6 +47,9 @@
|
||||
character(kind=c_char) :: mygrid(6)
|
||||
character(kind=c_char) :: hiscall(12)
|
||||
character(kind=c_char) :: hisgrid(6)
|
||||
logical(c_bool) :: b_even_seq
|
||||
logical(c_bool) :: b_superfox
|
||||
integer(c_int) :: yymmdd
|
||||
end type params_block
|
||||
|
||||
type, bind(C) :: dec_data
|
||||
|
@ -16,8 +16,8 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,hiscall, &
|
||||
character*4 decsym !"&" for mskspd or "^" for long averages
|
||||
character*37 msgreceived !Decoded message
|
||||
character*37 msglast,msglastswl !Used for dupechecking
|
||||
character*80 line !Formatted line with UTC dB T Freq Msg
|
||||
character*12 mycall,hiscall
|
||||
character*(*) line !Formatted line with UTC dB T Freq Msg
|
||||
character*(*) mycall,hiscall
|
||||
character*37 recent_shmsgs(NSHMEM)
|
||||
character*(*) datadir
|
||||
|
||||
@ -70,15 +70,19 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,hiscall, &
|
||||
msglastswl=' '
|
||||
nsnrlast=-99
|
||||
nsnrlastswl=-99
|
||||
mycall13=mycall//' '
|
||||
dxcall13=hiscall//' '
|
||||
! mycall13=mycall//' '
|
||||
! dxcall13=hiscall//' '
|
||||
mycall13=' '
|
||||
dxcall13=' '
|
||||
mycall13(1:12)=mycall(1:12)
|
||||
dxcall13(1:12)=hiscall(1:12)
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
fc=nrxfreq
|
||||
|
||||
! Reset if mycall or dxcall changes
|
||||
if(mycall13(1:12).ne.mycall .or. dxcall13(1:12).ne.hiscall) first=.true.
|
||||
if(mycall13(1:12).ne.mycall(1:12) .or. dxcall13(1:12).ne.hiscall(1:12)) first=.true.
|
||||
|
||||
! Dupe checking setup
|
||||
if(nutc00.ne.nutc0 .or. tsec.lt.tsec0) then ! reset dupe checker
|
||||
@ -90,7 +94,7 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,hiscall, &
|
||||
endif
|
||||
|
||||
tframe=float(NSPM)/12000.0
|
||||
line=char(0)
|
||||
line(1:1)=char(0)
|
||||
msgreceived=' '
|
||||
max_iterations=10
|
||||
niterations=0
|
||||
|
@ -222,14 +222,20 @@ program q65sim
|
||||
fac=sqrt(1.0/avep)
|
||||
cspread=fac*cspread !Normalize to constant avg power
|
||||
cdat=cspread*cdat !Apply Rayleigh fading
|
||||
|
||||
! do i=0,nfft-1
|
||||
! p=real(cspread(i))**2 + aimag(cspread(i))**2
|
||||
! write(14,3010) i,p,cspread(i)
|
||||
!3010 format(i8,3f12.6)
|
||||
! enddo
|
||||
endif
|
||||
|
||||
! psig=0.
|
||||
! pnoise=0.
|
||||
! do i=1,npts
|
||||
! if(i.gt.12000 .and. i.lt.624000) then
|
||||
! psig=psig + aimag(cdat(i))**2
|
||||
! pnoise=pnoise + xnoise(i)*xnoise(i)
|
||||
! endif
|
||||
! enddo
|
||||
! pnoise=pnoise*bandwidth_ratio
|
||||
! snr_2500=db(psig/pnoise) !Calibration confirmation!
|
||||
! print*,'SNR_2500:',snr_2500
|
||||
|
||||
dat=aimag(cdat) + xnoise !Add generated AWGN noise
|
||||
fac=32767.0
|
||||
if(snrdb.ge.90.0) iwave(1:npts)=nint(fac*dat(1:npts))
|
||||
|
@ -1,20 +1,25 @@
|
||||
subroutine foxgen2(nslots,cmsg)
|
||||
subroutine foxgen2(nslots,cmsg,line,foxcall)
|
||||
|
||||
! Parse old-style Fox messages to extract the necessary pieces for a SuperFox
|
||||
! transmission.
|
||||
|
||||
use packjt77
|
||||
character*40 cmsg(5)
|
||||
character*120 line
|
||||
character*40 cmsg(5) !Old-style Fox messages are here
|
||||
character*37 msg
|
||||
character*22 sfmsg
|
||||
character*12 mycall
|
||||
character*26 sfmsg
|
||||
character*13 mycall
|
||||
character*11 foxcall
|
||||
character*4 mygrid
|
||||
character*6 hiscall_1,hiscall_2
|
||||
character*4 rpt_1,rpt_2
|
||||
character*4 rpt1,rpt2
|
||||
character*13 w(19)
|
||||
integer nw(19)
|
||||
integer ntype !Message type: 0 Free Text
|
||||
! 1 CQ MyCall MyGrid
|
||||
! 2 Call_1 MyCall RR73
|
||||
! 3 Call_1 MyCall rpt_1
|
||||
! 4 Call_1 RR73; Call_2 <MyCall> rpt_2
|
||||
! 3 Call_1 MyCall rpt1
|
||||
! 4 Call_1 RR73; Call_2 <MyCall> rpt2
|
||||
|
||||
if(nslots.lt.1 .or. nslots.gt.5) return
|
||||
k=0
|
||||
@ -23,8 +28,8 @@ subroutine foxgen2(nslots,cmsg)
|
||||
hiscall_2=''
|
||||
mycall=''
|
||||
mygrid=''
|
||||
rpt_1=''
|
||||
rpt_2=''
|
||||
rpt1=''
|
||||
rpt2=''
|
||||
msg=cmsg(i)(1:37)
|
||||
call split77(msg,nwords,nw,w)
|
||||
ntype=0
|
||||
@ -36,105 +41,35 @@ subroutine foxgen2(nslots,cmsg)
|
||||
ntype=4
|
||||
hiscall_1=w(1)(1:6)
|
||||
hiscall_2=w(3)(1:6)
|
||||
rpt_1='RR73'
|
||||
rpt_2=w(5)(1:4)
|
||||
rpt1='RR73'
|
||||
rpt2=w(5)(1:4)
|
||||
mycall=w(4)(2:nw(4)-1)
|
||||
else if(index(msg,' RR73').gt.0) then
|
||||
ntype=2
|
||||
hiscall_1=w(1)(1:6)
|
||||
mycall=w(2)(1:12)
|
||||
rpt_1='RR73'
|
||||
rpt1='RR73'
|
||||
else if(nwords.eq.3 .and. nw(3).eq.3 .and. &
|
||||
(w(3)(1:1).eq.'-' .or. w(3)(1:1).eq.'+')) then
|
||||
ntype=3
|
||||
hiscall_1=w(1)(1:6)
|
||||
mycall=w(2)(1:12)
|
||||
rpt_1=w(3)(1:4)
|
||||
rpt1=w(3)(1:4)
|
||||
endif
|
||||
! write(*,3001) ntype,cmsg(i),hiscall_1,rpt_1,hiscall_2,rpt_2, &
|
||||
! mycall(1:6),mygrid
|
||||
!3001 format(i1,2x,a37,1x,a6,1x,a4,1x,a6,1x,a4,1x,a6,1x,a4)
|
||||
|
||||
k=k+1
|
||||
if(ntype.le.3) call sfox_assemble(ntype,k,msg(1:22),mycall,mygrid)
|
||||
if(ntype.le.3) call sfox_assemble(ntype,k,msg(1:26),mycall,mygrid,line)
|
||||
if(ntype.eq.4) then
|
||||
sfmsg=w(1)(1:nw(1))//' '//mycall(1:len(trim(mycall))+1)//'RR73'
|
||||
call sfox_assemble(2,k,sfmsg,mycall,mygrid)
|
||||
call sfox_assemble(2,k,sfmsg,mycall,mygrid,line)
|
||||
sfmsg=w(3)(1:nw(3))//' '//mycall(1:len(trim(mycall))+1)//w(5)(1:3)
|
||||
k=k+1
|
||||
call sfox_assemble(3,k,sfmsg,mycall,mygrid)
|
||||
call sfox_assemble(3,k,sfmsg,mycall,mygrid,line)
|
||||
endif
|
||||
|
||||
enddo
|
||||
call sfox_assemble(ntype,11,msg(1:22),mycall,mygrid) !k=11 to finish up
|
||||
|
||||
call sfox_assemble(ntype,11,msg(1:26),mycall,mygrid,line) !k=11 to finish up
|
||||
foxcall=mycall(1:11)
|
||||
|
||||
return
|
||||
end subroutine foxgen2
|
||||
|
||||
subroutine sfox_assemble(ntype,k,msg,mycall0,mygrid0)
|
||||
|
||||
character*22 msg
|
||||
character*22 msg0,msg1,msg2(10),msg3(5)
|
||||
character*12 mycall0,mycall
|
||||
character*4 mygrid0,mygrid
|
||||
integer ntype !Message type: 0 Free Text
|
||||
! 1 CQ MyCall MyGrid
|
||||
! 2 Call_1 MyCall RR73
|
||||
! 3 Call_1 MyCall rpt
|
||||
integer nmsg(0:3) !Number of messages of type ntype
|
||||
data nmsg/0,0,0,0/,nbits/0/,ntx/0/
|
||||
save
|
||||
! save mycall,mygrid,nmsg,nbits,ntx
|
||||
|
||||
if(mycall0(1:1).ne.' ') mycall=mycall0
|
||||
if(mygrid0(1:1).ne.' ') mygrid=mygrid0
|
||||
if(k.le.10) then
|
||||
if(ntype.eq.0) then
|
||||
if(nbits.le.262) then
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+71
|
||||
msg0=msg
|
||||
endif
|
||||
else if(ntype.eq.1) then
|
||||
if(nbits.le.290) then
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+43
|
||||
msg1=msg
|
||||
endif
|
||||
else if(ntype.eq.2) then
|
||||
if(nbits.le.305) then
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+28
|
||||
j=nmsg(ntype)
|
||||
msg2(j)=msg
|
||||
endif
|
||||
else
|
||||
if(nbits.le.300) then
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+33
|
||||
j=nmsg(ntype)
|
||||
msg3(j)=msg
|
||||
endif
|
||||
endif
|
||||
return
|
||||
endif
|
||||
|
||||
if(k.ge.11) then
|
||||
ntx=ntx+1 !Transmission number
|
||||
write(*,3002) ntx,ntype,nmsg(0:3),nbits
|
||||
3002 format(i3,i5,2x,4i3,i6)
|
||||
if(nmsg(0).ge.1) write(*,3010) ntx,msg0
|
||||
3010 format(i3,2x,a22)
|
||||
if(nmsg(1).ge.1) write(*,3010) ntx,msg1
|
||||
do i=1,nmsg(2)
|
||||
write(*,3010) ntx,msg2(i)
|
||||
enddo
|
||||
do i=1,nmsg(3)
|
||||
write(*,3010) ntx,msg3(i)
|
||||
enddo
|
||||
nmsg=0
|
||||
nbits=0
|
||||
endif
|
||||
|
||||
return
|
||||
end subroutine sfox_assemble
|
||||
|
12
lib/superfox/ft8_params.f90
Normal file
12
lib/superfox/ft8_params.f90
Normal file
@ -0,0 +1,12 @@
|
||||
! LDPC (174,91) code
|
||||
parameter (KK=91) !Information bits (77 + CRC14)
|
||||
parameter (ND=58) !Data symbols
|
||||
parameter (NS=21) !Sync symbols (3 @ Costas 7x7)
|
||||
parameter (NN=NS+ND) !Total channel symbols (79)
|
||||
parameter (NSPS=1920) !Samples per symbol at 12000 S/s
|
||||
parameter (NZ=NSPS*NN) !Samples in full 15 s waveform (151,680)
|
||||
parameter (NMAX=15*12000) !Samples in iwave (180,000)
|
||||
parameter (NFFT1=2*NSPS, NH1=NFFT1/2) !Length of FFTs for symbol spectra
|
||||
parameter (NSTEP=NSPS/4) !Rough time-sync step size
|
||||
parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps)
|
||||
parameter (NDOWN=60) !Downsample factor
|
3
lib/superfox/gtag.f90
Normal file
3
lib/superfox/gtag.f90
Normal file
@ -0,0 +1,3 @@
|
||||
integer ntag
|
||||
data ntag/z"1234567"/
|
||||
!-----------------------------------------------------------------------
|
39
lib/superfox/julian.f90
Normal file
39
lib/superfox/julian.f90
Normal file
@ -0,0 +1,39 @@
|
||||
module julian
|
||||
|
||||
contains
|
||||
|
||||
integer*8 function itime8()
|
||||
|
||||
implicit integer (a-z)
|
||||
! 1 2 3 4 5 6 7
|
||||
integer it(8) !y m d nmin h m s
|
||||
integer*8 secday
|
||||
data secday/86400/
|
||||
|
||||
call date_and_time(values=it)
|
||||
iyr=it(1)
|
||||
imo=it(2)
|
||||
iday=it(3)
|
||||
days=JD(iyr,imo,iday) - 2440588 !Days since epoch Jan 1, 1970
|
||||
ih=it(5)
|
||||
im=it(6)-it(4) !it(4) corrects for time zone
|
||||
is=it(7)
|
||||
nsec=3600*ih + 60*im + is
|
||||
itime8=days*secday + nsec
|
||||
|
||||
return
|
||||
end function itime8
|
||||
|
||||
integer function JD(I,J,K)
|
||||
|
||||
! Return Julian Date for I=year, J=month, K=day
|
||||
! Reference: Fliegel and Van Flandern, Comm. ACM 11, 10, 1968
|
||||
|
||||
JD = K - 32075 + 1461*(I + 4800 + (J - 14)/12)/4 &
|
||||
+ 367*(J - 2 - (J - 14)/12*12)/12 - 3 &
|
||||
*((I + 4900 + (J - 14)/12)/100)/4
|
||||
|
||||
return
|
||||
end function JD
|
||||
|
||||
end module julian
|
103
lib/superfox/popen_module.f90
Normal file
103
lib/superfox/popen_module.f90
Normal file
@ -0,0 +1,103 @@
|
||||
!*******************************************************************************
|
||||
!>
|
||||
! A simple module for `popen`.
|
||||
|
||||
module popen_module
|
||||
|
||||
use,intrinsic :: iso_c_binding
|
||||
|
||||
implicit none
|
||||
|
||||
private
|
||||
|
||||
! interfaces to C functions
|
||||
interface
|
||||
|
||||
function popen(command, mode) bind(C,name='popen')
|
||||
!! initiate pipe streams to or from a process
|
||||
import :: c_char, c_ptr
|
||||
implicit none
|
||||
character(kind=c_char),dimension(*) :: command
|
||||
character(kind=c_char),dimension(*) :: mode
|
||||
type(c_ptr) :: popen
|
||||
end function popen
|
||||
|
||||
function fgets(s, siz, stream) bind(C,name='fgets')
|
||||
!! get a string from a stream
|
||||
import :: c_char, c_ptr, c_int
|
||||
implicit none
|
||||
type (c_ptr) :: fgets
|
||||
character(kind=c_char),dimension(*) :: s
|
||||
integer(kind=c_int),value :: siz
|
||||
type(c_ptr),value :: stream
|
||||
end function fgets
|
||||
|
||||
function pclose(stream) bind(C,name='pclose')
|
||||
!! close a pipe stream to or from a process
|
||||
import :: c_ptr, c_int
|
||||
implicit none
|
||||
integer(c_int) :: pclose
|
||||
type(c_ptr),value :: stream
|
||||
end function pclose
|
||||
|
||||
end interface
|
||||
|
||||
public :: c2f_string, get_command_as_string
|
||||
|
||||
contains
|
||||
|
||||
!*******************************************************************************
|
||||
!>
|
||||
! Convert a C string to a Fortran string.
|
||||
|
||||
function c2f_string(c) result(f)
|
||||
|
||||
character(len=*),intent(in) :: c !! C string
|
||||
character(len=:),allocatable :: f !! Fortran string
|
||||
|
||||
integer :: i
|
||||
|
||||
i = index(c,c_null_char)
|
||||
|
||||
if (i<=0) then
|
||||
f = c
|
||||
else if (i==1) then
|
||||
f = ''
|
||||
else if (i>1) then
|
||||
f = c(1:i-1)
|
||||
end if
|
||||
|
||||
end function c2f_string
|
||||
|
||||
!*******************************************************************************
|
||||
!>
|
||||
! Return the result of the command as a string.
|
||||
|
||||
function get_command_as_string(command) result(str)
|
||||
|
||||
character(len=*),intent(in) :: command !! the command to run
|
||||
character(len=:),allocatable :: str !! the result of that command
|
||||
|
||||
integer,parameter :: buffer_length = 1000 !! read stream in chunks of this size
|
||||
|
||||
type(c_ptr) :: h !! for `popen`
|
||||
integer(c_int) :: istat !! `pclose` status
|
||||
character(kind=c_char,len=buffer_length) :: line !! buffer to read from `fgets`
|
||||
|
||||
str = ''
|
||||
h = c_null_ptr
|
||||
h = popen(command//c_null_char,'r'//c_null_char)
|
||||
|
||||
if (c_associated(h)) then
|
||||
do while (c_associated(fgets(line,buffer_length,h)))
|
||||
str = str//c2f_string(line)
|
||||
end do
|
||||
istat = pclose(h)
|
||||
end if
|
||||
|
||||
end function get_command_as_string
|
||||
|
||||
!*******************************************************************************
|
||||
end module popen_module
|
||||
!*******************************************************************************
|
||||
|
67
lib/superfox/qpc/dbgprintf.c
Normal file
67
lib/superfox/qpc/dbgprintf.c
Normal file
@ -0,0 +1,67 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// dbgprintf.c
|
||||
// Functions for printing debug information
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#include "dbgprintf.h"
|
||||
|
||||
// print functions for debug purposes
|
||||
void dbgprintf_vector_uchar(const char* name, const unsigned char* v, int vsize)
|
||||
{
|
||||
int k;
|
||||
|
||||
printf("%s=", name);
|
||||
for (k = 0; k < vsize; k++) {
|
||||
if ((k & 0x0F) == 0)
|
||||
printf("\n");
|
||||
printf("%02X ", v[k]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dbgprintf_vector_float(const char* name, const float* v, int vsize)
|
||||
{
|
||||
int k;
|
||||
|
||||
printf("%s=", name);
|
||||
for (k = 0; k < vsize; k++) {
|
||||
if ((k & 0x07) == 0)
|
||||
printf("\n");
|
||||
printf("%10.3f ", v[k]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dbgprintf_rows_float(const char* name, const float* v, int vsize, int nrows)
|
||||
{
|
||||
int k;
|
||||
int j;
|
||||
|
||||
printf("%s=\n", name);
|
||||
for (j = 0; j < nrows; j++) {
|
||||
printf("r%d:", j);
|
||||
for (k = 0; k < vsize; k++) {
|
||||
if ((k & 0x07) == 0)
|
||||
printf("\n");
|
||||
printf("%7.3f ", v[k]);
|
||||
}
|
||||
printf("\n");
|
||||
v += vsize;
|
||||
}
|
||||
}
|
64
lib/superfox/qpc/dbgprintf.h
Normal file
64
lib/superfox/qpc/dbgprintf.h
Normal file
@ -0,0 +1,64 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// dbgprintf.h
|
||||
// Functions for printing debug information
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _dbgprintf_h_
|
||||
#define _dbgprintf_h_
|
||||
|
||||
// Define DBGPRINTF_ANYWAY
|
||||
// in order to print debug information also
|
||||
// when _DEBUG is not defined
|
||||
|
||||
#define DBGPRINTF_ANYWAY
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DBG_PRINTF
|
||||
#else
|
||||
#ifdef DBGPRINTF_ANYWAY
|
||||
#define DBG_PRINTF
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// print functions for debug purposes
|
||||
#ifdef DBG_PRINTF
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dbgprintf_vector_uchar(const char* name, const unsigned char* v, int vsize);
|
||||
void dbgprintf_vector_float(const char* name, const float* v, int vsize);
|
||||
void dbgprintf_rows_float(const char* name, const float* v, int vsize, int nrows);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define dbgprintf_vector_uchar(a,b)
|
||||
#define dbgprintf_vector_float(a,b)
|
||||
#define dbgprintf_rows_float(a, b, c, d)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _dbgprintf_h_
|
383
lib/superfox/qpc/nhash2.c
Normal file
383
lib/superfox/qpc/nhash2.c
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
|
||||
File name: nhash2.c
|
||||
|
||||
*------------------------------------------------------------------------------
|
||||
*
|
||||
* This file is part of the WSPR application, Weak Signal Propogation Reporter
|
||||
*
|
||||
* File Name: nhash.c
|
||||
* Description: Functions to produce 32-bit hashes for hash table lookup
|
||||
*
|
||||
* Copyright (C) 2008-2014 Joseph Taylor, K1JT
|
||||
* License: GNU GPL v3+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
||||
* Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Files: lookup3.c
|
||||
* Copyright: Copyright (C) 2006 Bob Jenkins <bob_jenkins@burtleburtle.net>
|
||||
* License: public-domain
|
||||
* You may use this code any way you wish, private, educational, or commercial.
|
||||
* It's free.
|
||||
*
|
||||
*-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
These are functions for producing 32-bit hashes for hash table lookup.
|
||||
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||
are externally useful functions. Routines to test the hash are included
|
||||
if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||
the public domain. It has no warranty.
|
||||
|
||||
You probably want to use hashlittle(). hashlittle() and hashbig()
|
||||
hash byte arrays. hashlittle() is is faster than hashbig() on
|
||||
little-endian machines. Intel and AMD are little-endian machines.
|
||||
On second thought, you probably want hashlittle2(), which is identical to
|
||||
hashlittle() except it returns two 32-bit hashes for the price of one.
|
||||
You could implement hashbig2() if you wanted but I haven't bothered here.
|
||||
|
||||
If you want to find a hash of, say, exactly 7 integers, do
|
||||
a = i1; b = i2; c = i3;
|
||||
mix(a,b,c);
|
||||
a += i4; b += i5; c += i6;
|
||||
mix(a,b,c);
|
||||
a += i7;
|
||||
final(a,b,c);
|
||||
then use c as the hash value. If you have a variable length array of
|
||||
4-byte integers to hash, use hashword(). If you have a byte array (like
|
||||
a character string), use hashlittle(). If you have several byte arrays, or
|
||||
a mix of things, see the comments above hashlittle().
|
||||
|
||||
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
|
||||
then mix those integers. This is fast (you can do a lot more thorough
|
||||
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
|
||||
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
||||
*/
|
||||
|
||||
#define SELF_TEST 1
|
||||
|
||||
#include <stdio.h> /* defines printf for tests */
|
||||
#include <time.h> /* defines time_t for timings in the test */
|
||||
#include "nhash2.h"
|
||||
//#include <sys/param.h> /* attempt to define endianness */
|
||||
//#ifdef linux
|
||||
//# include <endian.h> /* attempt to define endianness */
|
||||
//#endif
|
||||
|
||||
#define HASH_LITTLE_ENDIAN 1
|
||||
|
||||
#define hashsize(n) ((uint32_t)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
mix -- mix 3 32-bit values reversibly.
|
||||
|
||||
This is reversible, so any information in (a,b,c) before mix() is
|
||||
still in (a,b,c) after mix().
|
||||
|
||||
If four pairs of (a,b,c) inputs are run through mix(), or through
|
||||
mix() in reverse, there are at least 32 bits of the output that
|
||||
are sometimes the same for one pair and different for another pair.
|
||||
This was tested for:
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
|
||||
satisfy this are
|
||||
4 6 8 16 19 4
|
||||
9 15 3 18 27 15
|
||||
14 9 3 7 17 3
|
||||
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
|
||||
for "differ" defined as + with a one-bit base and a two-bit delta. I
|
||||
used http://burtleburtle.net/bob/hash/avalanche.html to choose
|
||||
the operations, constants, and arrangements of the variables.
|
||||
|
||||
This does not achieve avalanche. There are input bits of (a,b,c)
|
||||
that fail to affect some output bits of (a,b,c), especially of a. The
|
||||
most thoroughly mixed value is c, but it doesn't really even achieve
|
||||
avalanche in c.
|
||||
|
||||
This allows some parallelism. Read-after-writes are good at doubling
|
||||
the number of bits affected, so the goal of mixing pulls in the opposite
|
||||
direction as the goal of parallelism. I did what I could. Rotates
|
||||
seem to cost as much as shifts on every machine I could lay my hands
|
||||
on, and rotates are much kinder to the top and bottom bits, so I used
|
||||
rotates.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= c; a ^= rot(c, 4); c += b; \
|
||||
b -= a; b ^= rot(a, 6); a += c; \
|
||||
c -= b; c ^= rot(b, 8); b += a; \
|
||||
a -= c; a ^= rot(c,16); c += b; \
|
||||
b -= a; b ^= rot(a,19); a += c; \
|
||||
c -= b; c ^= rot(b, 4); b += a; \
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
final -- final mixing of 3 32-bit values (a,b,c) into c
|
||||
|
||||
Pairs of (a,b,c) values differing in only a few bits will usually
|
||||
produce values of c that look totally different. This was tested for
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
These constants passed:
|
||||
14 11 25 16 4 14 24
|
||||
12 14 25 16 4 14 24
|
||||
and these came close:
|
||||
4 8 15 26 3 22 24
|
||||
10 8 15 26 3 22 24
|
||||
11 8 15 26 3 22 24
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define final(a,b,c) \
|
||||
{ \
|
||||
c ^= b; c -= rot(b,14); \
|
||||
a ^= c; a -= rot(c,11); \
|
||||
b ^= a; b -= rot(a,25); \
|
||||
c ^= b; c -= rot(b,16); \
|
||||
a ^= c; a -= rot(c,4); \
|
||||
b ^= a; b -= rot(a,14); \
|
||||
c ^= b; c -= rot(b,24); \
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
hashlittle() -- hash a variable-length key into a 32-bit value
|
||||
k : the key (the unaligned variable-length array of bytes)
|
||||
length : the length of the key, counting by bytes
|
||||
initval : can be any 4-byte value
|
||||
Returns a 32-bit value. Every bit of the key affects every bit of
|
||||
the return value. Two keys differing by one or two bits will have
|
||||
totally different hash values.
|
||||
|
||||
The best hash table sizes are powers of 2. There is no need to do
|
||||
mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||
use a bitmask. For example, if you need only 10 bits, do
|
||||
h = (h & hashmask(10));
|
||||
In which case, the hash table should have hashsize(10) elements.
|
||||
|
||||
If you are hashing n strings (uint8_t **)k, do it like this:
|
||||
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
|
||||
|
||||
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
|
||||
code any way you wish, private, educational, or commercial. It's free.
|
||||
|
||||
Use for hash table lookup, or anything where one collision in 2^^32 is
|
||||
acceptable. Do NOT use for cryptographic purposes.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
uint32_t nhash2( const void *key, uint64_t length, uint32_t initval)
|
||||
//int nhash( const char *key, int length, int initval)
|
||||
{
|
||||
uint32_t a,b,c; /* internal state */
|
||||
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
|
||||
|
||||
u.ptr = key;
|
||||
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||
|
||||
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
// printf("AAA %x %d %x %d\n",c,c,c&32767,c&32767);
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
/*
|
||||
* "k[2]&0xffffff" actually reads beyond the end of the string, but
|
||||
* then masks off the part it's not allowed to read. Because the
|
||||
* string is aligned, the masked-off tail is in the same word as the
|
||||
* rest of the string. Every machine with memory protection I've seen
|
||||
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||
* still catch it and complain. The masking trick does make the hash
|
||||
* noticably faster for short strings (like English words).
|
||||
*/
|
||||
#ifndef VALGRIND
|
||||
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
|
||||
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
|
||||
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
|
||||
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
|
||||
case 5 : b+=k[1]&0xff; a+=k[0]; break;
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=k[0]&0xffffff; break;
|
||||
case 2 : a+=k[0]&0xffff; break;
|
||||
case 1 : a+=k[0]&0xff; break;
|
||||
case 0 : return c; /* zero length strings require no mixing */
|
||||
}
|
||||
|
||||
#else /* make valgrind happy */
|
||||
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||
case 1 : a+=k8[0]; break;
|
||||
case 0 : return c;
|
||||
}
|
||||
|
||||
#endif /* !valgrind */
|
||||
|
||||
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*--------------- all but last block: aligned reads and different mixing */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0] + (((uint32_t)k[1])<<16);
|
||||
b += k[2] + (((uint32_t)k[3])<<16);
|
||||
c += k[4] + (((uint32_t)k[5])<<16);
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 6;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=k[4];
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=k[2];
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=k[0];
|
||||
break;
|
||||
case 1 : a+=k8[0];
|
||||
break;
|
||||
case 0 : return c; /* zero length requires no mixing */
|
||||
}
|
||||
|
||||
} else { /* need to read the key one byte at a time */
|
||||
const uint8_t *k = (const uint8_t *)key;
|
||||
|
||||
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
a += ((uint32_t)k[1])<<8;
|
||||
a += ((uint32_t)k[2])<<16;
|
||||
a += ((uint32_t)k[3])<<24;
|
||||
b += k[4];
|
||||
b += ((uint32_t)k[5])<<8;
|
||||
b += ((uint32_t)k[6])<<16;
|
||||
b += ((uint32_t)k[7])<<24;
|
||||
c += k[8];
|
||||
c += ((uint32_t)k[9])<<8;
|
||||
c += ((uint32_t)k[10])<<16;
|
||||
c += ((uint32_t)k[11])<<24;
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
|
||||
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||
switch(length) /* all the case statements fall through */
|
||||
{
|
||||
case 12: c+=((uint32_t)k[11])<<24;
|
||||
/* fall through */
|
||||
case 11: c+=((uint32_t)k[10])<<16;
|
||||
/* fall through */
|
||||
case 10: c+=((uint32_t)k[9])<<8;
|
||||
/* fall through */
|
||||
case 9 : c+=k[8];
|
||||
/* fall through */
|
||||
case 8 : b+=((uint32_t)k[7])<<24;
|
||||
/* fall through */
|
||||
case 7 : b+=((uint32_t)k[6])<<16;
|
||||
/* fall through */
|
||||
case 6 : b+=((uint32_t)k[5])<<8;
|
||||
/* fall through */
|
||||
case 5 : b+=k[4];
|
||||
/* fall through */
|
||||
case 4 : a+=((uint32_t)k[3])<<24;
|
||||
/* fall through */
|
||||
case 3 : a+=((uint32_t)k[2])<<16;
|
||||
/* fall through */
|
||||
case 2 : a+=((uint32_t)k[1])<<8;
|
||||
/* fall through */
|
||||
case 1 : a+=k[0];
|
||||
break;
|
||||
case 0 : return c;
|
||||
}
|
||||
}
|
||||
|
||||
final(a,b,c);
|
||||
return c;
|
||||
}
|
22
lib/superfox/qpc/nhash2.h
Normal file
22
lib/superfox/qpc/nhash2.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef NHASH_H_
|
||||
#define NHASH_H_
|
||||
|
||||
#ifdef Win32
|
||||
#include "win_stdint.h" /* defines uint32_t etc */
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#include <stdint.h> /* defines uint32_t etc */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t nhash( const void * key, uint64_t length, uint32_t initval);
|
||||
//int nhash(const char *key, int length, int initval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
329
lib/superfox/qpc/np_qpc.c
Normal file
329
lib/superfox/qpc/np_qpc.c
Normal file
@ -0,0 +1,329 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_qpc.h
|
||||
// Q-Ary Polar Codes encoding/decoding functions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "dbgprintf.h"
|
||||
#include "qpc_fwht.h"
|
||||
#include "np_qpc.h"
|
||||
|
||||
// static constant / functions
|
||||
|
||||
static const float knorm = 1.0f / QPC_Q;
|
||||
|
||||
static float* pdf_conv(float *dst, float* pdf1, float* pdf2)
|
||||
{
|
||||
// convolution between two pdf
|
||||
|
||||
float fwht_pdf1[QPC_Q];
|
||||
float fwht_pdf2[QPC_Q];
|
||||
int k;
|
||||
|
||||
qpc_fwht(fwht_pdf1, pdf1);
|
||||
qpc_fwht(fwht_pdf2, pdf2);
|
||||
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
fwht_pdf1[k] *= fwht_pdf2[k];
|
||||
|
||||
qpc_fwht(dst, fwht_pdf1);
|
||||
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
dst[k] *= knorm;
|
||||
|
||||
return dst;
|
||||
}
|
||||
static void pdfarray_conv(float* dstarray, float* pdf1array, float* pdf2array, int numrows)
|
||||
{
|
||||
int k;
|
||||
|
||||
// convolutions between rows of pdfs
|
||||
|
||||
for (k = 0; k < numrows; k++) {
|
||||
pdf_conv(dstarray, pdf1array, pdf2array);
|
||||
dstarray += QPC_Q;
|
||||
pdf1array += QPC_Q;
|
||||
pdf2array += QPC_Q;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static float _pdfuniform[QPC_Q];
|
||||
static const float* _pdf_uniform1();
|
||||
static const float* _pdf_uniform0();
|
||||
typedef const float*(*ptr_pdfuniform)(void);
|
||||
|
||||
static ptr_pdfuniform _ptr_pdf_uniform = _pdf_uniform0;
|
||||
|
||||
static const float* _pdf_uniform1()
|
||||
{
|
||||
return _pdfuniform;
|
||||
};
|
||||
static const float* _pdf_uniform0()
|
||||
{
|
||||
// compute uniform pdf once for all
|
||||
int k;
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
_pdfuniform[k] = knorm;
|
||||
|
||||
// next call to _qpc_pdfuniform
|
||||
// will be handled directly by _pqc_pdfuniform1
|
||||
_ptr_pdf_uniform = _pdf_uniform1;
|
||||
|
||||
return _pdfuniform;
|
||||
};
|
||||
static const float* pdf_uniform()
|
||||
{
|
||||
return _ptr_pdf_uniform();
|
||||
}
|
||||
|
||||
static float * pdf_mul(float *dst, float* pdf1, float* pdf2)
|
||||
{
|
||||
int k;
|
||||
float v;
|
||||
float norm = 0;
|
||||
for (k = 0; k < QPC_Q; k++) {
|
||||
v = pdf1[k] * pdf2[k];
|
||||
dst[k] = v;
|
||||
norm += v;
|
||||
}
|
||||
// if norm of the result is not positive
|
||||
// return in dst a uniform distribution
|
||||
if (norm <= 0)
|
||||
memcpy(dst, pdf_uniform(), QPC_Q * sizeof(float));
|
||||
else {
|
||||
norm = 1.0f / norm;
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
dst[k] = dst[k] * norm;
|
||||
}
|
||||
|
||||
|
||||
return dst;
|
||||
}
|
||||
static void pdfarray_mul(float* dstarray, float* pdf1array, float* pdf2array, int numrows)
|
||||
{
|
||||
int k;
|
||||
|
||||
// products between rows of pdfs
|
||||
|
||||
for (k = 0; k < numrows; k++) {
|
||||
pdf_mul(dstarray, pdf1array, pdf2array);
|
||||
dstarray += QPC_Q;
|
||||
pdf1array += QPC_Q;
|
||||
pdf2array += QPC_Q;
|
||||
}
|
||||
}
|
||||
|
||||
static float* pdf_convhard(float* dst, const float* pdf, unsigned char hd)
|
||||
{
|
||||
// convolution between a pdf and a hard-decision feedback
|
||||
|
||||
int k;
|
||||
for (k=0;k<QPC_Q;k++)
|
||||
dst[k] = pdf[k^hd];
|
||||
|
||||
return dst;
|
||||
}
|
||||
static void pdfarray_convhard(float* dstarray, const float* pdfarray, const unsigned char *hdarray, int numrows)
|
||||
{
|
||||
int k;
|
||||
|
||||
// hard convolutions between rows
|
||||
|
||||
for (k = 0; k < numrows; k++) {
|
||||
pdf_convhard(dstarray, pdfarray, hdarray[k]);
|
||||
dstarray += QPC_Q;
|
||||
pdfarray += QPC_Q;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char pdf_max(const float* pdf)
|
||||
{
|
||||
int k;
|
||||
|
||||
unsigned char imax = 0;
|
||||
float pdfmax = pdf[0];
|
||||
|
||||
for (k=1;k<QPC_Q;k++)
|
||||
if (pdf[k] > pdfmax) {
|
||||
pdfmax = pdf[k];
|
||||
imax = k;
|
||||
}
|
||||
|
||||
return imax;
|
||||
}
|
||||
|
||||
// local stack functions ---------------------------------------
|
||||
static float _qpc_stack[QPC_N * QPC_Q * 2];
|
||||
static float* _qpc_stack_base = _qpc_stack;
|
||||
|
||||
static float* _qpc_stack_push(int numfloats)
|
||||
{
|
||||
float* addr = _qpc_stack_base;
|
||||
_qpc_stack_base += numfloats;
|
||||
return addr;
|
||||
}
|
||||
static void _qpc_stack_pop(int numfloats)
|
||||
{
|
||||
_qpc_stack_base -= numfloats;
|
||||
}
|
||||
|
||||
// qpc encoder function (internal use) ----------------------------------------------------------
|
||||
unsigned char* _qpc_encode(unsigned char* y, unsigned char* x)
|
||||
{
|
||||
// Non recursive polar encoder
|
||||
// Same architecture of a fast fourier transform
|
||||
// in which the fft butteflies are replaced by the polar transform
|
||||
// butterflies
|
||||
|
||||
int k, j, m;
|
||||
int groups;
|
||||
int bfypergroup;
|
||||
int stepbfy;
|
||||
int stepgroup;
|
||||
int basegroup;
|
||||
int basebfy;
|
||||
|
||||
memcpy(y, x, QPC_N);
|
||||
|
||||
for (k = 0; k < QPC_LOG2N; k++) {
|
||||
groups = 1 << (QPC_LOG2N - 1 - k);
|
||||
stepbfy = bfypergroup = 1 << k;
|
||||
stepgroup = stepbfy << 1;
|
||||
basegroup = 0;
|
||||
for (j = 0; j < groups; j++) {
|
||||
basebfy = basegroup;
|
||||
for (m = 0; m < bfypergroup; m++) {
|
||||
// polar transform
|
||||
y[basebfy + stepbfy] = y[basebfy + stepbfy] ^ y[basebfy];
|
||||
basebfy = basebfy + 1;
|
||||
}
|
||||
basegroup = basegroup + stepgroup;
|
||||
}
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
// qpc polar decoder (internal use )--------------------------------------------------
|
||||
void _qpc_decode(unsigned char* xdec, unsigned char* ydec, const float* py, const unsigned char* f, const unsigned char* fsize, const int numrows)
|
||||
{
|
||||
|
||||
if (numrows == 1) {
|
||||
if (fsize[0] == 0) {
|
||||
// dbgprintf_vector_float("py", py, QPC_Q);
|
||||
|
||||
// frozen symbol
|
||||
xdec[0] = pdf_max(py);
|
||||
ydec[0] = f[0];
|
||||
}
|
||||
else {
|
||||
// fsize = 1 => information symbol
|
||||
xdec[0] = pdf_max(py);
|
||||
ydec[0] = xdec[0];
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
int k;
|
||||
int nextrows = numrows >> 1;
|
||||
int size = nextrows << QPC_LOG2Q;
|
||||
|
||||
// upper block variables
|
||||
unsigned char* xdech = xdec + nextrows;
|
||||
unsigned char* ydech = ydec + nextrows;
|
||||
const unsigned char* fh = f + nextrows;
|
||||
const unsigned char* fsizeh = fsize + nextrows;
|
||||
|
||||
// Step 1.
|
||||
// stack and init variables used in the recursion
|
||||
|
||||
float* pyl = _qpc_stack_push(size);
|
||||
memcpy(pyl, py, size * sizeof(float));
|
||||
|
||||
float* pyh = _qpc_stack_push(size);
|
||||
memcpy(pyh, py + size, size * sizeof(float));
|
||||
|
||||
// Step 2. Recursion on upper block
|
||||
// Forward pdf convolutions for the upper block
|
||||
// (place in the lower part of py the convolution of lower and higher blocks)
|
||||
|
||||
// float* pyh = py + size;
|
||||
// pdfarray_conv(py, pyl, pyh, nextrows); // convolution overwriting the lower block of py which is not needed
|
||||
|
||||
pdfarray_conv(pyh, pyl, pyh, nextrows);
|
||||
_qpc_decode(xdech, ydech, pyh, fh, fsizeh, nextrows);
|
||||
|
||||
// Step 3. compute pdfs in the lower block
|
||||
pdfarray_convhard(pyh, py+size, ydech,nextrows); // dst ptr must be different form src ptr
|
||||
pdfarray_mul(pyl, pyl, pyh, nextrows);
|
||||
// we don't need pyh anymore
|
||||
_qpc_stack_pop(size);
|
||||
|
||||
// Step 4. Recursion on the lower block
|
||||
_qpc_decode(xdec, ydec, pyl, f, fsize, nextrows);
|
||||
// we don't need pyl anymore
|
||||
_qpc_stack_pop(size);
|
||||
|
||||
// Step 5. Update backward results
|
||||
// xdec is already ok, we need just to update ydech
|
||||
for (k = 0; k < nextrows; k++)
|
||||
ydech[k] = ydech[k] ^ ydec[k];
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Public encoding/decoding functions ------------------------------------------------
|
||||
void qpc_encode(unsigned char* y, const unsigned char* x)
|
||||
{
|
||||
|
||||
// map information symbols
|
||||
int kk, pos;
|
||||
for (kk = 0; kk < QPC_K; kk++) {
|
||||
pos = qpccode.xpos[kk];
|
||||
qpccode.f[pos] = x[kk];
|
||||
}
|
||||
// do polar encoding
|
||||
_qpc_encode(y, qpccode.f);
|
||||
}
|
||||
void qpc_decode(unsigned char* xdec, unsigned char* ydec, float* py)
|
||||
{
|
||||
int k;
|
||||
unsigned char x[QPC_N];
|
||||
|
||||
// set the first py row with know frozen (punctured) symbol
|
||||
if (qpccode.np < qpccode.n) {
|
||||
// assume that we punctured only the first output symbol
|
||||
memset(py, 0, QPC_Q * sizeof(float));
|
||||
py[qpccode.f[0]] = 1.0f;
|
||||
}
|
||||
|
||||
// decode
|
||||
_qpc_decode(x, ydec, py, qpccode.f, qpccode.fsize, QPC_N);
|
||||
|
||||
// demap information symbols
|
||||
for (k = 0; k < QPC_K; k++)
|
||||
xdec[k] = x[qpccode.xpos[k]];
|
||||
|
||||
}
|
62
lib/superfox/qpc/np_qpc.h
Normal file
62
lib/superfox/qpc/np_qpc.h
Normal file
@ -0,0 +1,62 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_qpc.h
|
||||
// Q-Ary Polar Codes encoding/decoding functions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
#ifndef _np_qpc_h_
|
||||
#define _np_qpc_h_
|
||||
|
||||
#define QPC_LOG2N 7 // log2(codeword length) (not punctured)
|
||||
#define QPC_N (1<<QPC_LOG2N) // codeword length (not punctured)
|
||||
#define QPC_LOG2Q 7 // bits per symbol
|
||||
#define QPC_Q (1<<QPC_LOG2Q) // alphabet size
|
||||
#define QPC_K 50 // number of information symbols
|
||||
|
||||
|
||||
typedef struct {
|
||||
int n; // codeword length (unpunctured)
|
||||
int np; // codeword length (punctured)
|
||||
int k; // number of information symbols
|
||||
int q; // alphabet size
|
||||
int xpos[QPC_N]; // info symbols mapping/demapping tables
|
||||
unsigned char f[QPC_N]; // frozen symbols values
|
||||
unsigned char fsize[QPC_N]; // frozen symbol flag (fsize==0 => frozen)
|
||||
} qpccode_ds;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void qpc_encode(unsigned char* y, const unsigned char* x);
|
||||
void qpc_decode(unsigned char* xdec, unsigned char* ydec, float* py);
|
||||
|
||||
unsigned char* _qpc_encode(unsigned char* y, unsigned char* x);
|
||||
void _qpc_decode(unsigned char* xdec, unsigned char* ydec,
|
||||
const float* py, const unsigned char* f, const unsigned char* fsize,
|
||||
const int numrows);
|
||||
|
||||
extern qpccode_ds qpccode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _np_qpc_h_
|
135
lib/superfox/qpc/np_rnd.c
Normal file
135
lib/superfox/qpc/np_rnd.c
Normal file
@ -0,0 +1,135 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_rnd.c
|
||||
// Functions to generate random numbers with uniform/gaussian probability distributions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "np_rnd.h"
|
||||
|
||||
#if _WIN32 // note the underscore: without it, it's not msdn official!
|
||||
// Windows (x64 and x86)
|
||||
#include <windows.h> // required only for GetTickCount(...)
|
||||
#define K_RAND_MAX UINT_MAX
|
||||
#elif _SVID_SOURCE || _XOPEN_SOURCE || __unix__ || (defined (__APPLE__) && defined(__MACH__)) /* POSIX or Unix or Apple */
|
||||
#include <stdlib.h>
|
||||
#define rand_s(x) (*x)=(unsigned int)lrand48() // returns unsigned integers in the range 0..0x7FFFFFFF
|
||||
#define K_RAND_MAX 0x7FFFFFFF // that's the max number
|
||||
// generated by lrand48
|
||||
#else
|
||||
#error "No good quality PRNG found"
|
||||
#endif
|
||||
|
||||
|
||||
void np_normrnd_real(float *dst, int nitems, float mean, float stdev)
|
||||
{
|
||||
// for odd or even nitems
|
||||
|
||||
unsigned int r;
|
||||
float phi=0, u=0;
|
||||
int set = 0;
|
||||
float scalephi = (M_2PI / (1.0f + K_RAND_MAX));
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
|
||||
while (nitems--)
|
||||
if (set==1) {
|
||||
// generate a second normally distributed number
|
||||
*dst++ = sinf(phi)*u*stdev+mean;
|
||||
set = 0;
|
||||
}
|
||||
else {
|
||||
// generate a uniform distributed phase phi in the range [0,2*PI)
|
||||
rand_s((unsigned int*)&r); phi = scalephi * r;
|
||||
|
||||
// generate a uniform distributed random number u in the range (0,1]
|
||||
rand_s((unsigned int*)&r); u = scaleu * (1.0f + r);
|
||||
|
||||
// generate normally distributed number
|
||||
u = (float)sqrt(-2.0f * log(u));
|
||||
*dst++ = cosf(phi) * u * stdev + mean;
|
||||
|
||||
set=1;
|
||||
}
|
||||
}
|
||||
|
||||
void np_normrnd_cpx(float* dst, int nitems, float mean, float stdev)
|
||||
{
|
||||
// as qpc_normrnd_real, but generates always nitems complex numbers (2*nitems reals)
|
||||
|
||||
unsigned int r;
|
||||
float phi = 0, u = 0;
|
||||
// JHT int set = 0;
|
||||
float scalephi = (M_2PI / (1.0f + K_RAND_MAX));
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
// generate a uniform distributed phase phi in the range [0,2*PI)
|
||||
rand_s((unsigned int*)&r); phi = scalephi * r;
|
||||
|
||||
// generate a uniform distributed random number u in the range (0,1]
|
||||
rand_s((unsigned int*)&r); u = scaleu * (1.0f + r);
|
||||
|
||||
// generate normally distributed real and imaginary parts
|
||||
u = (float)sqrt(-2.0f * log(u));
|
||||
*dst++ = cosf(phi) * u * stdev + mean;
|
||||
*dst++ = sinf(phi) * u * stdev + mean;
|
||||
}
|
||||
}
|
||||
|
||||
void np_unidrnd(unsigned int* dst, int nitems, unsigned int nsetsize)
|
||||
{
|
||||
// generate uniform unsigned int random numbers in the range [0..nsetsize)
|
||||
|
||||
unsigned int r;
|
||||
float u;
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
rand_s((unsigned int*)&r); u = scaleu * nsetsize * r;
|
||||
*dst++ = (unsigned int)floorf(u);
|
||||
}
|
||||
|
||||
}
|
||||
void np_unidrnd_uc(unsigned char* dst, int nitems, unsigned char nsetsize)
|
||||
{
|
||||
// generate uniform unsigned char random numbers in the range [0..nsetsize)
|
||||
|
||||
unsigned int r;
|
||||
float u;
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
rand_s((unsigned int*)&r); u = scaleu * nsetsize * r;
|
||||
*dst++ = (unsigned char)floorf(u);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void np_unifrnd(float* dst, int nitems, float fmax)
|
||||
{
|
||||
// generate uniform float random numbers in the range [0..fmax)
|
||||
|
||||
unsigned int r;
|
||||
float u;
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
rand_s((unsigned int*)&r); u = scaleu * fmax * r;
|
||||
*dst++ = u;
|
||||
}
|
||||
|
||||
}
|
59
lib/superfox/qpc/np_rnd.h
Normal file
59
lib/superfox/qpc/np_rnd.h
Normal file
@ -0,0 +1,59 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_rnd.h
|
||||
// Functions to generate random numbers with uniform/gaussian probability distributions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef _np_rnd_h_
|
||||
#define _np_rnd_h_
|
||||
|
||||
#define _CRT_RAND_S
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#define M_2PI (2.0f*(float)M_PI)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// generate a random array of real numbers with a gaussian distribution of given mean and stdev
|
||||
void np_normrnd_real(float *dst, int nitems, float mean, float stdev);
|
||||
|
||||
// generate a random array of nitems complex numbers with a gaussian distribution of given mean and stdev
|
||||
void np_normrnd_cpx(float* dst, int nitems, float mean, float stdev);
|
||||
|
||||
// generate a random array of nitems unsigned int numbers with uniform distribution
|
||||
// in the range [0 .. nsetsize)
|
||||
void np_unidrnd(unsigned int* dst, int nitems, unsigned int nsetsize);
|
||||
|
||||
// generate a random array of nitems unsigned chars numbers with uniform distribution
|
||||
// in the range [0 .. nsetsize)
|
||||
void np_unidrnd_uc(unsigned char* dst, int nitems, unsigned char nsetsize);
|
||||
|
||||
// generate a random array of nitems float numbers with uniform distribution
|
||||
// in the range [0 .. fmax)
|
||||
void np_unifrnd(float* dst, int nitems, float fmax);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _np_rnd_h_
|
||||
|
233
lib/superfox/qpc/qpc_fwht.c
Normal file
233
lib/superfox/qpc/qpc_fwht.c
Normal file
@ -0,0 +1,233 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_fwht.c
|
||||
// Fast Walsh-Hadamard Transforms for q-ary polar codes
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "qpc_fwht.h"
|
||||
|
||||
static void _qpc_sumdiff8_16(float* y, float* t)
|
||||
{
|
||||
y[0] = t[0] + t[16];
|
||||
y[16] = t[0] - t[16];
|
||||
|
||||
y[1] = t[1] + t[17];
|
||||
y[17] = t[1] - t[17];
|
||||
|
||||
y[2] = t[2] + t[18];
|
||||
y[18] = t[2] - t[18];
|
||||
|
||||
y[3] = t[3] + t[19];
|
||||
y[19] = t[3] - t[19];
|
||||
|
||||
y[4] = t[4] + t[20];
|
||||
y[20] = t[4] - t[20];
|
||||
|
||||
y[5] = t[5] + t[21];
|
||||
y[21] = t[5] - t[21];
|
||||
|
||||
y[6] = t[6] + t[22];
|
||||
y[22] = t[6] - t[22];
|
||||
|
||||
y[7] = t[7] + t[23];
|
||||
y[23] = t[7] - t[23];
|
||||
|
||||
}
|
||||
static void _qpc_sumdiff8_32(float* y, float* t)
|
||||
{
|
||||
y[0] = t[0] + t[32];
|
||||
y[32] = t[0] - t[32];
|
||||
|
||||
y[1] = t[1] + t[33];
|
||||
y[33] = t[1] - t[33];
|
||||
|
||||
y[2] = t[2] + t[34];
|
||||
y[34] = t[2] - t[34];
|
||||
|
||||
y[3] = t[3] + t[35];
|
||||
y[35] = t[3] - t[35];
|
||||
|
||||
y[4] = t[4] + t[36];
|
||||
y[36] = t[4] - t[36];
|
||||
|
||||
y[5] = t[5] + t[37];
|
||||
y[37] = t[5] - t[37];
|
||||
|
||||
y[6] = t[6] + t[38];
|
||||
y[38] = t[6] - t[38];
|
||||
|
||||
y[7] = t[7] + t[39];
|
||||
y[39] = t[7] - t[39];
|
||||
|
||||
}
|
||||
static void _qpc_sumdiff8_64(float* y, float* t)
|
||||
{
|
||||
y[0] = t[0] + t[64];
|
||||
y[64] = t[0] - t[64];
|
||||
|
||||
y[1] = t[1] + t[65];
|
||||
y[65] = t[1] - t[65];
|
||||
|
||||
y[2] = t[2] + t[66];
|
||||
y[66] = t[2] - t[66];
|
||||
|
||||
y[3] = t[3] + t[67];
|
||||
y[67] = t[3] - t[67];
|
||||
|
||||
y[4] = t[4] + t[68];
|
||||
y[68] = t[4] - t[68];
|
||||
|
||||
y[5] = t[5] + t[69];
|
||||
y[69] = t[5] - t[69];
|
||||
|
||||
y[6] = t[6] + t[70];
|
||||
y[70] = t[6] - t[70];
|
||||
|
||||
y[7] = t[7] + t[71];
|
||||
y[71] = t[7] - t[71];
|
||||
|
||||
}
|
||||
|
||||
float* qpc_fwht8(float* y, float* x)
|
||||
{
|
||||
float t[8];
|
||||
|
||||
// first stage
|
||||
y[0] = x[0] + x[1];
|
||||
y[1] = x[0] - x[1];
|
||||
|
||||
y[2] = x[2] + x[3];
|
||||
y[3] = x[2] - x[3];
|
||||
|
||||
y[4] = x[4] + x[5];
|
||||
y[5] = x[4] - x[5];
|
||||
|
||||
y[6] = x[6] + x[7];
|
||||
y[7] = x[6] - x[7];
|
||||
|
||||
// second stage
|
||||
t[0] = y[0] + y[2];
|
||||
t[2] = y[0] - y[2];
|
||||
|
||||
t[1] = y[1] + y[3];
|
||||
t[3] = y[1] - y[3];
|
||||
|
||||
t[4] = y[4] + y[6];
|
||||
t[6] = y[4] - y[6];
|
||||
|
||||
t[5] = y[5] + y[7];
|
||||
t[7] = y[5] - y[7];
|
||||
|
||||
// third stage
|
||||
y[0] = t[0] + t[4];
|
||||
y[4] = t[0] - t[4];
|
||||
|
||||
y[1] = t[1] + t[5];
|
||||
y[5] = t[1] - t[5];
|
||||
|
||||
y[2] = t[2] + t[6];
|
||||
y[6] = t[2] - t[6];
|
||||
|
||||
y[3] = t[3] + t[7];
|
||||
y[7] = t[3] - t[7];
|
||||
|
||||
return y;
|
||||
}
|
||||
float* qpc_fwht16(float* y, float* x)
|
||||
{
|
||||
float t[16];
|
||||
|
||||
qpc_fwht8(t, x);
|
||||
qpc_fwht8(t + 8, x + 8);
|
||||
|
||||
y[0] = t[0] + t[8];
|
||||
y[8] = t[0] - t[8];
|
||||
|
||||
y[1] = t[1] + t[9];
|
||||
y[9] = t[1] - t[9];
|
||||
|
||||
y[2] = t[2] + t[10];
|
||||
y[10] = t[2] - t[10];
|
||||
|
||||
y[3] = t[3] + t[11];
|
||||
y[11] = t[3] - t[11];
|
||||
|
||||
y[4] = t[4] + t[12];
|
||||
y[12] = t[4] - t[12];
|
||||
|
||||
y[5] = t[5] + t[13];
|
||||
y[13] = t[5] - t[13];
|
||||
|
||||
y[6] = t[6] + t[14];
|
||||
y[14] = t[6] - t[14];
|
||||
|
||||
y[7] = t[7] + t[15];
|
||||
y[15] = t[7] - t[15];
|
||||
|
||||
return y;
|
||||
|
||||
}
|
||||
float* qpc_fwht32(float* y, float* x)
|
||||
{
|
||||
float t[32];
|
||||
|
||||
qpc_fwht16(t, x);
|
||||
qpc_fwht16(t + 16, x + 16);
|
||||
|
||||
_qpc_sumdiff8_16(y, t);
|
||||
_qpc_sumdiff8_16(y + 8, t + 8);
|
||||
|
||||
return y;
|
||||
}
|
||||
float* qpc_fwht64(float* y, float* x)
|
||||
{
|
||||
float t[64];
|
||||
|
||||
qpc_fwht32(t, x);
|
||||
qpc_fwht32(t + 32, x + 32);
|
||||
|
||||
_qpc_sumdiff8_32(y, t);
|
||||
_qpc_sumdiff8_32(y + 8, t + 8);
|
||||
_qpc_sumdiff8_32(y + 16, t + 16);
|
||||
_qpc_sumdiff8_32(y + 24, t + 24);
|
||||
|
||||
return y;
|
||||
}
|
||||
float* qpc_fwht128(float* y, float* x)
|
||||
{
|
||||
float t[128];
|
||||
|
||||
qpc_fwht64(t, x);
|
||||
qpc_fwht64(t + 64, x + 64);
|
||||
|
||||
_qpc_sumdiff8_64(y, t);
|
||||
_qpc_sumdiff8_64(y + 8, t + 8);
|
||||
_qpc_sumdiff8_64(y + 16, t + 16);
|
||||
_qpc_sumdiff8_64(y + 24, t + 24);
|
||||
_qpc_sumdiff8_64(y + 32, t + 32);
|
||||
_qpc_sumdiff8_64(y + 40, t + 40);
|
||||
_qpc_sumdiff8_64(y + 48, t + 48);
|
||||
_qpc_sumdiff8_64(y + 56, t + 56);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
// functions over pdfs used by the decoder -----------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
57
lib/superfox/qpc/qpc_fwht.h
Normal file
57
lib/superfox/qpc/qpc_fwht.h
Normal file
@ -0,0 +1,57 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_fwht.h
|
||||
// Fast Walsh-Hadamard Transforms for q-ary polar codes
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
// This file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef _qpc_fwht_h_
|
||||
#define _qpc_fwht_h_
|
||||
|
||||
#include "np_qpc.h"
|
||||
|
||||
#if QPC_LOG2Q==7
|
||||
#define qpc_fwht(a,b) qpc_fwht128(a,b)
|
||||
#endif
|
||||
#if QPC_LOG2Q==6
|
||||
#define qpc_fwht(a,b) qpc_fwht64(a,b)
|
||||
#endif
|
||||
#if QPC_LOG2Q==5
|
||||
#define qpc_fwht(a,b) qpc_fwht32(a,b)
|
||||
#endif
|
||||
#if QPC_LOG2Q==4
|
||||
#define qpc_fwht(a,b) qpc_fwht16(a,b)
|
||||
#endif
|
||||
// Note that it makes no sense to use fast convolutions
|
||||
// for transforms that are less than 16 symbols in size.
|
||||
// For such cases direct convolutions are faster.
|
||||
#if QPC_LOG2Q==3
|
||||
#define qpc_fwht(a,b) qpc_fwht8(a,b)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
float* qpc_fwht8(float* y, float* x);
|
||||
float* qpc_fwht16(float* y, float* x);
|
||||
float* qpc_fwht32(float* y, float* x);
|
||||
float* qpc_fwht64(float* y, float* x);
|
||||
float* qpc_fwht128(float* y, float* x);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _qpc_fwht_h_
|
198
lib/superfox/qpc/qpc_main.cpp
Normal file
198
lib/superfox/qpc/qpc_main.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_main.cpp
|
||||
//
|
||||
// Test the WER performance of the QPC (127,50) Q=128 code
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "dbgprintf.h"
|
||||
#include "qpc_fwht.h"
|
||||
#include "np_qpc.h"
|
||||
|
||||
// for random numbers generation and NCFSK Rayleigh channel simulation
|
||||
#include "np_rnd.h"
|
||||
void qpc_channel(float* yout, unsigned char* y, float EsNo)
|
||||
{
|
||||
// compute channel outputs amplitudes
|
||||
|
||||
int k;
|
||||
|
||||
// generate noise samples -----------------------------------------
|
||||
float sigman = 1.0f / sqrtf(2.0f);
|
||||
np_normrnd_cpx(yout, QPC_N * QPC_Q, 0, sigman);
|
||||
|
||||
// dbgprintf_rows_float("yout", yout, QPC_Q*2, QPC_N);
|
||||
|
||||
// generate rayleigh distributed signal amplitudes -----------------
|
||||
float symamps[QPC_N * 2];
|
||||
np_normrnd_cpx(symamps, QPC_N, 0, sigman);
|
||||
|
||||
// dbgprintf_vector_float("symamps", symamps, QPC_N*2);
|
||||
|
||||
// normalize signal amps to unity ----------------------------------
|
||||
float pwr = 0.0f;
|
||||
float* psymamps = symamps;
|
||||
// compute sig power
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pwr += psymamps[0] * psymamps[0] + psymamps[1] * psymamps[1];
|
||||
psymamps += 2;
|
||||
}
|
||||
pwr = pwr / QPC_N;
|
||||
|
||||
// normalize to avg EsNo
|
||||
float norm = sqrtf(EsNo/pwr);
|
||||
psymamps = symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
psymamps[0] *= norm;
|
||||
psymamps[1] *= norm;
|
||||
psymamps += 2;
|
||||
}
|
||||
// dbgprintf_vector_float("symamps norm", symamps, QPC_N * 2);
|
||||
|
||||
// add signal amplitudes to noise -----------------------------------
|
||||
float *pyout = yout;
|
||||
psymamps= symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pyout[y[k]<<1] += psymamps[0];
|
||||
pyout[(y[k]<<1)+1] += psymamps[1];
|
||||
pyout += (QPC_Q*2);
|
||||
psymamps += 2;
|
||||
}
|
||||
|
||||
// dbgprintf_rows_float("s+n out", yout, QPC_Q * 2, QPC_N);
|
||||
|
||||
return;
|
||||
}
|
||||
void qpc_likelihoods(float* py, float* yout, float EsNo, float No)
|
||||
{
|
||||
// compute symbols likelihoods
|
||||
// (rayleigh channel)
|
||||
|
||||
int k, j;
|
||||
|
||||
float norm = EsNo / (EsNo + 1) / No;
|
||||
|
||||
// compute likelihoods from energies ----------------------------
|
||||
float* pybase;
|
||||
float* ppyout = yout;
|
||||
float normpwr;
|
||||
float normpwrmax;
|
||||
float pynorm;
|
||||
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
|
||||
// compute loglikelihoods and largest one from energies
|
||||
pybase = py + k * QPC_Q;
|
||||
normpwrmax = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
normpwr = norm * (ppyout[0] * ppyout[0] + ppyout[1] * ppyout[1]);
|
||||
pybase[j] = normpwr;
|
||||
if (normpwr > normpwrmax)
|
||||
normpwrmax = normpwr;
|
||||
ppyout += 2;
|
||||
}
|
||||
// subtract largest exponent
|
||||
pynorm = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
pybase[j] = expf(pybase[j] - normpwrmax);
|
||||
pynorm += pybase[j];
|
||||
}
|
||||
// normalize to probabilities
|
||||
pynorm = 1.0f / pynorm;
|
||||
for (j = 0; j < QPC_Q; j++)
|
||||
pybase[j] = pybase[j] * pynorm;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int k;
|
||||
|
||||
int NT = 20000; // number of transmissions to simultate
|
||||
float EbNodB = 3.7f; // Eb/No to simulate
|
||||
|
||||
|
||||
int kc = qpccode.k;
|
||||
int np = qpccode.np;
|
||||
float Rc = 1.0f * kc / np;
|
||||
float Tm = 10.0f; // message duration
|
||||
float Rb = 1.0f / Tm * (QPC_K - 2) * QPC_LOG2Q; // Bit rate assuming two symbols for CRC
|
||||
|
||||
float EsNodB = EbNodB + 10.0f * log10f(Rc * QPC_LOG2Q);
|
||||
|
||||
static unsigned char xin[QPC_K]; // input information symbols
|
||||
static unsigned char xdec[QPC_K]; // decoded information symbols
|
||||
static unsigned char y[QPC_N]; // encoded codeword
|
||||
static unsigned char ydec[QPC_N]; // decoded codeword
|
||||
|
||||
static float yout[QPC_N * QPC_Q * 2]; // channel complex amplitutes output
|
||||
static float py[QPC_N * QPC_Q]; // channel output probabilities
|
||||
|
||||
float EsNo = powf(10.0f, EsNodB / 10.0f);
|
||||
float No = 1.0f;
|
||||
|
||||
//JHT static float we;
|
||||
static float wer;
|
||||
|
||||
int kk;
|
||||
|
||||
printf("QPC Word Error Rate Test\n");
|
||||
printf("Polar Code (%d,%d) Q=%d for the Rayleigh channel\n", qpccode.np, qpccode.k, qpccode.q);
|
||||
printf("Eb/No = %.1f dB\n", EbNodB);
|
||||
printf("Es/No = %.1f dB\n", EsNodB);
|
||||
printf("Tmsg = %.1f s\n", Tm);
|
||||
printf("Bit Rate = %.1f bit/s\n", Rb);
|
||||
printf("SNR(2500) = %.1f dB\n\n", EbNodB + 10.0f * log10f(Rb/ 2500));
|
||||
|
||||
|
||||
for (k = 0; k < NT; k++) {
|
||||
|
||||
np_unidrnd_uc(xin, QPC_K, QPC_Q); // generate random information symbols
|
||||
|
||||
qpc_encode(y, xin); // encode
|
||||
|
||||
// compute channel outputs and probabilities
|
||||
|
||||
// Note that if the code is punctured (i.e. N=127)
|
||||
// the first codeword symbol must not be transmitted over the channel
|
||||
// Here, in order to avoid useless copies,
|
||||
// the vector of likelihoods py continues to be a QPC_N*QPC_Q vector of floats.
|
||||
// The first received symbol likelihoods should start always at offset QPC_Q.
|
||||
// The first QPC_Q positions of py will be ignored (and set) by the decoder.
|
||||
qpc_channel(yout, y, EsNo);
|
||||
|
||||
// The decoder can't estimate the EsNo easily
|
||||
// so we assume that in any case it is 5 dB
|
||||
float EsNoDec = 3.16;
|
||||
qpc_likelihoods(py, yout, EsNoDec, No);
|
||||
|
||||
qpc_decode(xdec, ydec, py); // decode
|
||||
|
||||
// count words in errors
|
||||
for (kk = 0; kk < QPC_K; kk++)
|
||||
if (xin[kk] ^ xdec[kk]) {
|
||||
wer += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// show the decoder performance every 200 codewords transmissions
|
||||
if ((k % 200) == 0 && k>0) {
|
||||
printf("k=%6d/%6d wer = %8.2E\n", k, NT, wer / k);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
}
|
||||
// show the final result
|
||||
printf("k=%6d/%6d wer = %8.2E\n", k, NT, wer / k);
|
||||
printf("\nAll done.\n");
|
||||
return 0;
|
||||
}
|
38
lib/superfox/qpc/qpc_mod.f90
Normal file
38
lib/superfox/qpc/qpc_mod.f90
Normal file
@ -0,0 +1,38 @@
|
||||
module qpc_mod
|
||||
interface
|
||||
integer(c_int32_t) function nhash2 (xin, length, initval) bind(C, &
|
||||
name="nhash2")
|
||||
use iso_c_binding, only: c_signed_char, c_int64_t, c_int32_t
|
||||
integer(c_int64_t), intent(in), value :: length
|
||||
integer(c_signed_char), intent(in) :: xin(length)
|
||||
integer(c_int32_t), intent(in), value :: initval
|
||||
end function nhash2
|
||||
end interface
|
||||
|
||||
interface
|
||||
subroutine qpc_encode(y, xin) bind(C,name="qpc_encode")
|
||||
use iso_c_binding, only: c_ptr, c_signed_char
|
||||
integer(c_signed_char), intent(out) :: y(127)
|
||||
integer(c_signed_char), intent(in) :: xin(50)
|
||||
end subroutine qpc_encode
|
||||
end interface
|
||||
|
||||
interface
|
||||
subroutine qpc_channel(yout, y, EsNo) bind(C,name="qpc_channel")
|
||||
use iso_c_binding, only: c_float_complex, c_float, c_signed_char
|
||||
complex(c_float_complex), intent(out) :: yout(128,128)
|
||||
integer(c_signed_char), intent(out) :: y(127)
|
||||
real(c_float), intent(in), value :: EsNo
|
||||
end subroutine qpc_channel
|
||||
end interface
|
||||
|
||||
interface
|
||||
subroutine qpc_decode(xdec, ydec, py) bind(C,name="qpc_decode")
|
||||
use iso_c_binding, only: c_float, c_signed_char
|
||||
real(c_float), intent(in) :: py(128,128)
|
||||
integer(c_signed_char), intent(out) :: ydec(127)
|
||||
integer(c_signed_char), intent(out) :: xdec(50)
|
||||
end subroutine qpc_decode
|
||||
end interface
|
||||
|
||||
end module qpc_mod
|
60
lib/superfox/qpc/qpc_n127k50q128.c
Normal file
60
lib/superfox/qpc/qpc_n127k50q128.c
Normal file
@ -0,0 +1,60 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_n127k50q128.c
|
||||
//
|
||||
// Defines the parameters of the q-ary polar code (127,50) Q=128
|
||||
// for WSJT-X
|
||||
// ------------------------------------------------------------------------------
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// WARNING:
|
||||
// This source is NOT free software and it is licensed only for use with WSJT-X.
|
||||
// No derived work is authorized to use this code without the written
|
||||
// permission of his author (Nico Palermo / IV3NWV) who owns all the rights
|
||||
// of this IP (intellectual property).
|
||||
//
|
||||
// This file is distributed ONLY for the purpose of documenting and making of
|
||||
// public domain the encoding scheme used in WSJT-X so that the transmitted
|
||||
// messages can be decoded by anybody.
|
||||
// Anyway this does not imply that one could use the following tables in a
|
||||
// derived work without an explicit and written authorization from his author.
|
||||
// Any unauthorized use, as for any intellectual property, is simply
|
||||
// illegal.
|
||||
// -------------------------------------------------------------------------------
|
||||
#include "np_qpc.h"
|
||||
qpccode_ds qpccode = {
|
||||
128, //n
|
||||
127, //np
|
||||
50, //k
|
||||
128, //q
|
||||
{
|
||||
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 16, 32, 17, 18, 64, 20,
|
||||
33, 34, 24, 7, 11, 36, 13, 19, 14, 65, 40, 21, 66, 22, 35, 68,
|
||||
25, 48, 37, 26, 72, 15, 38, 28, 41, 67, 23, 80, 42, 69, 49, 96,
|
||||
44, 27, 70, 50, 73, 39, 29, 52, 74, 30, 56, 81, 76, 43, 82, 84,
|
||||
97, 45, 71, 88, 98, 46, 100, 51, 104, 53, 75, 112, 54, 57, 99, 119,
|
||||
92, 77, 58, 117, 59, 83, 106, 31, 85, 108, 115, 116, 122, 125, 124, 91,
|
||||
61, 90, 89, 111, 78, 93, 94, 126, 86, 107, 110, 118, 121, 62, 120, 87,
|
||||
105, 55, 114, 60, 127, 63, 103, 101, 123, 95, 102, 47, 109, 79, 113, 0
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
},
|
||||
{
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
}
|
||||
};
|
115
lib/superfox/qpc/qpc_subs.c
Normal file
115
lib/superfox/qpc/qpc_subs.c
Normal file
@ -0,0 +1,115 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_test.cpp
|
||||
//
|
||||
// Test the WER performance of the QPC (127,50) Q=128 code
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "dbgprintf.h"
|
||||
#include "qpc_fwht.h"
|
||||
#include "np_qpc.h"
|
||||
|
||||
#include "nhash2.h"
|
||||
|
||||
// for random numbers generation and NCFSK Rayleigh channel simulation
|
||||
#include "np_rnd.h"
|
||||
void qpc_channel(float* yout, unsigned char* y, float EsNo)
|
||||
{
|
||||
// compute channel outputs amplitudes
|
||||
|
||||
int k;
|
||||
|
||||
// generate noise samples -----------------------------------------
|
||||
float sigman = 1.0f / sqrtf(2.0f);
|
||||
np_normrnd_cpx(yout, QPC_N * QPC_Q, 0, sigman);
|
||||
|
||||
// dbgprintf_rows_float("yout", yout, QPC_Q*2, QPC_N);
|
||||
|
||||
// generate rayleigh distributed signal amplitudes -----------------
|
||||
float symamps[QPC_N * 2];
|
||||
np_normrnd_cpx(symamps, QPC_N, 0, sigman);
|
||||
|
||||
// dbgprintf_vector_float("symamps", symamps, QPC_N*2);
|
||||
|
||||
// normalize signal amps to unity ----------------------------------
|
||||
float pwr = 0.0f;
|
||||
float* psymamps = symamps;
|
||||
// compute sig power
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pwr += psymamps[0] * psymamps[0] + psymamps[1] * psymamps[1];
|
||||
psymamps += 2;
|
||||
}
|
||||
pwr = pwr / QPC_N;
|
||||
|
||||
// normalize to avg EsNo
|
||||
float norm = sqrtf(EsNo/pwr);
|
||||
psymamps = symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
psymamps[0] *= norm;
|
||||
psymamps[1] *= norm;
|
||||
psymamps += 2;
|
||||
}
|
||||
// dbgprintf_vector_float("symamps norm", symamps, QPC_N * 2);
|
||||
|
||||
// add signal amplitudes to noise -----------------------------------
|
||||
float *pyout = yout;
|
||||
psymamps= symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pyout[y[k]<<1] += psymamps[0];
|
||||
pyout[(y[k]<<1)+1] += psymamps[1];
|
||||
pyout += (QPC_Q*2);
|
||||
psymamps += 2;
|
||||
}
|
||||
|
||||
// dbgprintf_rows_float("s+n out", yout, QPC_Q * 2, QPC_N);
|
||||
|
||||
return;
|
||||
}
|
||||
void qpc_likelihoods(float* py, float* yout, float EsNo, float No)
|
||||
{
|
||||
// compute symbols likelihoods
|
||||
// (rayleigh channel)
|
||||
|
||||
int k, j;
|
||||
|
||||
float norm = EsNo / (EsNo + 1) / No;
|
||||
|
||||
// compute likelihoods from energies ----------------------------
|
||||
float* pybase;
|
||||
float* ppyout = yout;
|
||||
float normpwr;
|
||||
float normpwrmax;
|
||||
float pynorm;
|
||||
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
|
||||
// compute loglikelihoods and largest one from energies
|
||||
pybase = py + k * QPC_Q;
|
||||
normpwrmax = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
normpwr = norm * (ppyout[0] * ppyout[0] + ppyout[1] * ppyout[1]);
|
||||
pybase[j] = normpwr;
|
||||
if (normpwr > normpwrmax)
|
||||
normpwrmax = normpwr;
|
||||
ppyout += 2;
|
||||
}
|
||||
// subtract largest exponent
|
||||
pynorm = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
pybase[j] = expf(pybase[j] - normpwrmax);
|
||||
pynorm += pybase[j];
|
||||
}
|
||||
// normalize to probabilities
|
||||
pynorm = 1.0f / pynorm;
|
||||
for (j = 0; j < QPC_Q; j++)
|
||||
pybase[j] = pybase[j] * pynorm;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
150
lib/superfox/qpc_decode2.f90
Normal file
150
lib/superfox/qpc_decode2.f90
Normal file
@ -0,0 +1,150 @@
|
||||
subroutine qpc_decode2(c0,fsync,ftol,xdec,ndepth,dth,damp,crc_ok, &
|
||||
snrsync,fbest,tbest,snr)
|
||||
|
||||
use qpc_mod
|
||||
|
||||
parameter(NMAX=15*12000,NFT=365,NZ=100)
|
||||
complex c0(NMAX) !Signal as received
|
||||
complex c(NMAX) !Signal as received
|
||||
real py(0:127,0:127) !Probabilities for received synbol values
|
||||
real py0(0:127,0:127) !Probabilities for strong signal
|
||||
real pyd(0:127,0:127) !Dithered values for py
|
||||
real s2(0:127,0:151) !Symbol spectra, including sync
|
||||
real s3(0:127,0:127) !Synchronized symbol spectra
|
||||
real No
|
||||
integer crc_chk,crc_sent
|
||||
integer*8 n47
|
||||
integer idf(NZ),idt(NZ)
|
||||
integer nseed(33)
|
||||
integer*1 xdec(0:49) !Decoded message
|
||||
integer*1 ydec(0:127) !Decoded symbols
|
||||
logical crc_ok
|
||||
integer maxdither(8)
|
||||
integer isync(24) !Symbol numbers for sync tones
|
||||
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80,83, &
|
||||
84,86,89/
|
||||
data n47/47/,maxdither/20,50,100,200,500,1000,2000,5000/
|
||||
data nseed/ &
|
||||
321278106, -658879006, 1239150429, -941466001, -698554454, &
|
||||
1136210962, 1633585627, 1261915021, -1134191465, -487888229, &
|
||||
2131958895, -1429290834, -1802468092, 1801346659, 1966248904, &
|
||||
402671397, -1961400750, -1567227835, 1895670987, -286583128, &
|
||||
-595933665, -1699285543, 1518291336, 1338407128, 838354404, &
|
||||
-2081343776, -1449416716, 1236537391, -133197638, 337355509, &
|
||||
-460640480, 1592689606, 0/
|
||||
|
||||
data idf/0, 0, -1, 0, -1, 1, 0, -1, 1, -2, 0, -1, 1, -2, 2, &
|
||||
0, -1, 1, -2, 2, -3, 0, -1, 1, -2, 2, -3, 3, 0, -1, &
|
||||
1, -2, 2, -3, 3, -4, 0, -1, 1, -2, 2, -3, 3, -4, 4, &
|
||||
0, -1, 1, -2, 2, -3, 3, -4, 4, -5, -1, 1, -2, 2, -3, &
|
||||
3, -4, 4, -5, 1, -2, 2, -3, 3, -4, 4, -5, -2, 2, -3, &
|
||||
3, -4, 4, -5, 2, -3, 3, -4, 4, -5, -3, 3, -4, 4, -5, &
|
||||
3, -4, 4, -5, -4, 4, -5, 4, -5, -5/
|
||||
data idt/0 , -1, 0, 1, -1, 0, -2, 1, -1, 0, 2, -2, 1, -1, 0, &
|
||||
-3, 2, -2, 1, -1, 0, 3, -3, 2, -2, 1, -1, 0, -4, 3, &
|
||||
-3, 2, -2, 1, -1, 0, 4, -4, 3, -3, 2, -2, 1, -1, 0, &
|
||||
-5, 4, -4, 3, -3, 2, -2, 1, -1, 0, -5, 4, -4, 3, -3, &
|
||||
2, -2, 1, -1, -5, 4, -4, 3, -3, 2, -2, 1, -5, 4, -4, &
|
||||
3, -3, 2, -2, -5, 4, -4, 3, -3, 2, -5, 4, -4, 3, -3, &
|
||||
-5, 4, -4, 3, -5, 4, -4, -5, 4, -5/
|
||||
|
||||
|
||||
fsample=12000.0
|
||||
baud=12000.0/1024.0
|
||||
nstype=1
|
||||
n47=47
|
||||
mask21=2**21 - 1
|
||||
crc_ok=.false.
|
||||
|
||||
call qpc_sync(c0,fsample,isync,fsync,ftol,f2,t2,snrsync)
|
||||
f00=1500.0 + f2
|
||||
t00=t2
|
||||
fbest=f00
|
||||
tbest=t00
|
||||
maxd=1
|
||||
if(ndepth.gt.0) maxd=maxdither(ndepth)
|
||||
maxft=NZ
|
||||
if(snrsync.lt.4.0 .or. ndepth.le.0) maxft=1
|
||||
do idith=1,maxft
|
||||
if(idith.ge.2) maxd=1
|
||||
deltaf=idf(idith)*0.5
|
||||
deltat=idt(idith)*8.0/1024.0
|
||||
f=f00+deltaf
|
||||
t=t00+deltat
|
||||
fshift=1500.0 - (f+baud) !Shift frequencies down by f + 1 bin
|
||||
call twkfreq2(c0,c,NMAX,fsample,fshift)
|
||||
a=1.0
|
||||
b=0.0
|
||||
do kk=1,4
|
||||
if(kk.eq.2) b=0.4
|
||||
if(kk.eq.3) b=0.5
|
||||
if(kk.eq.4) b=0.6
|
||||
call sfox_demod(c,1500.0,t,isync,s2,s3) !Compute s2 and s3
|
||||
|
||||
if(b.gt.0.0) then
|
||||
do j=0,127
|
||||
call smo121a(s3(:,j),128,a,b)
|
||||
enddo
|
||||
endif
|
||||
call pctile(s3,128*128,50,base3)
|
||||
s3=s3/base3
|
||||
|
||||
EsNoDec=3.16
|
||||
No=1.
|
||||
py0=s3
|
||||
call qpc_likelihoods2(py,s3,EsNoDec,No) !For weak signals
|
||||
|
||||
call random_seed(put=nseed)
|
||||
do kkk=1,maxd
|
||||
if(kkk.eq.1) then
|
||||
pyd=py0
|
||||
else
|
||||
pyd=0.
|
||||
if(kkk.gt.2) then
|
||||
call random_number(pyd)
|
||||
pyd=2.0*(pyd-0.5)
|
||||
endif
|
||||
where(py.gt.dth) pyd=0. !Don't perturb large likelihoods
|
||||
pyd=py*(1.0 + damp*pyd) !Compute dithered likelihood
|
||||
endif
|
||||
do j=0,127
|
||||
ss=sum(pyd(:,j))
|
||||
if(ss.gt.0.0) then
|
||||
pyd(:,j)=pyd(:,j)/ss
|
||||
else
|
||||
pyd(:,j)=0.0
|
||||
endif
|
||||
enddo
|
||||
|
||||
call qpc_decode(xdec,ydec,pyd)
|
||||
xdec=xdec(49:0:-1)
|
||||
crc_chk=iand(nhash2(xdec,n47,571),mask21) !Compute crc_chk
|
||||
crc_sent=128*128*xdec(47) + 128*xdec(48) + xdec(49)
|
||||
crc_ok=crc_chk.eq.crc_sent
|
||||
|
||||
if(crc_ok) then
|
||||
call qpc_snr(s3,ydec,snr)
|
||||
if(snr.lt.-16.5) crc_ok=.false.
|
||||
! write(61,3061) idith,kk,kkk,idf(idith),idt(idith),a,b
|
||||
!3061 format(5i5,2f8.3)
|
||||
return
|
||||
endif
|
||||
enddo !kk: dither of smoothing weights
|
||||
enddo !kkk: dither of probabilities
|
||||
enddo !idith: dither of frequency and time
|
||||
return
|
||||
end subroutine qpc_decode2
|
||||
|
||||
subroutine smo121a(x,nz,a,b)
|
||||
|
||||
real x(nz)
|
||||
fac=1.0/(a+2*b)
|
||||
x0=x(1)
|
||||
do i=2,nz-1
|
||||
x1=x(i)
|
||||
x(i)=fac*(a*x(i) + b*(x0+x(i+1)))
|
||||
x0=x1
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine smo121a
|
28
lib/superfox/qpc_likelihoods2.f90
Normal file
28
lib/superfox/qpc_likelihoods2.f90
Normal file
@ -0,0 +1,28 @@
|
||||
subroutine qpc_likelihoods2(py,s3,EsNo,No)
|
||||
|
||||
integer QQ,QN
|
||||
parameter(QQ=128,QN=128)
|
||||
real py(0:QQ-1,0:QN-1)
|
||||
real s3(0:QQ-1,0:QN-1)
|
||||
real No,norm,normpwr,normpwrmax
|
||||
|
||||
norm=(EsNo/(EsNo+1.0))/No
|
||||
|
||||
! Compute likelihoods for symbol values, from the symbol power spectra
|
||||
do k=0,QN-1
|
||||
normpwrmax=0.
|
||||
do j=0,QQ-1
|
||||
normpwr=norm*s3(j,k)
|
||||
py(j,k)=normpwr
|
||||
normpwrmax=max(normpwr,normpwrmax)
|
||||
enddo
|
||||
pynorm=0.
|
||||
do j=0,QQ-1
|
||||
py(j,k)=exp(py(j,k)-normpwrmax)
|
||||
pynorm=pynorm + py(j,k)
|
||||
enddo
|
||||
py(0:QQ-1,k)=py(0:QQ-1,k)/pynorm !Normalize to probabilities
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine qpc_likelihoods2
|
17
lib/superfox/qpc_snr.f90
Normal file
17
lib/superfox/qpc_snr.f90
Normal file
@ -0,0 +1,17 @@
|
||||
subroutine qpc_snr(s3,y,snr)
|
||||
|
||||
use qpc_mod
|
||||
! real s2(0:NQ-1,0:151) !Symbol spectra, including sync
|
||||
real s3(0:127,0:127) !Synchronized symbol spectra
|
||||
integer*1 y(0:127) !Encoded symbols
|
||||
! integer isync(24)
|
||||
|
||||
p=0.
|
||||
do j=1,127
|
||||
i=y(j)
|
||||
p=p + s3(i,j)
|
||||
enddo
|
||||
snr=db(p/127.0) - db(127.0) - 4.0
|
||||
|
||||
return
|
||||
end subroutine qpc_snr
|
101
lib/superfox/qpc_sync.f90
Normal file
101
lib/superfox/qpc_sync.f90
Normal file
@ -0,0 +1,101 @@
|
||||
subroutine qpc_sync(crcvd0,fsample,isync,fsync,ftol,f2,t2,snrsync)
|
||||
|
||||
parameter(N9SEC=9*12000,NMAX=15*12000,NDOWN=16,NZ=N9SEC/NDOWN)
|
||||
complex crcvd0(NMAX) !Signal as received
|
||||
complex c0(0:N9SEC-1) !For long FFT
|
||||
complex c1(0:NZ-1)
|
||||
complex c1sum(0:NZ-1)
|
||||
complex z
|
||||
real s(N9SEC/4)
|
||||
real p(-1125:1125)
|
||||
integer ipk(1)
|
||||
integer isync(24)
|
||||
|
||||
baud=12000.0/1024.0
|
||||
df2=fsample/N9SEC
|
||||
fac=1.0/N9SEC
|
||||
c0=fac*crcvd0(1:N9SEC)
|
||||
call four2a(c0,N9SEC,1,-1,1) !Forward c2c FFT
|
||||
iz=N9SEC/4
|
||||
do i=1,iz
|
||||
s(i)=real(c0(i))**2 + aimag(c0(i))**2
|
||||
enddo
|
||||
|
||||
do i=1,4 !Smooth the spectrum a bit
|
||||
call smo121(s,iz)
|
||||
enddo
|
||||
|
||||
ia=nint((fsync-ftol)/df2)
|
||||
ib=nint((fsync+ftol)/df2)
|
||||
ipk=maxloc(s(ia:ib))
|
||||
i0=ipk(1) + ia - 1
|
||||
f2=df2*i0-750.0 ! f2 is the offset from nominal 750 Hz.
|
||||
ia=nint(i0-baud/df2)
|
||||
ib=nint(i0+baud/df2)
|
||||
s1=0.0
|
||||
s0=0.0
|
||||
do i=ia,ib
|
||||
s0=s0+s(i)
|
||||
s1=s1+(i-i0)*s(i)
|
||||
enddo
|
||||
delta=s1/s0
|
||||
i0=nint(i0+delta)
|
||||
f2=i0*df2-750.0
|
||||
|
||||
c1=0.
|
||||
ia=nint(i0-baud/df2)
|
||||
ib=nint(i0+baud/df2)
|
||||
do i=ia,ib
|
||||
j=i-i0
|
||||
if(j.ge.0) c1(j)=c0(i)
|
||||
if(j.lt.0) c1(j+NZ)=c0(i)
|
||||
enddo
|
||||
call four2a(c1,NZ,1,1,1) !Reverse c2c FFT: back to time domain
|
||||
|
||||
c1sum(0)=c1(0)
|
||||
do i=1,NZ-1
|
||||
c1sum(i)=c1sum(i-1) + c1(i)
|
||||
enddo
|
||||
|
||||
nspsd=1024/NDOWN
|
||||
dt=NDOWN/12000.0
|
||||
lagmax=1.5/dt
|
||||
i0=nint(0.5*fsample/NDOWN) !Nominal start time is 0.5 s
|
||||
pmax=0.
|
||||
lagpk=0
|
||||
do lag=-lagmax,lagmax
|
||||
sp=0.
|
||||
do j=1,24
|
||||
i1=i0 + (isync(j)-1)*nspsd + lag
|
||||
i2=i1 + nspsd
|
||||
if(i1.lt.0 .or. i1.gt.NZ-1) cycle
|
||||
if(i2.lt.0 .or. i2.gt.NZ-1) cycle
|
||||
z=c1sum(i2)-c1sum(i1)
|
||||
sp=sp + real(z)**2 + aimag(z)**2
|
||||
enddo
|
||||
if(sp.gt.pmax) then
|
||||
pmax=sp
|
||||
lagpk=lag
|
||||
endif
|
||||
p(lag)=sp
|
||||
enddo
|
||||
|
||||
t2=lagpk*dt
|
||||
snrsync=0.
|
||||
sp=0.
|
||||
sq=0.
|
||||
nsum=0
|
||||
tsym=1024/12000.0
|
||||
do lag=-lagmax,lagmax
|
||||
t=(lag-lagpk)*dt
|
||||
if(abs(t).lt.tsym) cycle
|
||||
nsum=nsum+1
|
||||
sp=sp + p(lag)
|
||||
sq=sq + p(lag)*p(lag)
|
||||
enddo
|
||||
ave=sp/nsum
|
||||
rms=sqrt(sq/nsum-ave*ave)
|
||||
snrsync=(pmax-ave)/rms
|
||||
|
||||
return
|
||||
end subroutine qpc_sync
|
28
lib/superfox/ran1.f90
Normal file
28
lib/superfox/ran1.f90
Normal file
@ -0,0 +1,28 @@
|
||||
FUNCTION ran1(idum)
|
||||
INTEGER idum,IA,IM,IQ,IR,NTAB,NDIV
|
||||
REAL ran1,AM,EPS,RNMX
|
||||
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836, &
|
||||
NTAB=32,NDIV=1+(IM-1)/NTAB,EPS=1.2e-7,RNMX=1.-EPS)
|
||||
INTEGER j,k,iv(NTAB),iy
|
||||
SAVE iv,iy
|
||||
DATA iv /NTAB*0/, iy /0/
|
||||
if (idum.le.0.or.iy.eq.0) then
|
||||
idum=max(-idum,1)
|
||||
do j=NTAB+8,1,-1
|
||||
k=idum/IQ
|
||||
idum=IA*(idum-k*IQ)-IR*k
|
||||
if (idum.lt.0) idum=idum+IM
|
||||
if (j.le.NTAB) iv(j)=idum
|
||||
enddo
|
||||
iy=iv(1)
|
||||
endif
|
||||
k=idum/IQ
|
||||
idum=IA*(idum-k*IQ)-IR*k
|
||||
if (idum.lt.0) idum=idum+IM
|
||||
j=1+iy/NDIV
|
||||
iy=iv(j)
|
||||
iv(j)=idum
|
||||
ran1=min(AM*iy,RNMX)
|
||||
|
||||
return
|
||||
END FUNCTION ran1
|
17
lib/superfox/sfox_ana.f90
Normal file
17
lib/superfox/sfox_ana.f90
Normal file
@ -0,0 +1,17 @@
|
||||
subroutine sfox_ana(dd,npts,c0,npts2)
|
||||
|
||||
real dd(npts) !Raw data at 12000 Hz
|
||||
complex c0(0:npts2-1) !Complex data at 12000 Hz
|
||||
save
|
||||
|
||||
nfft1=npts
|
||||
nfft2=nfft1
|
||||
fac=2.0/(32767.0*nfft1)
|
||||
c0(0:npts-1)=fac*dd(1:npts)
|
||||
call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT
|
||||
c0(nfft2/2+1:nfft2-1)=0. !Remove negative frequencies
|
||||
c0(0)=0.5*c0(0) !Scale the DC term to 1/2
|
||||
call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT; c0 is analytic sig
|
||||
|
||||
return
|
||||
end subroutine sfox_ana
|
92
lib/superfox/sfox_assemble.f90
Normal file
92
lib/superfox/sfox_assemble.f90
Normal file
@ -0,0 +1,92 @@
|
||||
subroutine sfox_assemble(ntype,k,msg,mycall0,mygrid0,line)
|
||||
|
||||
! In subsequent calls, assemble all necessary information for a SuperFox
|
||||
! transmission.
|
||||
|
||||
character*120 line
|
||||
character*26 msg
|
||||
character*26 msg0,msg1,msg2(5),msg3(5)
|
||||
character*4 rpt2(5)
|
||||
character*6 hiscall(10)
|
||||
character*13 mycall0,mycall
|
||||
character*4 mygrid0,mygrid
|
||||
integer ntype !Message type: 0 Free Text
|
||||
! 1 CQ MyCall MyGrid
|
||||
! 2 Call_1 MyCall RR73
|
||||
! 3 Call_1 MyCall rpt
|
||||
integer nmsg(0:3) !Number of messages of type ntype
|
||||
data nmsg/0,0,0,0/,nbits/0/,ntx/0/,nb_mycall/0/
|
||||
save
|
||||
|
||||
if(mycall0(1:1).ne.' ') mycall=mycall0
|
||||
if(mygrid0(1:1).ne.' ') mygrid=mygrid0
|
||||
if(ntype.ge.1) nb_mycall=28 !### Allow for nonstandard MyCall ###
|
||||
if(sum(nmsg).eq.0) then
|
||||
hiscall=' '
|
||||
rpt2=' '
|
||||
endif
|
||||
|
||||
if(k.le.10) then
|
||||
if(ntype.eq.0) then
|
||||
if(nbits+nb_mycall.le.191) then !Enough room for a free text message?
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+142
|
||||
msg0=msg
|
||||
endif
|
||||
else if(ntype.eq.1) then
|
||||
if(nbits+nb_mycall.le.318) then !Enough room for a CQ ?
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+15
|
||||
msg1=msg
|
||||
endif
|
||||
else if(ntype.eq.2) then
|
||||
if(nbits+nb_mycall.le.305) then !Enough room for a RR73 message?
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+28
|
||||
j=nmsg(ntype)
|
||||
msg2(j)=msg
|
||||
i1=index(msg,' ')
|
||||
hiscall(j+5)=msg(1:i1-1)
|
||||
endif
|
||||
else if(ntype.eq.3) then
|
||||
if(nbits+nb_mycall.le.300) then !Enough room for a message with report?
|
||||
nmsg(ntype)=nmsg(ntype)+1
|
||||
nbits=nbits+33
|
||||
j=nmsg(ntype)
|
||||
msg3(j)=msg
|
||||
i1=index(msg,' ')
|
||||
hiscall(j)=msg(1:i1-1)
|
||||
i1=max(index(msg,'-'),index(msg,'+'))
|
||||
rpt2(j)=msg(i1:i1+3)
|
||||
endif
|
||||
endif
|
||||
return
|
||||
endif
|
||||
|
||||
if(k.ge.11) then
|
||||
! All pieces are now available. Put them into a command line for external
|
||||
! program sfox_tx.
|
||||
ntx=ntx+1 !Transmission number
|
||||
nbits=nbits+nb_mycall !Add bits for MyCall
|
||||
|
||||
if(nmsg(1).ge.1) then
|
||||
line=msg1
|
||||
else
|
||||
line=trim(mycall)
|
||||
do i=1,nmsg(3)
|
||||
line=trim(line)//' '//trim(hiscall(i))//' '//rpt2(i)
|
||||
enddo
|
||||
do i=1,nmsg(2)
|
||||
line=trim(line)//' '//trim(hiscall(i+5))
|
||||
enddo
|
||||
endif
|
||||
|
||||
nmsg=0
|
||||
nbits=0
|
||||
nb_mycall=0
|
||||
hiscall=' '
|
||||
rpt2=' '
|
||||
endif
|
||||
|
||||
return
|
||||
end subroutine sfox_assemble
|
79
lib/superfox/sfox_demod.f90
Normal file
79
lib/superfox/sfox_demod.f90
Normal file
@ -0,0 +1,79 @@
|
||||
subroutine sfox_demod(crcvd,f,t,isync,s2,s3)
|
||||
|
||||
use sfox_mod
|
||||
complex crcvd(NMAX) !Signal as received
|
||||
complex c(0:NSPS-1) !Work array, one symbol long
|
||||
real s2(0:NQ-1,0:151) !Symbol spectra, including sync
|
||||
real s3(0:NQ-1,0:NN) !Synchronized symbol spectra
|
||||
integer isync(24)
|
||||
integer ipk(1)
|
||||
integer hist1(0:NQ-1),hist2(0:NQ-1)
|
||||
|
||||
j0=nint(12000.0*(t+0.5))
|
||||
df=12000.0/NSPS
|
||||
i0=nint(f/df)-NQ/2
|
||||
k2=0
|
||||
s2(:,0)=0. !The punctured symbol
|
||||
s3(:,0)=0. !The punctured symbol
|
||||
|
||||
do n=1,NDS !Loop over all symbols
|
||||
jb=n*NSPS + j0
|
||||
ja=jb-NSPS+1
|
||||
k2=k2+1
|
||||
if(ja.lt.1 .or. jb.gt.NMAX) cycle
|
||||
c=crcvd(ja:jb)
|
||||
call four2a(c,NSPS,1,-1,1) !Compute symbol spectrum
|
||||
do i=0,NQ-1
|
||||
s2(i,k2)=real(c(i0+i))**2 + aimag(c(i0+i))**2
|
||||
enddo
|
||||
enddo
|
||||
|
||||
|
||||
call pctile(s2,NQ*151,50,base2)
|
||||
s2=s2/base2
|
||||
|
||||
hist1=0
|
||||
hist2=0
|
||||
do j=0,151
|
||||
ipk=maxloc(s2(1:NQ-1,j)) !Find the spectral peak
|
||||
i=ipk(1)-1
|
||||
hist1(i)=hist1(i)+1
|
||||
enddo
|
||||
|
||||
hist1(0)=0 !Don't treat sync tone as a birdie
|
||||
do i=0,123
|
||||
hist2(i)=sum(hist1(i:i+3))
|
||||
enddo
|
||||
|
||||
ipk=maxloc(hist1)
|
||||
i1=ipk(1)-1
|
||||
m1=maxval(hist1)
|
||||
ipk=maxloc(hist2)
|
||||
i2=ipk(1)-1
|
||||
m2=maxval(hist2)
|
||||
if(m1.gt.12) then
|
||||
do i=0,127
|
||||
if(hist1(i).gt.12) then
|
||||
s2(i,:)=1.0
|
||||
endif
|
||||
enddo
|
||||
endif
|
||||
|
||||
if(m2.gt.20) then
|
||||
if(i2.ge.1) i2=i2-1
|
||||
if(i2.gt.120) i2=120
|
||||
s2(i2:i2+7,:)=1.0
|
||||
endif
|
||||
|
||||
k3=0
|
||||
do n=1,NDS !Copy symbol spectra from s2 into s3
|
||||
if(any(isync(1:NS).eq.n)) cycle !Skip the sync symbols
|
||||
k3=k3+1
|
||||
s3(:,k3)=s2(:,n)
|
||||
enddo
|
||||
|
||||
call pctile(s3,NQ*NN,50,base3)
|
||||
s3=s3/base3
|
||||
|
||||
return
|
||||
end subroutine sfox_demod
|
86
lib/superfox/sfox_gen_gfsk.f90
Normal file
86
lib/superfox/sfox_gen_gfsk.f90
Normal file
@ -0,0 +1,86 @@
|
||||
subroutine sfox_gen_gfsk(idat,f0,isync,itone,cdat)
|
||||
|
||||
parameter (NSPS=1024)
|
||||
parameter (NDS=151)
|
||||
parameter (NN=127) !NN = number of code symbols
|
||||
parameter (NS=24) !NS = number of sync symbols
|
||||
parameter (NMAX=15*12000)
|
||||
parameter (NPTS=(NDS+2)*NSPS) !# of samples in waveform at 12000 samples/sec
|
||||
parameter (BT=8) !GFSK time-bandwidth product
|
||||
|
||||
complex cdat(NMAX)
|
||||
complex w, wstep
|
||||
integer idat(NN)
|
||||
integer isync(NS)
|
||||
integer itone(NDS)
|
||||
real*8 dt,twopi,phi,dphi_peak
|
||||
real*8 dphi(0:NPTS-1)
|
||||
real pulse(3*NSPS)
|
||||
logical first/.true./
|
||||
|
||||
save first,twopi,dt,hmod,dphi_peak,pulse
|
||||
|
||||
if(first) then
|
||||
twopi=8.d0*atan(1.0)
|
||||
fsample=12000.0
|
||||
dt=1.0/fsample
|
||||
hmod=1.0
|
||||
dphi_peak=twopi*hmod/real(NSPS)
|
||||
do i=1,3*NSPS
|
||||
tt=(i-1.5*NSPS)/real(NSPS)
|
||||
pulse(i)=gfsk_pulse(BT,tt)
|
||||
enddo
|
||||
first=.false.
|
||||
endif
|
||||
wave=0.
|
||||
|
||||
! Create the itone sequence: data symbols and interspersed sync symbols
|
||||
j=1
|
||||
k=0
|
||||
do i=1,NDS
|
||||
if(j.le.NS .and. i.eq.isync(j)) then
|
||||
if(j.lt.NS) j=j+1 !Index for next sync symbol
|
||||
itone(i)=0 !Insert sync symbol at tone 0
|
||||
else
|
||||
k=k+1
|
||||
itone(i)=idat(k) + 1 !Symbol value 0 is transmitted at tone 1, etc.
|
||||
endif
|
||||
enddo
|
||||
|
||||
! Generate the SuperFox waveform.
|
||||
|
||||
dphi=0.d0
|
||||
do j=1,NDS
|
||||
ib=(j-1)*NSPS
|
||||
ie=ib+3*NSPS-1
|
||||
dphi(ib:ie)=dphi(ib:ie)+dphi_peak*pulse(1:3*NSPS)*itone(j)
|
||||
enddo
|
||||
dphi(0:2*NSPS-1)=dphi(0:2*NSPS-1)+dphi_peak*itone(1)*pulse(NSPS+1:3*NSPS)
|
||||
dphi(NDS*NSPS:(NDS+2)*NSPS-1)=dphi(NDS*NSPS:(NDS+2)*NSPS-1)+dphi_peak*itone(NDS)*pulse(1:2*NSPS)
|
||||
|
||||
phi=0.d0
|
||||
dphi=dphi+twopi*f0*dt
|
||||
k=0
|
||||
do j=1,NSPS*(NDS+2)-1
|
||||
k=k+1
|
||||
cdat(k)=cmplx(cos(phi),sin(phi))
|
||||
phi=phi+dphi(j)
|
||||
enddo
|
||||
|
||||
! Add raised cosine ramps at the beginning and end of the waveform.
|
||||
! Since the modulator expects an integral number of symbols, dummy
|
||||
! symbols are added to the beginning and end of the waveform to
|
||||
! hold the ramps. All but nramp of the samples in each dummy
|
||||
! symbol will be zero.
|
||||
|
||||
nramp=NSPS/BT
|
||||
cdat(1:NSPS-nramp)=cmplx(0.0,0.0)
|
||||
cdat(NSPS-nramp+1:NSPS)=cdat(NSPS-nramp+1:NSPS) * &
|
||||
(1.0-cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
|
||||
k1=(NDS+1)*NSPS+1
|
||||
cdat(k1:k1+nramp-1)=cdat(k1:k1+nramp-1) * &
|
||||
(1.0+cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
|
||||
cdat(k1+nramp:NPTS)=0.0
|
||||
|
||||
return
|
||||
end subroutine sfox_gen_gfsk
|
73
lib/superfox/sfox_mod.f90
Normal file
73
lib/superfox/sfox_mod.f90
Normal file
@ -0,0 +1,73 @@
|
||||
module sfox_mod
|
||||
|
||||
parameter (NMAX=15*12000) !Samples in iwave (180,000)
|
||||
integer MM,NQ,NN,KK,NS,NDS,NFZ,NSPS,NSYNC,NZ,NFFT1
|
||||
real baud,tsym,bw
|
||||
|
||||
contains
|
||||
subroutine sfox_init(mm0,nn0,kk0,itu,fspread,delay,fsample,ns0)
|
||||
|
||||
character*2 itu
|
||||
integer isps(54)
|
||||
integer iloc(1)
|
||||
data isps/ 896, 960, 972, 980,1000,1008,1024,1029,1050,1080, &
|
||||
1120,1125,1134,1152,1176,1200,1215,1225,1250,1260, &
|
||||
1280,1296,1323,1344,1350,1372,1400,1440,1458,1470, &
|
||||
1500,1512,1536,1568,1575,1600,1620,1680,1701,1715, &
|
||||
1728,1750,1764,1792,1800,1875,1890,1920,1944,1960, &
|
||||
2000,2016,2025,2048/
|
||||
|
||||
MM=mm0 !Bits per symbol
|
||||
NQ=2**MM !Q, number of MFSK tones
|
||||
NN=nn0 !Codeword length
|
||||
KK=kk0 !Number of information symbols
|
||||
NS=ns0 !Number of sync symbols
|
||||
NDS=NN+NS !Total number of channel symbols
|
||||
NFZ=3 !First zero
|
||||
|
||||
jsps=nint(12.8*fsample/NDS)
|
||||
iloc=minloc(abs(isps-jsps))
|
||||
NSPS=isps(iloc(1)) !Samples per symbol
|
||||
NSYNC=NS*NSPS !Samples in sync waveform
|
||||
NZ=NSPS*NDS !Samples in full Tx waveform
|
||||
NFFT1=2*NSPS !Length of FFTs for symbol spectra
|
||||
|
||||
baud=fsample/NSPS
|
||||
tsym=1.0/baud
|
||||
bw=NQ*baud
|
||||
|
||||
fspread=0.0
|
||||
delay=0.0
|
||||
if(itu.eq.'LQ') then
|
||||
fspread=0.5
|
||||
delay=0.5
|
||||
else if(itu.eq.'LM') then
|
||||
fspread=1.5
|
||||
delay=2.0
|
||||
else if(itu.eq.'LD') then
|
||||
fspread=10.0
|
||||
delay=6.0
|
||||
else if(itu.eq.'MQ') then
|
||||
fspread=0.1
|
||||
delay=0.5
|
||||
else if(itu.eq.'MM') then
|
||||
fspread=0.5
|
||||
delay=1.0
|
||||
else if(itu.eq.'MD') then
|
||||
fspread=1.0
|
||||
delay=2.0
|
||||
else if(itu.eq.'HQ') then
|
||||
fspread=0.5
|
||||
delay=1.0
|
||||
else if(itu.eq.'HM') then
|
||||
fspread=10.0
|
||||
delay=3.0
|
||||
else if(itu.eq.'HD') then
|
||||
fspread=30.0
|
||||
delay=7.0
|
||||
endif
|
||||
|
||||
return
|
||||
end subroutine sfox_init
|
||||
|
||||
end module sfox_mod
|
178
lib/superfox/sfox_pack.f90
Normal file
178
lib/superfox/sfox_pack.f90
Normal file
@ -0,0 +1,178 @@
|
||||
subroutine sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
|
||||
|
||||
use qpc_mod
|
||||
use packjt
|
||||
use packjt77
|
||||
use julian
|
||||
parameter (NQU1RKS=203514677)
|
||||
integer*8 n47,n58,now
|
||||
integer*1 xin(0:49) !Packed message as 7-bit symbols
|
||||
logical*1 bMoreCQs,bSendMsg
|
||||
logical text,allz
|
||||
character*120 line !SuperFox message pieces
|
||||
character*10 ckey
|
||||
character*26 freeTextMsg
|
||||
character*13 w(16)
|
||||
character*11 c11
|
||||
character*329 msgbits !Packed message as bits
|
||||
character*38 c
|
||||
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
|
||||
|
||||
i0=index(line,'/')
|
||||
i3=0 !Default to i3=0, standard message
|
||||
nh1=0 !Number of Hound calls with RR73
|
||||
nh2=0 !Number of Hound calls with report
|
||||
|
||||
! Split the command line into words
|
||||
w=' '
|
||||
i1=1
|
||||
do j=1,16
|
||||
do i=i1,min(i1+12,120)
|
||||
if(line(i:i).eq.' ') exit
|
||||
enddo
|
||||
i2=i-1
|
||||
w(j)=line(i1:i2)
|
||||
do i=i2+1,120
|
||||
if(line(i:i).ne.' ') exit
|
||||
enddo
|
||||
i1=i
|
||||
if(i1.ge.120) exit
|
||||
enddo
|
||||
nwords=j
|
||||
|
||||
do i=1,nwords
|
||||
if(w(i)(1:1).eq.' ') then
|
||||
nwords=i-1
|
||||
exit
|
||||
endif
|
||||
enddo
|
||||
|
||||
do i=1,329 !Set all msgbits to '0'
|
||||
msgbits(i:i)='0'
|
||||
enddo
|
||||
|
||||
now=itime8()/30
|
||||
now=30*now
|
||||
read(ckey(5:10),*) notp
|
||||
|
||||
write(msgbits(307:326),'(b20.20)') notp !Insert the digital signature
|
||||
|
||||
if(w(1)(1:3).eq.'CQ ') then
|
||||
i3=3
|
||||
c11=w(2)(1:11)
|
||||
n58=0
|
||||
do i=1,11
|
||||
n58=n58*38 + index(c,c11(i:i)) - 1
|
||||
enddo
|
||||
write(msgbits(1:58),'(b58.58)') n58
|
||||
call packgrid(w(3)(1:4),n15,text)
|
||||
write(msgbits(59:73),'(b15.15)') n15
|
||||
write(msgbits(327:329),'(b3.3)') i3 !Message type i3=3
|
||||
go to 800
|
||||
endif
|
||||
|
||||
call pack28(w(1),n28) !Fox call
|
||||
write(msgbits(1:28),'(b28.28)') n28
|
||||
|
||||
! Default report is RR73 if we're also sending a free text message.
|
||||
if(bSendMsg) msgbits(141:160)='11111111111111111111'
|
||||
|
||||
j=29
|
||||
|
||||
! Process callsigns with RR73
|
||||
do i=2,nwords
|
||||
if(w(i)(1:1).eq.'+' .or. w(i)(1:1).eq.'-') cycle !Skip report words
|
||||
i1=min(i+1,nwords)
|
||||
if(w(i1)(1:1) .eq.'+' .or. w(i1)(1:1).eq.'-') cycle !Skip if i+1 is report
|
||||
call pack28(w(i),n28)
|
||||
write(msgbits(j:j+27),1002) n28 !Insert this call for RR73 message
|
||||
1002 format(b28.28)
|
||||
j=j+28
|
||||
nh1=nh1+1
|
||||
if(nh1.ge.5) exit !At most 5 RR73 callsigns
|
||||
enddo
|
||||
|
||||
! Process callsigns with a report
|
||||
j=169
|
||||
j2=281
|
||||
if(bSendMsg) then
|
||||
i3=2
|
||||
j=29 + 28*nh1
|
||||
j2=141 + 5*nh1
|
||||
endif
|
||||
|
||||
do i=2,nwords
|
||||
i1=min(i+1,nwords)
|
||||
if(w(i1)(1:1).eq.'+' .or. w(i1)(1:1).eq.'-') then
|
||||
call pack28(w(i),n28)
|
||||
write(msgbits(j:j+27),1002) n28 !Insert this call
|
||||
read(w(i1),*) n !Valid reports are -18 to +12, plus RR73
|
||||
if(n.lt.-18) n=-18 !... Even numbers only ...
|
||||
if(n.gt.12) n=12
|
||||
write(msgbits(j2:j2+4),1000) n+18
|
||||
1000 format(b5.5)
|
||||
w(i1)=""
|
||||
nh2=nh2+1
|
||||
! print*,'C',i3,i,j,n,w(i)
|
||||
if( nh2.ge.4 .or. (nh1+nh2).ge.9 ) exit ! At most 4 callsigns w/reports
|
||||
j=j+28
|
||||
j2=j2+5
|
||||
endif
|
||||
enddo
|
||||
|
||||
800 if(bSendMsg) then
|
||||
i1=26
|
||||
do i=1,26
|
||||
if(freeTextMsg(i:i).ne.' ') i1=i
|
||||
enddo
|
||||
do i=i1+1,26
|
||||
freeTextMsg(i:i)='.'
|
||||
enddo
|
||||
if(i3.eq.3) then
|
||||
call packtext77(freeTextMsg(1:13),msgbits(74:144))
|
||||
call packtext77(freeTextMsg(14:26),msgbits(145:215))
|
||||
elseif(i3.eq.2) then
|
||||
call packtext77(freeTextMsg(1:13),msgbits(161:231))
|
||||
call packtext77(freeTextMsg(14:26),msgbits(232:302))
|
||||
endif
|
||||
write(msgbits(327:329),'(b3.3)') i3 !Message type i3=2
|
||||
endif
|
||||
if(bMoreCQs) msgbits(306:306)='1'
|
||||
|
||||
read(msgbits(327:329),'(b3)') i3
|
||||
if(i3.eq.0) then
|
||||
do i=1,9
|
||||
i0=i*28 + 1
|
||||
read(msgbits(i0:i0+27),'(b28)') n28
|
||||
if(n28.eq.0) write(msgbits(i0:i0+27),'(b28.28)') NQU1RKS
|
||||
enddo
|
||||
else if(i3.eq.3) then
|
||||
allz=.true.
|
||||
do i=0,6
|
||||
i0=i*32 + 74
|
||||
read(msgbits(i0:i0+31),'(b32)') n32
|
||||
if(n32.ne.0) allz=.false.
|
||||
enddo
|
||||
if(allz) then
|
||||
do i=0,6
|
||||
i0=i*32 + 74
|
||||
write(msgbits(i0:i0+31),'(b32.32)') NQU1RKS
|
||||
enddo
|
||||
endif
|
||||
endif
|
||||
|
||||
read(msgbits,1004) xin(0:46)
|
||||
1004 format(47b7)
|
||||
|
||||
mask21=2**21 - 1
|
||||
n47=47
|
||||
ncrc21=iand(nhash2(xin,n47,571),mask21) !Compute 21-bit CRC
|
||||
xin(47)=ncrc21/16384 !First 7 of 21 bits
|
||||
xin(48)=iand(ncrc21/128,127) !Next 7 bits
|
||||
xin(49)=iand(ncrc21,127) !Last 7 bits
|
||||
|
||||
xin=xin(49:0:-1) !Reverse the symbol order
|
||||
! NB: CRC is now in first three symbols, fox call in the last four.
|
||||
|
||||
return
|
||||
end subroutine sfox_pack
|
55
lib/superfox/sfox_prob.f90
Normal file
55
lib/superfox/sfox_prob.f90
Normal file
@ -0,0 +1,55 @@
|
||||
subroutine sfox_prob(s3,rxdat,rxprob,rxdat2,rxprob2)
|
||||
|
||||
! Demodulate the 64-bin spectra for each of 63 symbols in a frame.
|
||||
|
||||
! Parameters
|
||||
! rxdat most reliable symbol value
|
||||
! rxdat2 second most likely symbol value
|
||||
! rxprob probability that rxdat was the transmitted value
|
||||
! rxprob2 probability that rxdat2 was the transmitted value
|
||||
|
||||
use sfox_mod
|
||||
implicit real*8 (a-h,o-z)
|
||||
real*4 s3(0:NQ-1,0:NN-1)
|
||||
integer rxdat(0:NN-1),rxprob(0:NN-1),rxdat2(0:NN-1),rxprob2(0:NN-1)
|
||||
|
||||
afac=1.1
|
||||
! scale=255.999
|
||||
scale=2047.999
|
||||
|
||||
! Compute average spectral value
|
||||
ave=sum(s3)/(NQ*ND)
|
||||
i1=1 !Silence warning
|
||||
i2=1
|
||||
|
||||
! Compute probabilities for most reliable symbol values
|
||||
do j=0,NN-1 !Loop over all symbols
|
||||
s1=-1.e30
|
||||
psum=0.
|
||||
do i=0,NQ-1 !Loop over frequency bins
|
||||
x=min(afac*s3(i,j)/ave,50.d0)
|
||||
psum=psum+s3(i,j)
|
||||
if(s3(i,j).gt.s1) then
|
||||
s1=s3(i,j) !Find max signal+noise power
|
||||
i1=i !Find most reliable symbol value
|
||||
endif
|
||||
enddo
|
||||
if(psum.eq.0.0) psum=1.e-6 !Guard against zero signal+noise
|
||||
|
||||
s2=-1.e30
|
||||
do i=0,NQ-1
|
||||
if(i.ne.i1 .and. s3(i,j).gt.s2) then
|
||||
s2=s3(i,j) !Second largest signal+noise power
|
||||
i2=i !Bin number for second largest power
|
||||
endif
|
||||
enddo
|
||||
p1=s1/psum !p1, p2 are symbol metrics for ftrsd
|
||||
p2=s2/psum
|
||||
rxdat(j)=i1
|
||||
rxdat2(j)=i2
|
||||
rxprob(j)=scale*p1 !Scaled probabilities, 0 - 255
|
||||
rxprob2(j)=scale*p2
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine sfox_prob
|
213
lib/superfox/sfox_remove_ft8.f90
Normal file
213
lib/superfox/sfox_remove_ft8.f90
Normal file
@ -0,0 +1,213 @@
|
||||
subroutine sfox_remove_ft8(dd,npts)
|
||||
use packjt77
|
||||
include 'ft8_params.f90'
|
||||
parameter (MAXCAND=100)
|
||||
parameter (NP2=2812)
|
||||
integer itone(NN)
|
||||
integer iloc(1), ip(1)
|
||||
integer icos7(0:6)
|
||||
integer graymap(0:7)
|
||||
integer*1 cw(174),apmask(174)
|
||||
integer*1 message91(91)
|
||||
integer*1 message77(77)
|
||||
|
||||
character*77 c77
|
||||
character*37 msg37
|
||||
|
||||
real s8(0:7,NN)
|
||||
real s2(0:7)
|
||||
real ss(9)
|
||||
real candidate(3,MAXCAND)
|
||||
real sbase(NH1)
|
||||
real dd(npts)
|
||||
real bmeta(174),bmetd(174)
|
||||
real llra(174),llrd(174)
|
||||
complex cd0(0:3199)
|
||||
complex csymb(32)
|
||||
complex ctwk(32)
|
||||
complex cs(0:7,NN)
|
||||
data icos7/3,1,4,0,6,5,2/
|
||||
logical first,newdat
|
||||
logical one(0:7,0:2)
|
||||
logical unpk77_success
|
||||
data first/.true./
|
||||
data graymap/0,1,3,2,5,6,4,7/
|
||||
save one,first,twopi
|
||||
|
||||
if(first) then
|
||||
one=.false.
|
||||
do i=0,7
|
||||
do j=0,2
|
||||
if(iand(i,2**j).ne.0) one(i,j)=.true.
|
||||
enddo
|
||||
enddo
|
||||
first=.false.
|
||||
twopi=8.0*atan(1.0)
|
||||
endif
|
||||
|
||||
fs2=12000.0/NDOWN
|
||||
dt2=1.0/fs2
|
||||
nfa=500
|
||||
nfb=2500
|
||||
syncmin=1.5
|
||||
nfqso=750
|
||||
call sync8(dd,npts,nfa,nfb,syncmin,nfqso,MAXCAND,candidate,ncand,sbase)
|
||||
newdat=.true.
|
||||
do icand=1,ncand
|
||||
f1=candidate(1,icand)
|
||||
xdt=candidate(2,icand)
|
||||
xbase=10.0**(0.1*(sbase(nint(f1/3.125))-40.0))
|
||||
call ft8_downsample(dd,newdat,f1,cd0)
|
||||
newdat=.false.
|
||||
i0=nint((xdt+0.5)*fs2)
|
||||
smax=0.0
|
||||
do idt=i0-10,i0+10
|
||||
call sync8d(cd0,idt,ctwk,0,sync)
|
||||
if(sync.gt.smax) then
|
||||
smax=sync
|
||||
ibest=idt
|
||||
endif
|
||||
enddo
|
||||
|
||||
smax=0.0
|
||||
delfbest=0.0
|
||||
do ifr=-5,5 !Search over +/- 2.5 Hz
|
||||
delf=ifr*0.5
|
||||
dphi=twopi*delf*dt2
|
||||
phi=0.0
|
||||
do i=1,32
|
||||
ctwk(i)=cmplx(cos(phi),sin(phi))
|
||||
phi=mod(phi+dphi,twopi)
|
||||
enddo
|
||||
call sync8d(cd0,ibest,ctwk,1,sync)
|
||||
if( sync .gt. smax ) then
|
||||
smax=sync
|
||||
delfbest=delf
|
||||
endif
|
||||
enddo
|
||||
|
||||
f1=f1+delfbest !Improved estimate of DF
|
||||
|
||||
call ft8_downsample(dd,newdat,f1,cd0) !Mix f1 to baseband and downsample
|
||||
|
||||
smax=0.0
|
||||
do idt=-4,4 !Search over +/- one quarter symbol
|
||||
call sync8d(cd0,ibest+idt,ctwk,0,sync)
|
||||
ss(idt+5)=sync
|
||||
enddo
|
||||
smax=maxval(ss)
|
||||
iloc=maxloc(ss)
|
||||
ibest=iloc(1)-5+ibest
|
||||
xdt=(ibest-1)*dt2
|
||||
sync=smax
|
||||
|
||||
do k=1,NN
|
||||
i1=ibest+(k-1)*32
|
||||
csymb=cmplx(0.0,0.0)
|
||||
if( i1.ge.0 .and. i1+31 .le. NP2-1 ) csymb=cd0(i1:i1+31)
|
||||
call four2a(csymb,32,1,-1,1)
|
||||
cs(0:7,k)=csymb(1:8)/1e3
|
||||
s8(0:7,k)=abs(csymb(1:8))
|
||||
enddo
|
||||
|
||||
! sync quality check
|
||||
is1=0
|
||||
is2=0
|
||||
is3=0
|
||||
do k=1,7
|
||||
ip=maxloc(s8(:,k))
|
||||
if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1
|
||||
ip=maxloc(s8(:,k+36))
|
||||
if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1
|
||||
ip=maxloc(s8(:,k+72))
|
||||
if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1
|
||||
enddo
|
||||
! hard sync sum - max is 21
|
||||
nsync=is1+is2+is3
|
||||
if(nsync .le. 6) then ! bail out
|
||||
nbadcrc=1
|
||||
cycle
|
||||
endif
|
||||
|
||||
nsym=1
|
||||
nt=2**(3*nsym)
|
||||
do ihalf=1,2
|
||||
do k=1,29,nsym
|
||||
if(ihalf.eq.1) ks=k+7
|
||||
if(ihalf.eq.2) ks=k+43
|
||||
amax=-1.0
|
||||
do i=0,nt-1
|
||||
i3=iand(i,7)
|
||||
s2(i)=abs(cs(graymap(i3),ks))
|
||||
enddo
|
||||
i32=1+(k-1)*3+(ihalf-1)*87
|
||||
ibmax=2
|
||||
do ib=0,ibmax
|
||||
bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - &
|
||||
maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib))
|
||||
if(i32+ib .gt.174) cycle
|
||||
bmeta(i32+ib)=bm
|
||||
den=max(maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)), &
|
||||
maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)))
|
||||
if(den.gt.0.0) then
|
||||
cm=bm/den
|
||||
else ! erase it
|
||||
cm=0.0
|
||||
endif
|
||||
bmetd(i32+ib)=cm
|
||||
enddo
|
||||
enddo
|
||||
enddo
|
||||
|
||||
call normalizebmet(bmeta,174)
|
||||
call normalizebmet(bmetd,174)
|
||||
|
||||
scalefac=2.83
|
||||
llra=scalefac*bmeta
|
||||
llrd=scalefac*bmetd
|
||||
|
||||
cw=0
|
||||
dmin=0
|
||||
norder=2
|
||||
maxosd=-1
|
||||
Keff=91
|
||||
apmask=0
|
||||
message91=0
|
||||
cw=0
|
||||
call decode174_91(llra,Keff,maxosd,norder,apmask,message91,cw, &
|
||||
ntype,nharderrors,dmin)
|
||||
|
||||
if(nharderrors.ge.0) then
|
||||
message77=message91(1:77)
|
||||
else
|
||||
cycle
|
||||
endif
|
||||
|
||||
if(count(cw.eq.0).eq.174) cycle
|
||||
|
||||
write(c77,'(77i1)') message77
|
||||
read(c77(72:74),'(b3)') n3
|
||||
read(c77(75:77),'(b3)') i3
|
||||
if(i3.gt.5 .or. (i3.eq.0.and.n3.gt.6)) cycle
|
||||
if(i3.eq.0 .and. n3.eq.2) cycle
|
||||
|
||||
call unpack77(c77,1,msg37,unpk77_success)
|
||||
! write(77,*) 'FT8 interference: ',msg37
|
||||
if(.not.unpk77_success) cycle
|
||||
! Message structure: S7 D29 S7 D29 S7
|
||||
itone(1:7)=icos7
|
||||
itone(36+1:36+7)=icos7
|
||||
itone(NN-6:NN)=icos7
|
||||
k=7
|
||||
do j=1,ND
|
||||
i=3*j -2
|
||||
k=k+1
|
||||
if(j.eq.30) k=k+7
|
||||
indx=cw(i)*4 + cw(i+1)*2 + cw(i+2)
|
||||
itone(k)=graymap(indx)
|
||||
enddo
|
||||
call subtractft8(dd,itone,f1,xdt,.true.)
|
||||
! return
|
||||
enddo
|
||||
return
|
||||
end subroutine sfox_remove_ft8
|
95
lib/superfox/sfox_remove_tone.f90
Normal file
95
lib/superfox/sfox_remove_tone.f90
Normal file
@ -0,0 +1,95 @@
|
||||
subroutine sfox_remove_tone(c0,fsync)
|
||||
|
||||
parameter (NMAX=15*12000)
|
||||
parameter (NFILT=8000)
|
||||
complex c0(NMAX)
|
||||
complex cwindow(15*12000)
|
||||
complex cref(NMAX)
|
||||
complex cfilt(NMAX)
|
||||
real window(-NFILT/2:NFILT/2)
|
||||
! real endcorrection(NFILT/2+1)
|
||||
real s(NMAX/4)
|
||||
integer ipk(1)
|
||||
logical first
|
||||
data first/.true./
|
||||
save cwindow,first,pi
|
||||
|
||||
if(first) then
|
||||
pi=4.0*atan(1.0)
|
||||
fac=1.0/float(NMAX)
|
||||
sumw=0.0
|
||||
do j=-NFILT/2,NFILT/2
|
||||
window(j)=cos(pi*j/NFILT)**2
|
||||
sumw=sumw+window(j)
|
||||
enddo
|
||||
cwindow=0.
|
||||
cwindow(1:NFILT+1)=window/sumw
|
||||
cwindow=cshift(cwindow,NFILT/2+1)
|
||||
call four2a(cwindow,NMAX,1,-1,1)
|
||||
cwindow=cwindow*fac ! frequency domain smoothing filter
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
fsample=12000.0
|
||||
baud=fsample/1024.0
|
||||
df=fsample/NMAX
|
||||
fac=1.0/NMAX
|
||||
|
||||
do it=1,1 ! Remove 1 tone, if present
|
||||
cfilt=fac*c0
|
||||
call four2a(cfilt,NMAX,1,-1,1) ! fourier transform of input data
|
||||
iz=NMAX/4
|
||||
do i=1,iz
|
||||
s(i)=real(cfilt(i))**2 + aimag(cfilt(i))**2
|
||||
enddo
|
||||
|
||||
ia=nint((fsync-50.0)/df)
|
||||
ib=nint((fsync+1500.0+50.0)/df)
|
||||
ipk=maxloc(s(ia:ib))
|
||||
i0=ipk(1) + ia - 1
|
||||
|
||||
nbaud=nint(baud/df)
|
||||
ia=i0-nbaud
|
||||
ib=i0+nbaud
|
||||
s0=0.0
|
||||
s1=0.0
|
||||
s2=0.0
|
||||
do i=ia,ib
|
||||
s0=s0+s(i)
|
||||
s1=s1+(i-i0)*s(i)
|
||||
enddo
|
||||
delta=s1/s0
|
||||
i0=nint(i0+delta)
|
||||
f2=i0*df
|
||||
|
||||
ia=i0-nbaud
|
||||
ib=i0+nbaud
|
||||
do i=ia,ib
|
||||
s2=s2 + s(i)*(i-i0)**2
|
||||
enddo
|
||||
sigma=sqrt(s2/s0)*df
|
||||
|
||||
! write(*,*) 'frequency, spectral width ',f2,sigma
|
||||
if(sigma .gt. 2.5) exit
|
||||
! write(*,*) 'remove_tone - frequency: ',f2
|
||||
|
||||
dt=1.0/fsample
|
||||
do i=1, NMAX
|
||||
arg=2*pi*f2*i*dt
|
||||
cref(i)=cmplx(cos(arg),sin(arg))
|
||||
enddo
|
||||
cfilt=c0*conjg(cref) ! baseband to be filtered
|
||||
call four2a(cfilt,NMAX,1,-1,1)
|
||||
cfilt=cfilt*cwindow
|
||||
call four2a(cfilt,NMAX,1,1,1)
|
||||
|
||||
nframe=50*3456
|
||||
do i=1,nframe
|
||||
cref(i)=cfilt(i)*cref(i)
|
||||
c0(i)=c0(i)-cref(i)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
return
|
||||
|
||||
end subroutine sfox_remove_tone
|
119
lib/superfox/sfox_unpack.f90
Normal file
119
lib/superfox/sfox_unpack.f90
Normal file
@ -0,0 +1,119 @@
|
||||
subroutine sfox_unpack(nutc,x,nsnr,f0,dt0,foxcall,notp)
|
||||
|
||||
use packjt77
|
||||
parameter (NQU1RKS=203514677)
|
||||
integer*1 x(0:49)
|
||||
integer*8 n58
|
||||
logical success
|
||||
character*336 msgbits
|
||||
character*22 msg(10) !### only msg(1) is used ??? ###
|
||||
character*13 foxcall,c13
|
||||
character*10 ssignature
|
||||
character*4 crpt(5),grid4
|
||||
character*26 freeTextMsg
|
||||
character*38 c
|
||||
logical use_otp
|
||||
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
|
||||
|
||||
ncq=0
|
||||
if (notp.eq.0) then
|
||||
use_otp = .FALSE.
|
||||
else
|
||||
use_otp = .TRUE.
|
||||
endif
|
||||
write(msgbits,1000) x(0:46)
|
||||
1000 format(47b7.7)
|
||||
read(msgbits(327:329),'(b6)') i3 !Message type
|
||||
read(msgbits(1:28),'(b28)') n28 !Standard Fox call
|
||||
call unpack28(n28,foxcall,success)
|
||||
|
||||
if(i3.eq.1) then !Compound Fox callsign
|
||||
! read(msgbits(87:101),'(b15)') n15
|
||||
! call unpackgrid(n15,grid4)
|
||||
! msg(1)='CQ '//trim(foxcall)//' '//grid4
|
||||
! write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(1))
|
||||
! go to 100
|
||||
else if(i3.eq.2) then !Up to 4 Hound calls and free text
|
||||
call unpacktext77(msgbits(161:231),freeTextMsg(1:13))
|
||||
call unpacktext77(msgbits(232:302),freeTextMsg(14:26))
|
||||
do i=26,1,-1
|
||||
if(freeTextMsg(i:i).ne.'.') exit
|
||||
freeTextMsg(i:i)=' '
|
||||
enddo
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),freeTextMsg
|
||||
1100 format(i6.6,i4,f5.1,i5,1x,"~",2x,a)
|
||||
else if(i3.eq.3) then !CQ FoxCall Grid
|
||||
read(msgbits(1:58),'(b58)') n58 !FoxCall
|
||||
do i=11,1,-1
|
||||
j=mod(n58,38)+1
|
||||
foxcall(i:i)=c(j:j)
|
||||
n58=n58/38
|
||||
enddo
|
||||
foxcall(12:13)=' '
|
||||
read(msgbits(59:73),'(b15)') n15
|
||||
call unpackgrid(n15,grid4)
|
||||
msg(1)='CQ '//trim(foxcall)//' '//grid4
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(1))
|
||||
read(msgbits(74:105),'(b32)') n32
|
||||
if(n32.eq.NQU1RKS) go to 100
|
||||
call unpacktext77(msgbits(74:144),freeTextMsg(1:13))
|
||||
call unpacktext77(msgbits(145:215),freeTextMsg(14:26))
|
||||
do i=26,1,-1
|
||||
if(freeTextMsg(i:i).ne.'.') exit
|
||||
freeTextMsg(i:i)=' '
|
||||
enddo
|
||||
if(len(trim(freeTextMsg)).gt.0) write(*,1100) nutc,nsnr,dt0,&
|
||||
nint(f0),freeTextMsg
|
||||
go to 100
|
||||
endif
|
||||
|
||||
j=281
|
||||
iz=4 !Max number of reports
|
||||
if(i3.eq.2) j=141
|
||||
do i=1,iz !Extract the reports
|
||||
read(msgbits(j:j+4),'(b5)') n
|
||||
if(n.eq.31) then
|
||||
crpt(i)='RR73'
|
||||
else
|
||||
write(crpt(i),1006) n-18
|
||||
1006 format(i3.2)
|
||||
if(crpt(i)(1:1).eq.' ') crpt(i)(1:1)='+'
|
||||
endif
|
||||
j=j+5
|
||||
enddo
|
||||
|
||||
! Unpack Hound callsigns and format user-level messages:
|
||||
iz=9 !Max number of hound calls
|
||||
if(i3.eq.2 .or. i3.eq.3) iz=4
|
||||
do i=1,iz
|
||||
j=28*i + 1
|
||||
read(msgbits(j:j+27),'(b28)') n28
|
||||
call unpack28(n28,c13,success)
|
||||
if(n28.eq.0 .or. n28.eq.NQU1RKS) cycle
|
||||
msg(i)=trim(c13)//' '//trim(foxcall)
|
||||
if(msg(i)(1:3).eq.'CQ ') then
|
||||
ncq=ncq+1
|
||||
else
|
||||
if(i3.eq.2) then
|
||||
msg(i)=trim(msg(i))//' '//crpt(i)
|
||||
else
|
||||
if(i.le.5) msg(i)=trim(msg(i))//' RR73'
|
||||
if(i.gt.5) msg(i)=trim(msg(i))//' '//crpt(i-5)
|
||||
endif
|
||||
endif
|
||||
if(ncq.le.1 .or. msg(i)(1:3).ne.'CQ ') then
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(i))
|
||||
endif
|
||||
enddo
|
||||
|
||||
if(msgbits(306:306).eq.'1' .and. ncq.lt.1) then
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),'CQ '//foxcall
|
||||
endif
|
||||
|
||||
100 read(msgbits(307:326),'(b20)') notp
|
||||
if (use_otp) then
|
||||
write(ssignature,'(I6.6)') notp
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),'$VERIFY$ '//trim(foxcall)//' '//trim(ssignature)
|
||||
endif
|
||||
return
|
||||
end subroutine sfox_unpack
|
40
lib/superfox/sfox_wave.f90
Normal file
40
lib/superfox/sfox_wave.f90
Normal file
@ -0,0 +1,40 @@
|
||||
subroutine sfox_wave(fname)
|
||||
|
||||
! Called by WSJT-X when it's time for SuperFox to transmit. Reads array
|
||||
! itone(1:151) from disk file 'sfox_2.dat' in the writable data directory.
|
||||
|
||||
parameter (NWAVE=(160+2)*134400*4) !Max WSJT-X waveform (FST4-1800 at 48kHz)
|
||||
parameter (NN=151,NSPS=1024)
|
||||
character*(*) fname
|
||||
integer itone(151)
|
||||
real*8 dt,twopi,f0,baud,phi,dphi
|
||||
|
||||
common/foxcom/wave(NWAVE)
|
||||
|
||||
wave=0.
|
||||
open(25,file=trim(fname),status='unknown',err=999)
|
||||
read(25,'(20i4)',err=999,end=999) itone
|
||||
close(25)
|
||||
if(itone(1).lt.0 .or. itone(1).gt.128) go to 999
|
||||
|
||||
! Generate the SuperFox waveform.
|
||||
|
||||
dt=1.d0/48000.d0
|
||||
twopi=8.d0*atan(1.d0)
|
||||
f0=750.0d0
|
||||
phi=0.d0
|
||||
baud=12000.d0/NSPS
|
||||
k=0
|
||||
do j=1,NN
|
||||
f=f0 + baud*mod(itone(j),128)
|
||||
dphi=twopi*f*dt
|
||||
do ii=1,4*NSPS
|
||||
k=k+1
|
||||
phi=phi+dphi
|
||||
xphi=phi
|
||||
wave(k)=sin(xphi)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
999 return
|
||||
end subroutine sfox_wave
|
77
lib/superfox/sfox_wave_gfsk.f90
Normal file
77
lib/superfox/sfox_wave_gfsk.f90
Normal file
@ -0,0 +1,77 @@
|
||||
subroutine sfox_wave_gfsk()
|
||||
|
||||
! Called by WSJT-X when it's time for SuperFox to transmit. Reads array
|
||||
! itone(1:151) from disk file 'sfox_2.dat' in the writable data directory.
|
||||
! Generates a GFSK waveform with short ramp-up and ramp-down symbols of
|
||||
! duration NSPS/BT at the beginning and end of the waveform.
|
||||
|
||||
parameter (NWAVE=(160+2)*134400*4) !Max WSJT-X waveform (FST4-1800 at 48kHz)
|
||||
parameter (NSYM=151,NSPS=1024*4)
|
||||
parameter (NPTS=(NSYM+2)*NSPS)
|
||||
parameter (BT=8)
|
||||
character*40 cmsg2
|
||||
integer itone(151)
|
||||
real*8 dt,twopi,f0,phi,dphi_peak
|
||||
real*8 dphi(0:NPTS-1)
|
||||
real*8 pulse(3*NSPS)
|
||||
logical first/.true./
|
||||
|
||||
common/foxcom/wave(NWAVE)
|
||||
common/foxcom3/nslots2,cmsg2(5),itone3(151)
|
||||
save first,twopi,dt,hmod,dphi_peak,pulse
|
||||
|
||||
if(first) then
|
||||
fsample=48000.0
|
||||
twopi=8.d0*atan(1.d0)
|
||||
dt=1.d0/fsample
|
||||
hmod=1.0
|
||||
dphi_peak=twopi*hmod/real(NSPS)
|
||||
do i=1,3*NSPS
|
||||
tt=(i-1.5*NSPS)/real(NSPS)
|
||||
pulse(i)=gfsk_pulse(BT,tt)
|
||||
enddo
|
||||
first=.false.
|
||||
endif
|
||||
wave=0.
|
||||
|
||||
itone=itone3
|
||||
if(itone(1).lt.0 .or. itone(1).gt.128) go to 999
|
||||
|
||||
! Generate the SuperFox waveform.
|
||||
|
||||
dphi=0.d0
|
||||
do j=1,NSYM
|
||||
ib=(j-1)*NSPS
|
||||
ie=ib+3*NSPS-1
|
||||
dphi(ib:ie)=dphi(ib:ie)+dphi_peak*pulse(1:3*NSPS)*itone(j)
|
||||
enddo
|
||||
dphi(0:2*NSPS-1)=dphi(0:2*NSPS-1)+dphi_peak*itone(1)*pulse(NSPS+1:3*NSPS)
|
||||
dphi(NSYM*NSPS:(NSYM+2)*NSPS-1)=dphi(NSYM*NSPS:(NSYM+2)*NSPS-1)+dphi_peak*itone(NSYM)*pulse(1:2*NSPS)
|
||||
|
||||
phi=0.d0
|
||||
f0=750.0d0
|
||||
dphi=dphi+twopi*f0*dt
|
||||
k=0
|
||||
do j=1,NSPS*(NSYM+2)-1
|
||||
k=k+1
|
||||
wave(k)=sin(phi)
|
||||
phi=phi+dphi(j)
|
||||
enddo
|
||||
|
||||
! Add raised cosine ramps at the beginning and end of the waveform.
|
||||
! Since the modulator expects an integral number of symbols, dummy
|
||||
! symbols are added to the beginning and end of the waveform to
|
||||
! hold the ramps. All but nramp of the samples in each dummy
|
||||
! symbol will be zero.
|
||||
|
||||
nramp=NSPS/BT
|
||||
wave(1:NSPS-nramp)=0.0
|
||||
wave(NSPS-nramp+1:NSPS)=wave(NSPS-nramp+1:NSPS) * &
|
||||
(1.0-cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
|
||||
k1=(NSYM+1)*NSPS+1
|
||||
wave(k1:k1+nramp-1)=wave(k1:k1+nramp-1) * &
|
||||
(1.0+cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
|
||||
wave(k1+nramp:NPTS)=0.0
|
||||
|
||||
999 return
|
||||
end subroutine sfox_wave_gfsk
|
164
lib/superfox/sfoxsim.f90
Normal file
164
lib/superfox/sfoxsim.f90
Normal file
@ -0,0 +1,164 @@
|
||||
program sfoxsim
|
||||
|
||||
! - Generate complex-valued SuperFox waveform, cdat.
|
||||
! - Pass cdat through Watterson channel simulator
|
||||
! - Add noise to the imaginary part of cdat and write to wav file.
|
||||
|
||||
use wavhdr
|
||||
use qpc_mod
|
||||
use sfox_mod
|
||||
|
||||
type(hdr) h !Header for .wav file
|
||||
logical*1 bMoreCQs !Include a CQ when space available?
|
||||
logical*1 bSendMsg !Send a Free text message
|
||||
integer*2 iwave(NMAX) !Generated i*2 waveform
|
||||
integer isync(24) !Indices of sync symbols
|
||||
integer itone(151) !Symbol values, data and sync
|
||||
integer*1 xin(0:49)
|
||||
integer*1 y(0:127)
|
||||
real*4 xnoise(NMAX) !Random noise
|
||||
real*4 dat(NMAX) !Generated real data
|
||||
complex cdat(NMAX) !Generated complex waveform
|
||||
complex crcvd(NMAX) !Signal as received
|
||||
real, allocatable :: s3(:,:) !Symbol spectra: will be s3(NQ,NN)
|
||||
integer, allocatable :: msg0(:) !Information symbols
|
||||
integer, allocatable :: chansym(:) !Encoded data, 7-bit integers
|
||||
character fname*17,arg*12,channel*2,foxcall*11
|
||||
character*10 ckey
|
||||
character*26 text_msg
|
||||
character*120 line !SuperFox message pieces
|
||||
character*40 cmsg(5)
|
||||
data ckey/'0000000000'/
|
||||
data cmsg/'W0AAA RR73; W5FFF <K1JT> -18', &
|
||||
'W1BBB RR73; W6GGG <K1JT> -15', &
|
||||
'W2CCC RR73; W7HHH <K1JT> -12', &
|
||||
'W3DDD RR73; W8III <K1JT> -09', &
|
||||
'W4EEE RR73; W9JJJ <K1JT> -06'/
|
||||
data text_msg/'0123456789ABCDEFGHIJKLMNOP'/
|
||||
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80, &
|
||||
83,84,86,89/
|
||||
|
||||
nargs=iargc()
|
||||
if(nargs.ne.10) then
|
||||
print*,'Usage: sfoxsim f0 DT Chan FoxC H1 H2 CQ FT nfiles snr'
|
||||
print*,'Example: sfoxsim 750 0.0 MM K1JT 5 1 0 0 10 -15'
|
||||
print*,' f0=0 to dither f0 and DT'
|
||||
print*,' Chan Channel type AW LQ LM LD MQ MM MD HQ HM HD'
|
||||
print*,' FoxC Fox callsign'
|
||||
print*,' key'
|
||||
print*,' H1 number of Hound calls with RR73'
|
||||
print*,' H2 number of Hound calls with reports'
|
||||
print*,' CQ=1 to include a CQ message'
|
||||
print*,' FT=1 to include a Free Text message'
|
||||
go to 999
|
||||
endif
|
||||
call getarg(1,arg)
|
||||
read(arg,*) f0
|
||||
call getarg(2,arg)
|
||||
read(arg,*) xdt
|
||||
call getarg(3,channel)
|
||||
call getarg(4,foxcall)
|
||||
call getarg(5,arg)
|
||||
read(arg,*) nh1
|
||||
call getarg(6,arg)
|
||||
read(arg,*) nh2
|
||||
call getarg(7,arg)
|
||||
read(arg,*) ncq
|
||||
bMoreCQs=ncq.ne.0
|
||||
call getarg(8,arg)
|
||||
read(arg,*) nft
|
||||
bSendMsg=nft.ne.0
|
||||
call getarg(9,arg)
|
||||
read(arg,*) nfiles
|
||||
call getarg(10,arg)
|
||||
read(arg,*) snr
|
||||
|
||||
fspread=0.0
|
||||
delay=0.0
|
||||
fsample=12000.0 !Sample rate (Hz)
|
||||
call sfox_init(7,127,50,channel,fspread,delay,fsample,24)
|
||||
txt=(NN+NS)*NSPS/fsample
|
||||
write(*,1000) f0,xdt,channel,snr
|
||||
1000 format('sfoxsim: f0= ',f5.1,' dt= ',f4.2,' Channel: ',a2,' snr: ',f5.1,' dB')
|
||||
|
||||
! Allocate storage for arrays that depend on code parameters.
|
||||
allocate(s3(0:NQ-1,0:NN-1))
|
||||
allocate(msg0(1:KK))
|
||||
allocate(chansym(0:NN-1))
|
||||
|
||||
if(nft.ne.0) then
|
||||
open(10,file='text_msg.txt',status='old',err=2)
|
||||
read(10,*) text_msg
|
||||
endif
|
||||
|
||||
2 idum=-1
|
||||
rms=100.
|
||||
baud=fsample/nsps !Keying rate, 11.719 baud for nsps=1024
|
||||
bandwidth_ratio=2500.0/fsample
|
||||
do i=1,5
|
||||
cmsg(i)=cmsg(i)(1:19)//trim(foxcall)//cmsg(i)(24:28)
|
||||
if(i.gt.nh1 .and. i.gt.nh2) then
|
||||
cmsg(i)=''
|
||||
elseif(i.gt.nh1) then
|
||||
cmsg(i)=cmsg(i)(13:18)//trim(foxcall)//cmsg(i)(25:28)
|
||||
elseif(i.gt.nh2) then
|
||||
cmsg(i)=cmsg(i)(1:6)//trim(foxcall)//' RR73'
|
||||
endif
|
||||
! write(*,*) 'Debug ',cmsg(i)
|
||||
enddo
|
||||
|
||||
if((nh1+nh2).eq.0 .and. bMoreCQs) cmsg(1)='CQ '//trim(foxcall)//' FN20'
|
||||
|
||||
! Generate a SuperFox message
|
||||
nslots=5
|
||||
call foxgen2(nslots,cmsg,line,foxcall) !Parse old-style Fox messages
|
||||
call sfox_pack(line,ckey,bMoreCQs,bSendMsg,text_msg,xin)
|
||||
call qpc_encode(y,xin)
|
||||
|
||||
y=cshift(y,1)
|
||||
y(127)=0
|
||||
chansym=y(0:126)
|
||||
|
||||
sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snr)
|
||||
sigr=sqrt(2.)*sig
|
||||
if(snr.gt.90.0) sig=1.0
|
||||
|
||||
do ifile=1,nfiles
|
||||
xnoise=0.
|
||||
if(snr.lt.90) then
|
||||
do i=1,NMAX
|
||||
xnoise(i)=gran() !Gaussian noise
|
||||
enddo
|
||||
endif
|
||||
|
||||
f1=f0
|
||||
if(f0.eq.0.0) then
|
||||
f1=750 + 20.0*(ran1(idum)-0.5)
|
||||
xdt=ran1(idum)-0.5
|
||||
endif
|
||||
! Generate cdat, the SuperFox waveform
|
||||
call sfox_gen_gfsk(chansym,f1,isync,itone,cdat)
|
||||
|
||||
crcvd=0.
|
||||
crcvd(1:NMAX)=cshift(cdat(1:NMAX),-nint((0.5+xdt)*fsample))
|
||||
if(fspread.ne.0 .or. delay.ne.0) call watterson(crcvd,NMAX,NZ,fsample,&
|
||||
delay,fspread)
|
||||
|
||||
dat=aimag(sigr*crcvd(1:NMAX)) + xnoise !Add generated AWGN noise
|
||||
fac=32767.0
|
||||
if(snr.ge.90.0) iwave(1:NMAX)=nint(fac*dat(1:NMAX))
|
||||
if(snr.lt.90.0) iwave(1:NMAX)=nint(rms*dat(1:NMAX))
|
||||
|
||||
h=default_header(12000,NMAX)
|
||||
fname='000000_000001.wav'
|
||||
nsec=(ifile-1)*30
|
||||
nhr=nsec/3600
|
||||
nmin=(nsec-nhr*3600)/60
|
||||
nsec=mod(nsec,60)
|
||||
write(fname(8:13),'(3i2.2)') nhr,nmin,nsec
|
||||
open(10,file=trim(fname),access='stream',status='unknown')
|
||||
write(10) h,iwave(1:NMAX) !Save the .wav file
|
||||
close(10)
|
||||
enddo ! ifile
|
||||
|
||||
999 end program sfoxsim
|
59
lib/superfox/sfrx.f90
Normal file
59
lib/superfox/sfrx.f90
Normal file
@ -0,0 +1,59 @@
|
||||
program sfrx
|
||||
|
||||
! Command-line SuperFox decoder
|
||||
|
||||
use sfox_mod
|
||||
use julian
|
||||
|
||||
integer*2 iwave(NMAX)
|
||||
integer ihdr(11)
|
||||
character*120 fname
|
||||
include 'gtag.f90'
|
||||
|
||||
narg=iargc()
|
||||
|
||||
if(narg.lt.1) then
|
||||
print*,'Usage: sfrx fsync ftol infile [...]'
|
||||
print*,' sfrx 775 10 240811_102400.wav'
|
||||
print*,'Reads one or more .wav files and calls SuperFox decoder on each.'
|
||||
print '(" Git tag: ",z9)',ntag
|
||||
go to 999
|
||||
endif
|
||||
|
||||
call getarg(1,fname)
|
||||
read(fname,*,err=1) fsync
|
||||
call getarg(2,fname)
|
||||
read(fname,*,err=1) ftol
|
||||
|
||||
nfqso=nint(fsync)
|
||||
ntol=nint(ftol)
|
||||
|
||||
1 nf=0
|
||||
nd=0
|
||||
nv=0
|
||||
|
||||
do ifile=3,narg
|
||||
call getarg(ifile,fname)
|
||||
write(72,*) ifile,narg,fname
|
||||
open(10,file=trim(fname),status='old',access='stream',err=4)
|
||||
|
||||
go to 5
|
||||
4 print*,'Cannot open file ',trim(fname)
|
||||
go to 999
|
||||
5 read(10) ihdr,iwave
|
||||
close(10)
|
||||
|
||||
nz=len(trim(fname))
|
||||
nyymmdd=ihdr(1)
|
||||
nutc=ihdr(2)
|
||||
if(fname(nz-3:nz).eq.'.wav') then
|
||||
read(fname(nz-16:nz-11),*) nyymmdd
|
||||
read(fname(nz-9:nz-4),*) nutc
|
||||
endif
|
||||
|
||||
call sfrx_sub(nyymmdd,nutc,nfqso,ntol,iwave)
|
||||
|
||||
nf=nf+1
|
||||
enddo
|
||||
|
||||
999 end program sfrx
|
54
lib/superfox/sfrx_sub.f90
Normal file
54
lib/superfox/sfrx_sub.f90
Normal file
@ -0,0 +1,54 @@
|
||||
subroutine sfrx_sub(nyymmdd,nutc,nfqso,ntol,iwave)
|
||||
|
||||
use sfox_mod
|
||||
use julian
|
||||
|
||||
integer*2 iwave(NMAX)
|
||||
integer*8 secday,ntime8
|
||||
integer*1 xdec(0:49)
|
||||
character*13 foxcall
|
||||
complex c0(NMAX) !Complex form of signal as received
|
||||
real dd(NMAX)
|
||||
logical crc_ok
|
||||
data secday/86400/
|
||||
|
||||
fsync=nfqso
|
||||
ftol=ntol
|
||||
fsample=12000.0
|
||||
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
|
||||
npts=15*12000
|
||||
|
||||
if(nyymmdd.eq.-1) then
|
||||
ntime8=itime8()/30
|
||||
ntime8=30*ntime8
|
||||
else
|
||||
iyr=2000+nyymmdd/10000
|
||||
imo=mod(nyymmdd/100,100)
|
||||
iday=mod(nyymmdd,100)
|
||||
ih=nutc/10000
|
||||
im=mod(nutc/100,100)
|
||||
is=mod(nutc,100)
|
||||
ntime8=secday*(JD(iyr,imo,iday)-2440588) + 3600*ih + 60*im + is
|
||||
endif
|
||||
|
||||
dd=iwave
|
||||
call sfox_remove_ft8(dd,npts)
|
||||
|
||||
call sfox_ana(dd,npts,c0,npts)
|
||||
|
||||
call sfox_remove_tone(c0,fsync) ! Needs testing
|
||||
|
||||
ndepth=3
|
||||
dth=0.5
|
||||
damp=1.0
|
||||
|
||||
call qpc_decode2(c0,fsync,ftol, xdec,ndepth,dth,damp,crc_ok, &
|
||||
snrsync,fbest,tbest,snr)
|
||||
if(crc_ok) then
|
||||
nsnr=nint(snr)
|
||||
nsignature = 1
|
||||
call sfox_unpack(nutc,xdec,nsnr,fbest-750.0,tbest,foxcall,nsignature)
|
||||
endif
|
||||
|
||||
return
|
||||
end subroutine sfrx_sub
|
107
lib/superfox/sftx.f90
Normal file
107
lib/superfox/sftx.f90
Normal file
@ -0,0 +1,107 @@
|
||||
program sftx
|
||||
|
||||
! This program is required in order to create a SuperFox transmission.
|
||||
|
||||
! The present version goes through the following steps:
|
||||
! 1. Read old-style Fox messages from file 'sfox_1.dat' in the WSJT-X
|
||||
! writable data directory.
|
||||
! 2. Parse up to NSlots=5 messages to extract MyCall, up to 9 Hound
|
||||
! calls, and the report or RR73 to be sent to each Hound.
|
||||
! 3. Assemble and encode a single SuperFox message to produce itone(1:151),
|
||||
! the array of channel symbol values.
|
||||
! 4. Write the contents of array itone to file 'sfox_2.dat'.
|
||||
|
||||
use qpc_mod
|
||||
use sfox_mod
|
||||
character*120 fname !Corrected path for sfox_1.dat
|
||||
character*120 line !List of SuperFox message pieces
|
||||
character*40 cmsg(5) !Old-style Fox messages
|
||||
character*26 freeTextMsg
|
||||
character*2 arg
|
||||
character*10 ckey
|
||||
! character*9 foxkey
|
||||
character*11 foxcall0,foxcall
|
||||
logical*1 bMoreCQs,bSendMsg
|
||||
logical crc_ok
|
||||
real py(0:127,0:127) !Probabilities for received synbol values
|
||||
integer*8 n47
|
||||
integer itone(151) !SuperFox channel-symbol values
|
||||
integer*1 xin(0:49) !Packed message as 7-bit symbols
|
||||
integer*1 xdec(0:49) !Decoded message
|
||||
integer*1 y(0:127) !Encoded symbols as i*1 integers
|
||||
integer*1 ydec(0:127) !Decoded codeword
|
||||
integer*1 yy(0:10)
|
||||
integer chansym0(127) !Transmitted symbols, data only
|
||||
integer chansym(127) !Received symbols, data only
|
||||
integer isync(24) !Symbol numbers for sync tones
|
||||
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80, &
|
||||
83,84,86,89/
|
||||
include 'gtag.f90'
|
||||
|
||||
narg=iargc()
|
||||
if(narg.ne.3) then
|
||||
print '(" Git tag: ",z9)',ntag
|
||||
go to 999
|
||||
endif
|
||||
|
||||
! sftx <message_file_name> <foxcall> <ckey>
|
||||
call getarg(1,fname)
|
||||
do i=1,len(trim(fname))
|
||||
if(fname(i:i).eq.'\\') fname(i:i)='/'
|
||||
enddo
|
||||
call getarg(2,foxcall0)
|
||||
call getarg(3,ckey)
|
||||
|
||||
! if((foxkey(foxcall0).ne.ckey).and.(INDEX(ckey,'OTP:').eq.0)) then ! neither kind
|
||||
! itone=-99
|
||||
! go to 100
|
||||
! endif
|
||||
|
||||
fsample=12000.0
|
||||
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
|
||||
open(25,file=trim(fname),status='unknown')
|
||||
do i=1,5
|
||||
read(25,1000,end=10) cmsg(i)
|
||||
1000 format(a40)
|
||||
enddo
|
||||
i=6
|
||||
10 close(25)
|
||||
nslots=i-1
|
||||
freeTextMsg=' '
|
||||
bMoreCQs=cmsg(1)(40:40).eq.'1'
|
||||
bSendMsg=cmsg(nslots)(39:39).eq.'1'
|
||||
if(bSendMsg) then
|
||||
freeTextMsg=cmsg(nslots)(1:26)
|
||||
if(nslots.gt.2) nslots=2
|
||||
endif
|
||||
|
||||
call foxgen2(nslots,cmsg,line,foxcall) !Parse old-style Fox messages
|
||||
|
||||
! Pack message information and CRC into xin(0:49)
|
||||
call sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
|
||||
call qpc_encode(y,xin) !Encode the message to 128 symbols
|
||||
y=cshift(y,1) !Puncture the code by removing y(0)
|
||||
y(127)=0
|
||||
chansym0=y(0:126)
|
||||
|
||||
! Create the full itone sequence containing both data and sync symbols
|
||||
j=1
|
||||
k=0
|
||||
do i=1,NDS
|
||||
if(j.le.NS .and. i.eq.isync(j)) then
|
||||
if(j.lt.NS) j=j+1 !Index for next sync symbol
|
||||
itone(i)=0 !Insert sync symbol at tone 0
|
||||
else
|
||||
k=k+1
|
||||
itone(i)=chansym0(k) + 1 !Symbol value 0 transmitted as tone 1, etc.
|
||||
endif
|
||||
enddo
|
||||
|
||||
100 i1=max(index(fname,'sfox_1'),1)
|
||||
fname(i1:i1+9)='sfox_2.dat'
|
||||
open(25,file=trim(fname),status='unknown')
|
||||
write(25,1100) itone
|
||||
1100 format(20i4)
|
||||
close(25)
|
||||
|
||||
999 end program sftx
|
65
lib/superfox/sftx_sub.f90
Normal file
65
lib/superfox/sftx_sub.f90
Normal file
@ -0,0 +1,65 @@
|
||||
subroutine sftx_sub(ckey0)
|
||||
|
||||
! This routine is required in order to create a SuperFox transmission.
|
||||
|
||||
! The present version goes through the following steps:
|
||||
! 1. Read old-style Fox messages from file 'sfox_1.dat' in the WSJT-X
|
||||
! writable data directory.
|
||||
! 2. Parse up to NSlots=5 messages to extract MyCall, up to 9 Hound
|
||||
! calls, and the report or RR73 to be sent to each Hound.
|
||||
! 3. Assemble and encode a single SuperFox message to produce itone(1:151),
|
||||
! the array of channel symbol values.
|
||||
! 4. Write the contents of array itone to file 'sfox_2.dat'.
|
||||
|
||||
use qpc_mod
|
||||
use sfox_mod
|
||||
character*120 line !List of SuperFox message pieces
|
||||
character*40 cmsg !Old-style Fox messages
|
||||
character*26 freeTextMsg
|
||||
character*(*) ckey0
|
||||
character*10 ckey
|
||||
character*11 foxcall
|
||||
logical*1 bMoreCQs,bSendMsg
|
||||
integer*1 xin(0:49) !Packed message as 7-bit symbols
|
||||
integer*1 y(0:127) !Encoded symbols as i*1 integers
|
||||
integer chansym0(127) !Transmitted symbols, data only
|
||||
integer isync(24) !Symbol numbers for sync tones
|
||||
common/foxcom3/nslots,cmsg(5),itone(151)
|
||||
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80, &
|
||||
83,84,86,89/
|
||||
|
||||
ckey=ckey0
|
||||
|
||||
fsample=12000.0
|
||||
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
|
||||
freeTextMsg=' '
|
||||
bMoreCQs=cmsg(1)(40:40).eq.'1'
|
||||
bSendMsg=cmsg(nslots)(39:39).eq.'1'
|
||||
if(bSendMsg) then
|
||||
freeTextMsg=cmsg(nslots)(1:26)
|
||||
if(nslots.gt.4) nslots=4
|
||||
endif
|
||||
|
||||
call foxgen2(nslots,cmsg,line,foxcall) !Parse old-style Fox messages
|
||||
|
||||
! Pack message information and CRC into xin(0:49)
|
||||
call sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
|
||||
call qpc_encode(y,xin) !Encode the message to 128 symbols
|
||||
y=cshift(y,1) !Puncture the code by removing y(0)
|
||||
y(127)=0
|
||||
chansym0=y(0:126)
|
||||
|
||||
! Create the full itone sequence containing both data and sync symbols
|
||||
j=1
|
||||
k=0
|
||||
do i=1,NDS
|
||||
if(j.le.NS .and. i.eq.isync(j)) then
|
||||
if(j.lt.NS) j=j+1 !Index for next sync symbol
|
||||
itone(i)=0 !Insert sync symbol at tone 0
|
||||
else
|
||||
k=k+1
|
||||
itone(i)=chansym0(k) + 1 !Symbol value 0 transmitted as tone 1, etc.
|
||||
endif
|
||||
enddo
|
||||
|
||||
end subroutine sftx_sub
|
66
lib/superfox/superfox_qpc_2.txt
Normal file
66
lib/superfox/superfox_qpc_2.txt
Normal file
@ -0,0 +1,66 @@
|
||||
Bit packing of SuperFox QPC Messages
|
||||
-----------------------------------------------------------------------------
|
||||
The IV3NWV Q-ary Polar Code has parameters (n,k) = (127,50). The last
|
||||
three 7-bit information symbols convey a 21-bit CRC based on the first
|
||||
47 symbols. Thus, each Super Fox transmission carries a payload of
|
||||
47*7=329 bits. On a modern x86 processor the decoder executes in
|
||||
deterministic time around 5 ms per decode, and always produces a
|
||||
result. The CRC test rejects all but around 1 in two million false
|
||||
decodes.
|
||||
|
||||
Bit fields are labeled with tags as defined in the QEX article "The
|
||||
FT4 and FT8 Communication Protocols" by Franke, Somerville, and Taylor
|
||||
in QEX for July/August 2020, available on the WSJT web site here:
|
||||
https://wsjt.sourceforge.io/FT4_FT8_QEX.pdf. As one example, the tag
|
||||
'c28' denotes a standard callsign, which requires 28 bits.
|
||||
|
||||
=============================================================================
|
||||
i3 = 0: Standard message: FoxCall, up to 9 HoundCalls, up to 4 signal
|
||||
reports, "MoreCQs" flag, a digital signature, and a 3-bit message type.
|
||||
-----------------------------------------------------------------------------
|
||||
F H1 H2 H3 H4 H5 H6 H7 H8 H9 R6 R7 R8 R9 U Q D M Type
|
||||
c28 c28 c28 c28 c28 c28 c28 c28 c28 c28 r5 r5 r5 r5 u5 q1 d20 i3=0 Std Msg
|
||||
280 300 305 326 329
|
||||
=============================================================================
|
||||
i3 = 1: If Fox uses a compound callsign we have space for only 8 Hound calls.
|
||||
Otherwise like type i3=0.
|
||||
-----------------------------------------------------------------------------
|
||||
FC H1 H2 H2 H4 H5 H6 H7 H8 R5 R6 R7 R8 U Q D M
|
||||
c58 c28 c28 c28 c28 c28 c28 c28 c28 r5 r5 r5 r5 u3 q1 d20 i3=1
|
||||
58 282 302 305 326 329
|
||||
=============================================================================
|
||||
i3 = 2: A free text message with up to 26 characters can be transmitted along
|
||||
with messages to as many as 4 Hounds conveying either reports or RR73s.
|
||||
-----------------------------------------------------------------------------
|
||||
F H1 H2 H3 H4 R1 R2 R3 R4 T T U Q D M Type
|
||||
c28 c28 c28 c28 c28 r5 r5 r5 r5 t71 t71 u3 q1 d20 i3=2 FT+4H
|
||||
140 160 302 305 326 329
|
||||
=============================================================================
|
||||
i3 = 3: Message "CQ FoxCall Grid <Free text>"
|
||||
-----------------------------------------------------------------------------
|
||||
FC G T T U Q D M Type
|
||||
c58 g15 t71 t71 u90 q1 d20 i3=3 CQ FT
|
||||
58 73 144 215 305 326 329
|
||||
=============================================================================
|
||||
|
||||
D Digital signature (20 bits)
|
||||
F Fox call (28 bits)
|
||||
FC Compound Fox call (58 bits)
|
||||
G Grid locator (15 bits)
|
||||
H Hound call (28 bits)
|
||||
M Message type (3 bits)
|
||||
Q MoreCQs flag
|
||||
R Report, (5 bits: -18 to +12 dB, or RR73)
|
||||
T Free text, up to 26 characters total
|
||||
U Unused bits
|
||||
|
||||
Unused callsign slots are set to the numerical value for "QU1RKS", and
|
||||
ignored when received. Similarly for unused t71 slots. Unused report
|
||||
slots are set to 0 (-20 dB). "CQ FoxCall" will be displayed along
|
||||
with other messages if the "q1" bit is 1.
|
||||
|
||||
The SuperFox decoder displays its results with a separate line for each Hound.
|
||||
Thus, the old-style message "K1ABC RR73; W9XYZ <VP8PJ> -14" becomes
|
||||
|
||||
K1ABC VP8PJ RR73
|
||||
W9XYZ VP8PJ -14
|
19
lib/superfox/twkfreq2.f90
Normal file
19
lib/superfox/twkfreq2.f90
Normal file
@ -0,0 +1,19 @@
|
||||
subroutine twkfreq2(c3,c4,npts,fsample,fshift)
|
||||
|
||||
! Adjust frequency of complex waveform
|
||||
|
||||
complex c3(npts)
|
||||
complex c4(npts)
|
||||
complex w,wstep
|
||||
data twopi/6.283185307/
|
||||
|
||||
w=1.0
|
||||
dphi=fshift*twopi/fsample
|
||||
wstep=cmplx(cos(dphi),sin(dphi))
|
||||
do i=1,npts
|
||||
w=w*wstep
|
||||
c4(i)=w*c3(i)
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine twkfreq2
|
@ -9,7 +9,6 @@
|
||||
#include "pimpl_h.hpp"
|
||||
|
||||
class Configuration;
|
||||
class QDateTime;
|
||||
class QSqlTableModel;
|
||||
class QTextStream;
|
||||
class AD1CCty;
|
||||
|
109
otpgenerator.cpp
Normal file
109
otpgenerator.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
|
||||
#include "otpgenerator.h"
|
||||
|
||||
#include <QMessageAuthenticationCode>
|
||||
#include <QtEndian>
|
||||
#include <QDateTime>
|
||||
#include <QtMath>
|
||||
|
||||
// FROM https://github.com/RikudouSage/QtOneTimePassword/
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Dominik Chrástecký
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
OTPGenerator::OTPGenerator(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QByteArray OTPGenerator::generateHOTP(const QByteArray &rawSecret, quint64 counter, int length)
|
||||
{
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
counter = qToBigEndian(counter);
|
||||
#endif
|
||||
QByteArray data;
|
||||
data.reserve(8);
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
data.append(counter & 0xff);
|
||||
counter >>= 8;
|
||||
}
|
||||
QMessageAuthenticationCode mac(QCryptographicHash::Sha1);
|
||||
mac.setKey(rawSecret);
|
||||
mac.addData(data);
|
||||
QByteArray hmac = mac.result();
|
||||
int offset = hmac.at(hmac.length() - 1) & 0xf;
|
||||
quint32 truncatedHash = ((hmac.at(offset) & 0x7f) << 24)
|
||||
| ((hmac.at(offset + 1) & 0xff) << 16)
|
||||
| ((hmac.at(offset + 2) & 0xff) << 8)
|
||||
| (hmac.at(offset + 3) & 0xff);
|
||||
int modulus = int(qPow(10, length));
|
||||
return QByteArray::number(truncatedHash % modulus, 10).rightJustified(length, '0');
|
||||
}
|
||||
|
||||
QString OTPGenerator::generateHOTP(const QString &secret, quint64 counter, int length)
|
||||
{
|
||||
return generateHOTP(fromBase32(secret), counter, length);
|
||||
}
|
||||
|
||||
QByteArray OTPGenerator::generateTOTP(const QByteArray &rawSecret, int length)
|
||||
{
|
||||
const qint64 counter = QDateTime::currentDateTime().toMSecsSinceEpoch() / 30000;
|
||||
return generateHOTP(rawSecret, counter, length);
|
||||
}
|
||||
|
||||
QString OTPGenerator::generateTOTP(const QString &secret, int length)
|
||||
{
|
||||
return generateTOTP(fromBase32(secret), length);
|
||||
}
|
||||
|
||||
QString OTPGenerator::generateTOTP(const QString &secret, QDateTime dt, int length)
|
||||
{
|
||||
const qint64 counter = dt.toMSecsSinceEpoch() / 30000;
|
||||
return generateHOTP(fromBase32(secret), counter, length);
|
||||
}
|
||||
|
||||
QByteArray OTPGenerator::fromBase32(const QString &input)
|
||||
{
|
||||
QByteArray result;
|
||||
result.reserve((input.length() * 5 + 7) / 8);
|
||||
int buffer = 0;
|
||||
int bitsLeft = 0;
|
||||
for (int i = 0; i < input.length(); i++) {
|
||||
int ch = input[i].toLatin1();
|
||||
int value;
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
value = ch - 'A';
|
||||
else if (ch >= '2' && ch <= '7')
|
||||
value = 26 + ch - '2';
|
||||
else
|
||||
continue;
|
||||
buffer = (buffer << 5) | value;
|
||||
bitsLeft += 5;
|
||||
if (bitsLeft >= 8) {
|
||||
result.append(buffer >> (bitsLeft - 8));
|
||||
bitsLeft -= 8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
50
otpgenerator.h
Normal file
50
otpgenerator.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef OTPGENERATOR_H
|
||||
#define OTPGENERATOR_H
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Dominik Chrástecký
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#define BASE32_CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
|
||||
|
||||
class OTPGenerator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OTPGenerator(QObject *parent = nullptr);
|
||||
|
||||
QByteArray generateHOTP(const QByteArray &rawSecret, quint64 counter, int length);
|
||||
Q_INVOKABLE QString generateHOTP(const QString &secret, quint64 counter, int length);
|
||||
|
||||
QByteArray generateTOTP(const QByteArray &rawSecret, int length);
|
||||
Q_INVOKABLE QString generateTOTP(const QString &secret, QDateTime dt, int length);
|
||||
Q_INVOKABLE QString generateTOTP(const QString &secret, int length);
|
||||
private:
|
||||
QByteArray fromBase32(const QString &input);
|
||||
|
||||
signals:
|
||||
|
||||
};
|
||||
|
||||
#endif // OTPGENERATOR_H
|
@ -1,7 +1,7 @@
|
||||
subroutine decode0(dd,ss,savg)
|
||||
|
||||
use timer_module, only: timer
|
||||
parameter (NSMAX=60*96000)
|
||||
parameter (NSMAX=60*96000,NFFT=32768)
|
||||
|
||||
real*4 dd(2,NSMAX),ss(400,NFFT),savg(NFFT)
|
||||
real*8 fcenter
|
||||
@ -11,7 +11,7 @@ subroutine decode0(dd,ss,savg)
|
||||
character mycall*12,hiscall*12,mygrid*6,hisgrid*6,datetime*20
|
||||
character mycall0*12,hiscall0*12,hisgrid0*6
|
||||
character*64 result
|
||||
common/decodes/ndecodes,ncand,nQDecoderDone,nWDecoderBusy, &
|
||||
common/decodes/ndecodes,ncand2,nQDecoderDone,nWDecoderBusy, &
|
||||
nWTransmitting,kHzRequested,result(50)
|
||||
common/npar/fcenter,nutc,fselected,mousedf,mousefqso,nagain, &
|
||||
ndepth,ndiskdat,ntx60,newdat,nfa,nfb,nfcal,nfshift, &
|
||||
|
@ -1,5 +1,5 @@
|
||||
subroutine getcand2(ss,savg0,nts_q65,nagain,nhsym,ntx30a,ntx30b, &
|
||||
ntol,f0_selected,bAlso30,cand,ncand)
|
||||
ntol,f0_selected,bAlso30,cand,ncand2)
|
||||
|
||||
! Get candidates for Q65 decodes, based on presence of sync tone.
|
||||
|
||||
@ -110,7 +110,7 @@ subroutine getcand2(ss,savg0,nts_q65,nagain,nhsym,ntx30a,ntx30b, &
|
||||
endif
|
||||
|
||||
enddo
|
||||
ncand=j !Total number of candidates found
|
||||
ncand2=j !Total number of candidates found
|
||||
|
||||
return
|
||||
end subroutine getcand2
|
||||
|
@ -31,7 +31,7 @@ subroutine q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol, &
|
||||
character*17 fname
|
||||
character*64 result,ctmp
|
||||
character*20 datetime,datetime1
|
||||
common/decodes/ndecodes,ncand,nQDecoderDone,nWDecoderBusy, &
|
||||
common/decodes/ndecodes,ncand2,nQDecoderDone,nWDecoderBusy, &
|
||||
nWTransmitting,kHzRequested,result(50)
|
||||
common/cacb/ca
|
||||
data ifile/0/
|
||||
|
@ -21,7 +21,7 @@ subroutine q65c
|
||||
character*6 mygrid,hisgrid
|
||||
character*20 datetime
|
||||
character*64 result
|
||||
common/decodes/ndecodes,ncand,nQDecoderDone,nWDecoderBusy, &
|
||||
common/decodes/ndecodes,ncand2,nQDecoderDone,nWDecoderBusy, &
|
||||
nWTransmitting,kHzRequested,result(50)
|
||||
common/datcom2/dd(2,5760000),ss(400,NFFT),savg(NFFT),nparams0
|
||||
common/savecom/revision,fname
|
||||
@ -90,7 +90,7 @@ subroutine q65c
|
||||
endif
|
||||
endif
|
||||
|
||||
999 return
|
||||
return
|
||||
end subroutine q65c
|
||||
|
||||
subroutine all_done
|
||||
|
@ -35,7 +35,7 @@ subroutine qmapa(dd,ss,savg,newdat,nutc,fcenter,ntol,nfa,nfb, &
|
||||
type(good_decode) found(MAX_CANDIDATES)
|
||||
character*64 result
|
||||
character*20 datetime
|
||||
common/decodes/ndecodes,ncand,nQDecoderDone,nWDecoderBusy, &
|
||||
common/decodes/ndecodes,ncand2,nQDecoderDone,nWDecoderBusy, &
|
||||
nWTransmitting,kHzRequested,result(50)
|
||||
save
|
||||
|
||||
@ -52,7 +52,7 @@ subroutine qmapa(dd,ss,savg,newdat,nutc,fcenter,ntol,nfa,nfb, &
|
||||
call timer('get_cand',0)
|
||||
! Get a list of decoding candidates
|
||||
call getcand2(ss,savg,nts_q65,nagain,nhsym,ntx30a,ntx30b,ntol, &
|
||||
f0_selected,bAlso30,cand,ncand)
|
||||
f0_selected,bAlso30,cand,ncand2)
|
||||
call timer('get_cand',1)
|
||||
endif
|
||||
|
||||
@ -69,11 +69,11 @@ subroutine qmapa(dd,ss,savg,newdat,nutc,fcenter,ntol,nfa,nfb, &
|
||||
call timer('fftbig ',1)
|
||||
|
||||
if(nagain.ge.2) then
|
||||
ncand=1
|
||||
ncand2=1
|
||||
fqso=fselected
|
||||
endif
|
||||
|
||||
do icand=1,ncand !Attempt to decode each candidate
|
||||
do icand=1,ncand2 !Attempt to decode each candidate
|
||||
tsec=sec_midn() - tsec0
|
||||
if(ndiskdat.eq.0) then
|
||||
! No more realtime decode attempts if it's nearly too late, already
|
||||
|
@ -318,7 +318,7 @@
|
||||
<message>
|
||||
<location filename="../widgets/colorhighlighting.ui" line="150"/>
|
||||
<source>New Call</source>
|
||||
<translation>Nou Indicatiu</translation>
|
||||
<translation>Indicatiu nou</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/colorhighlighting.ui" line="157"/>
|
||||
@ -2238,12 +2238,12 @@ Error(%2): %3</translation>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1683"/>
|
||||
<source>Maximum drift rate in units of symbol rate per transmission.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Taxa de deriva màxima en unitats de taxa de símbols per transmissió.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1686"/>
|
||||
<source>Max Drift </source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Deriva màxima </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="2604"/>
|
||||
@ -3658,7 +3658,7 @@ La llista es pot mantenir a la configuració (F2).</translation>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="3429"/>
|
||||
<source>Quick-Start Guide to WSJT-X 2.5.0 and MAP65 3.0</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Guia d'inici ràpid de WSJT-X 2.5.0 i MAP65 3.0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.cpp" line="258"/>
|
||||
@ -3685,7 +3685,7 @@ La llista es pot mantenir a la configuració (F2).</translation>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.cpp" line="523"/>
|
||||
<source>Scanned ADIF log, %1 worked-before records created. CTY: %2</source>
|
||||
<translation>Log ADIF escanejat, %1 funcionava abans de la creació de registres</translation>
|
||||
<translation>Log ADIF escanejat, %1 funcionava abans de la creació de registres. CTY: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.cpp" line="631"/>
|
||||
|
@ -2480,17 +2480,17 @@ Error(%2): %3</translation>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1683"/>
|
||||
<source>Maximum drift rate in units of symbol rate per transmission.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Tasa de deriva máxima en unidades de tasa de símbolos por transmisión.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1686"/>
|
||||
<source>Max Drift </source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Máxima deriva </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="3416"/>
|
||||
<source>Quick-Start Guide to Q65</source>
|
||||
<translation>Guía de inicio rápido de Q65</translation>
|
||||
<translation>Guía de inicio rápido de Q65 (inglés)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="3424"/>
|
||||
@ -2500,7 +2500,7 @@ Error(%2): %3</translation>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="3429"/>
|
||||
<source>Quick-Start Guide to WSJT-X 2.5.0 and MAP65 3.0</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Guía de inicio rápido para WSJT-X 2.5.0 y MAP65 3.0 (inglés)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1588"/>
|
||||
@ -2703,7 +2703,7 @@ Amarillo cuando esta muy bajo.</translation>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="876"/>
|
||||
<source>&Lookup</source>
|
||||
<translation>Buscar</translation>
|
||||
<translation>Buscar (&L)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="988"/>
|
||||
@ -3044,7 +3044,7 @@ No está disponible para los titulares de indicativo no estándar.</translatorco
|
||||
<location filename="../widgets/mainwindow.ui" line="1215"/>
|
||||
<source>Best S+P</source>
|
||||
<translatorcomment>El mejor S+P </translatorcomment>
|
||||
<translation>Mejor S+P (&B)</translation>
|
||||
<translation>Mejor S+P</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1225"/>
|
||||
@ -3181,7 +3181,8 @@ Cuando no está marcado, puede verse los resultados de la calibración.</transla
|
||||
Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders)</source>
|
||||
<translatorcomment>Enviar este mensaje en el siguiente intervalo de transmisión.
|
||||
Haz doble clic para alternar el uso del mensaje TX1 para iniciar un QSO con una estación (no está permitido para titulares de indicativos compuestos de tipo 1).</translatorcomment>
|
||||
<translation>Enviar este mensaje en el siguiente intervalo de TX. Doble clic para alternar el uso del mensaje TX1 para iniciar un QSO con una estación (no está permitido para titulares de indicativos compuestos de tipo 1).</translation>
|
||||
<translation>Enviar este mensaje en el siguiente intervalo de TX.
|
||||
Doble clic para alternar el uso del mensaje TX1 para iniciar un QSO con una estación (no está permitido para titulares de indicativos compuestos de tipo 1).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1826"/>
|
||||
@ -3246,7 +3247,8 @@ Haz doble clic para alternar el uso del mensaje TX1 para iniciar un QSO con una
|
||||
<location filename="../widgets/mainwindow.ui" line="2035"/>
|
||||
<source>Send this message in next Tx interval
|
||||
Double-click to reset to the standard 73 message</source>
|
||||
<translation>Enviar este mensaje en el siguiente intervalo de TX. Doble clic para restablecer el mensaje 73 estándar.</translation>
|
||||
<translation>Enviar este mensaje en el siguiente intervalo de TX.
|
||||
Doble clic para restablecer el mensaje 73 estándar.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="2045"/>
|
||||
@ -3300,7 +3302,9 @@ RR73 messages should only be used when you are reasonably confident that no mess
|
||||
<translatorcomment>Cambia a este mensaje de TX AHORA.
|
||||
Haz doble clic para alternar entre los mensajes RRR y RR73 en TX4 (no está permitido para titulares de indicativos compuestos de tipo 2).
|
||||
Los mensajes RR73 solo deben usarse cuando esté razonablemente seguro de que no se requerirán repeticiones de mensajes.</translatorcomment>
|
||||
<translation>Cambiar a este mensaje de TX AHORA. Doble clic para alternar entre los mensajes RRR y RR73 en TX4 (no está permitido para titulares de indicativos compuestos de tipo 2). Los mensajes RR73 solo deben usarse cuando esté razonablemente seguro de que no se requerirán repeticiones de mensajes.</translation>
|
||||
<translation>Cambiar a este mensaje de TX AHORA.
|
||||
Doble clic para alternar entre los mensajes RRR y RR73 en TX4 (no está permitido para titulares de indicativos compuestos de tipo 2).
|
||||
Los mensajes RR73 solo deben usarse cuando esté razonablemente seguro de que no se requerirán repeticiones de mensajes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="1951"/>
|
||||
@ -3397,7 +3401,7 @@ predefinida. La lista se puede modificar en "Ajustes" (F2).</translati
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="3358"/>
|
||||
<source>Quick-Start Guide to FST4 and FST4W</source>
|
||||
<translation>Guía de inicio rápido a FST4 y FST4W</translation>
|
||||
<translation>Guía de inicio rápido a FST4 y FST4W (inglés)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.ui" line="3384"/>
|
||||
@ -4239,7 +4243,7 @@ predefinida. La lista se puede modificar en "Ajustes" (F2).</translati
|
||||
<location filename="../widgets/mainwindow.cpp" line="523"/>
|
||||
<source>Scanned ADIF log, %1 worked-before records created. CTY: %2</source>
|
||||
<translatorcomment>Log ADIF escaneado, %1 funcionaba antes de la creación de registros</translatorcomment>
|
||||
<translation>Log ADIF escaneado, %1 registros trabajados B4 creados</translation>
|
||||
<translation>Log ADIF escaneado, %1 registros trabajados B4 creados. CTY: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.cpp" line="631"/>
|
||||
@ -4912,7 +4916,7 @@ ya está en CALL3.TXT, ¿desea reemplazarlo?</translation>
|
||||
<location filename="../widgets/mainwindow.cpp" line="8593"/>
|
||||
<source>Confirm Reset</source>
|
||||
<translatorcomment>Confirmar reinicio</translatorcomment>
|
||||
<translation>Confirmar restablecer</translation>
|
||||
<translation>Confirmar borrado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/mainwindow.cpp" line="6841"/>
|
||||
@ -5354,7 +5358,7 @@ Error(%2): %3</translation>
|
||||
<message>
|
||||
<location filename="../SampleDownloader.cpp" line="112"/>
|
||||
<source>Base URL for samples:</source>
|
||||
<translation>Enlace para muestras:</translation>
|
||||
<translation>Enlace de las muestras:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SampleDownloader.cpp" line="113"/>
|
||||
@ -5483,7 +5487,7 @@ Error(%2): %3</translation>
|
||||
<message>
|
||||
<location filename="../Audio/soundout.cpp" line="95"/>
|
||||
<source>No audio output device configured.</source>
|
||||
<translation>No hay dispositivo de salida de audio configurado</translation>
|
||||
<translation>No hay dispositivo de salida de audio configurado.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Audio/soundout.cpp" line="184"/>
|
||||
@ -5974,7 +5978,7 @@ Error(%2): %3</translation>
|
||||
<location filename="../Configuration.ui" line="237"/>
|
||||
<source>Font...</source>
|
||||
<translatorcomment>Letra...</translatorcomment>
|
||||
<translation>Tipo de letra para la aplicación</translation>
|
||||
<translation>Tipo de letra para la aplicación..</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Configuration.ui" line="244"/>
|
||||
@ -6220,7 +6224,7 @@ período de silencio cuando se ha realizado la decodificación.</translation>
|
||||
<message>
|
||||
<location filename="../Configuration.ui" line="628"/>
|
||||
<source>4800</source>
|
||||
<translation></translation>
|
||||
<translation>4800</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Configuration.ui" line="633"/>
|
||||
@ -6832,7 +6836,7 @@ Haz clic derecho para acciones específicas del artículo.
|
||||
Clic, Mayúsculas+Clic y, CTRL+Clic para seleccionar elementos.</translatorcomment>
|
||||
<translation>Arrastre y suelte elementos para reorganizar el orden
|
||||
Clic derecho para acciones específicas del elemento.
|
||||
Clic, Mayús+Clic y CTRL+Clic para seleccionar elementos.</translation>
|
||||
Clic, Mayús+Clic y CTRL+Clic para seleccionar elementos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Configuration.ui" line="1709"/>
|
||||
@ -7559,7 +7563,7 @@ Clic derecho para insertar y eliminar opciones.</translation>
|
||||
<location filename="../Configuration.ui" line="2970"/>
|
||||
<source>Waterfall spectra</source>
|
||||
<translatorcomment>Espectros de la cascada</translatorcomment>
|
||||
<translation>Espectro de la cascada (waterfall)</translation>
|
||||
<translation>Cascada (Waterfall)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Configuration.ui" line="2976"/>
|
||||
|
@ -89,7 +89,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widgets/activeStations.ui" line="141"/>
|
||||
<source><html><head/><body><p>Check tis box to show only stations ready to be called.</p></body></html></source>
|
||||
<source><html><head/><body><p>Check this box to show only stations ready to be called.</p></body></html></source>
|
||||
<translation><html><head/><body><p>Seleziona questa casella per visualizzare solo le stazioni pronte per essere chiamate.</p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,26 @@ void ActiveStations::changeFont (QFont const& font)
|
||||
updateGeometry ();
|
||||
}
|
||||
|
||||
void ActiveStations::clearStations() {
|
||||
m_textbuffer.clear();
|
||||
m_decodes_by_frequency.clear();
|
||||
}
|
||||
|
||||
void ActiveStations::addLine(QString line) {
|
||||
QString m_textbuffer = "";
|
||||
// "012700 -1 0.2 210 ~ KJ7COA JA2HGF -14"
|
||||
unsigned freq = line.mid(16, 4).toUInt();
|
||||
m_decodes_by_frequency[freq] = line;
|
||||
// show them in frequency order
|
||||
QMap<int, QString>::const_iterator i = m_decodes_by_frequency.constBegin();
|
||||
m_textbuffer.clear();
|
||||
while (i != m_decodes_by_frequency.constEnd()) {
|
||||
m_textbuffer.append(i.value());
|
||||
++i;
|
||||
}
|
||||
this->displayRecentStations(m_mode, m_textbuffer);
|
||||
}
|
||||
|
||||
void ActiveStations::read_settings ()
|
||||
{
|
||||
SettingsGroup group {settings_, "ActiveStations"};
|
||||
@ -60,8 +80,7 @@ void ActiveStations::write_settings ()
|
||||
settings_->setValue("WantedOnly",ui->cbWantedOnly->isChecked());
|
||||
}
|
||||
|
||||
void ActiveStations::displayRecentStations(QString mode, QString const& t)
|
||||
{
|
||||
void ActiveStations::setupUi(QString mode) {
|
||||
if(mode!=m_mode) {
|
||||
m_mode=mode;
|
||||
ui->cbReadyOnly->setText(" Ready only");
|
||||
@ -71,24 +90,37 @@ void ActiveStations::displayRecentStations(QString mode, QString const& t)
|
||||
ui->cbReadyOnly->setText("* CQ only");
|
||||
} else if(m_mode=="Q65-pileup") {
|
||||
ui->header_label2->setText(" N Freq Call Grid El Age(h)");
|
||||
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "Wanted only", nullptr));
|
||||
} else if(m_mode=="Fox Mode" || m_mode=="SuperFox Mode" ) {
|
||||
ui->header_label2->setText(" UTC dB DT Freq " + tr("Message"));
|
||||
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "My call only", nullptr));
|
||||
this->setClickOK(true);
|
||||
} else {
|
||||
ui->header_label2->setText(" N Call Grid Az S/N Freq Tx Age Pts");
|
||||
ui->label->setText("Rate:");
|
||||
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "Wanted only", nullptr));
|
||||
}
|
||||
bool b=(m_mode.left(3)=="Q65");
|
||||
ui->bandChanges->setVisible(!b);
|
||||
ui->cbReadyOnly->setVisible(m_mode!="Q65-pileup");
|
||||
ui->cbWantedOnly->setVisible(m_mode!="Q65-pileup");
|
||||
ui->label_2->setVisible(!b);
|
||||
ui->label_3->setVisible(!b);
|
||||
ui->score->setVisible(!b);
|
||||
ui->sbMaxRecent->setVisible(!b);
|
||||
bool is_fox_mode =(m_mode=="Fox Mode");
|
||||
ui->bandChanges->setVisible(!b && !is_fox_mode);
|
||||
ui->cbReadyOnly->setVisible(m_mode != "Q65-pileup" && !is_fox_mode);
|
||||
ui->cbWantedOnly->setVisible(m_mode != "Q65-pileup"); // this is used for "My call only" in Fox mode
|
||||
ui->label_2->setVisible(!b && !is_fox_mode);
|
||||
ui->label_3->setVisible(!b && !is_fox_mode);
|
||||
ui->score->setVisible(!b && !is_fox_mode);
|
||||
ui->sbMaxRecent->setVisible(!b && !is_fox_mode);
|
||||
|
||||
b=(m_mode!="Q65-pileup");
|
||||
b=(m_mode!="Q65-pileup" && !is_fox_mode);
|
||||
ui->sbMaxAge->setVisible(b);
|
||||
ui->label->setVisible(b);
|
||||
ui->rate->setVisible(b);
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveStations::displayRecentStations(QString mode, QString const& t)
|
||||
{
|
||||
setupUi(mode);
|
||||
|
||||
bool bClickOK=m_clickOK;
|
||||
m_clickOK=false;
|
||||
ui->RecentStationsPlainTextEdit->setPlainText(t);
|
||||
@ -143,7 +175,10 @@ void ActiveStations::on_textEdit_clicked()
|
||||
if(text!="") {
|
||||
int nline=text.left(2).toInt();
|
||||
if(QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) nline=-nline;
|
||||
emit callSandP(nline);
|
||||
if (!m_mode.contains("fox", Qt::CaseInsensitive))
|
||||
emit callSandP(nline);
|
||||
else
|
||||
emit queueActiveWindowHound(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user