Compare commits

..

227 Commits

Author SHA1 Message Date
Jordan Sherer 6d7b187269 Fixed table column swap for snr and offset 2018-11-01 00:50:39 -04:00
Jordan Sherer 13308a38f8 Fixed sync for non APPLE 2018-11-01 00:44:14 -04:00
Jordan Sherer 804605e9e6 Fixed text count for APPLE 2018-11-01 00:41:15 -04:00
Jordan Sherer 4e981da9c8 Fixed send button initial frame count. Fixed apple specific text counting 2018-11-01 00:37:29 -04:00
Jordan Sherer 6436e163bd Fixed QSO log not uppercase callsign 2018-11-01 00:20:20 -04:00
Jordan Sherer 379a0fa78f Fixed bug with auto-replies using selected callsign as the directed callsign 2018-11-01 00:06:09 -04:00
Jordan Sherer 1c4a2ab7d8 Fix bug with fort.19 2018-11-01 00:05:41 -04:00
Jordan Sherer 54f6bdb0af Bump to v0.8.1 2018-10-31 22:13:26 -04:00
Jordan Sherer 5a0e2a8b14 Fixed time delta average reset on activity clear 2018-10-31 22:10:04 -04:00
Jordan Sherer 1a9c611195 Fixed issue with tdrift average when reset 2018-10-31 22:09:03 -04:00
Jordan Sherer c70661461e Fixed selcall button should prevent heartbeat acks 2018-10-31 21:52:58 -04:00
Jordan Sherer 1f866e14f1 Hotfix. Fixed heartbear idle min value should be zero 2018-10-31 21:42:08 -04:00
Jordan Sherer c0e8a791e6 Hotfix. Broken heartbeat ack when a directed callsign is selected 2018-10-31 18:17:34 -04:00
Jordan Sherer 74523985bb Time drift button labeling 2018-10-31 11:58:11 -04:00
Jordan Sherer 8d28ea345a 0.8 is not backwards compatible 2018-10-31 11:56:12 -04:00
Jordan Sherer 33446297fa Update heartbeat to allow on demand only. Add AUTO requirement for ACKs 2018-10-31 10:51:17 -04:00
Jordan Sherer 6f648d5a60 Added compatibility parsing for commands 2018-10-30 21:00:04 -04:00
Jordan Sherer f1f618bbcd Added worked before status 2018-10-30 20:50:31 -04:00
Jordan Sherer ac7da998a2 15 seconds is not now 2018-10-30 17:04:30 -04:00
Jordan Sherer b3cd705fb6 OCD 2018-10-30 17:00:14 -04:00
Jordan Sherer 604e366d4a Rig name in title 2018-10-29 22:41:54 -04:00
Jordan Sherer 8d73805dce Average time drift labels 2018-10-29 22:34:26 -04:00
Jordan Sherer 5c491dc10d Update threshold and tones. Cleanup bits 2018-10-29 17:56:31 -04:00
Jordan Sherer d611259a25 Fixed typo in varicode 2018-10-29 13:39:15 -04:00
Jordan Sherer 00f2d46167 Reduce late start threshold to 2 seconds 2018-10-29 09:24:52 -04:00
Jordan Sherer e4cba50144 Better labeling 2018-10-29 09:24:38 -04:00
Jordan Sherer 440311a75b Restructured data frame packing so we can send more over the wire in fewer frames 2018-10-29 03:26:10 -04:00
Jordan Sherer 38fc98702b Average time delta computation 2018-10-29 02:02:58 -04:00
Jordan Sherer 6201de8c12 Tweak decoder for better decodes under poor conditions 2018-10-29 01:09:17 -04:00
Jordan Sherer 4321bd5e75 Time drift columns and show column labels 2018-10-28 17:54:10 -04:00
Jordan Sherer 9f7fd2e7e2 Replaced character queries with textual queries to make it easier to read 2018-10-28 12:37:47 -04:00
Jordan Sherer 65a2411c46 Better interface for idle timer values 2018-10-28 12:06:37 -04:00
Jordan Sherer d076eedeb8 Fixed idle timer for idle watchdog 2018-10-28 11:24:00 -04:00
Jordan Sherer 7da30200f5 Heartbeat commands instead 2018-10-28 10:06:03 -04:00
Jordan Sherer cac5f798a3 Rename beacon to heartbean with pings and ping acks 2018-10-28 09:52:07 -04:00
Jordan Sherer 41fb7481ed Bump eol 2018-10-28 09:50:16 -04:00
Jordan Sherer 09effda8e4 Added default macro for CQ message 2018-10-27 15:25:23 -04:00
Jordan Sherer eecf7f65c7 Macro for CQ, Reply, QTH, QTC messages 2018-10-27 15:19:49 -04:00
Jordan Sherer 0618b1cc09 Do not allow text overrides for selected calls during parsing 2018-10-27 15:14:54 -04:00
Jordan Sherer 00685b9117 Warning message for stupid messages 2018-10-27 15:01:27 -04:00
Jordan Sherer a5a6c95a44 Added SK short message 2018-10-27 14:54:48 -04:00
Jordan Sherer 8612f2cd32 Hashed messages have a 16-bit checksum instead of a 32-bit checksum 2018-10-27 14:52:11 -04:00
Jordan Sherer 5fa60659f3 Idle minutes should always be incremented 2018-10-27 14:51:11 -04:00
Jordan Sherer 08629019d4 Added macro like functionality for saved messages 2018-10-27 14:41:57 -04:00
Jordan Sherer 7293d1e796 Remove table configuration from context menu 2018-10-27 14:41:40 -04:00
Jordan Sherer aff001ce96 Bump to v0.8.0 2018-10-27 12:42:16 -04:00
Jordan Sherer 31d80a9b1d Updated configuration tooltip and validation 2018-10-27 12:41:30 -04:00
Jordan Sherer 9010fa07c0 Replace ALLCALL with @ALLCALL 2018-10-27 10:13:34 -04:00
Jordan Sherer 121bb0fdb5 Replace GROUPCALL with actual group calls 2018-10-27 10:09:40 -04:00
Jordan Sherer 47a7c06854 Added configuration for groups 2018-10-27 09:54:13 -04:00
Jordan Sherer c4089c0af9 Don't allow compound calls greater than 9 chars 2018-10-27 09:53:57 -04:00
Jordan Sherer 5c28d154ff Added autoprepend back in 2018-10-26 22:16:48 -04:00
Jordan Sherer 6dfd037736 Compound callsigns and group callsigns parse correctly 2018-10-26 22:10:08 -04:00
Jordan Sherer 3767b347d9 Working compound extended callsigns with group identifiers 2018-10-26 22:10:07 -04:00
Jordan Sherer ff12fd2240 Added validation message for callsigns 2018-10-26 22:10:07 -04:00
Jordan Sherer 6a0fea1d0a Experiment trying to extend compound callsigns 2018-10-26 22:10:07 -04:00
Jordan Sherer f11e02c966 Do not delete band activity or call activity rows that are selected 2018-10-26 22:09:38 -04:00
Jordan Sherer 0763ecfe37 Expose transmit delay in configuration 2018-10-23 12:35:09 -04:00
Jordan Sherer 4c3ed5c719 Removed temp txt file 2018-10-23 12:34:29 -04:00
Jordan Sherer 0064176736 Reduce late start to 25% 2018-10-23 02:26:19 -04:00
Jordan Sherer 67386a09c7 Simple buffered directed commands should log immediately 2018-10-23 02:18:03 -04:00
Jordan Sherer 3c81108cc6 Moved relay responses into the main window 2018-10-23 02:06:24 -04:00
Jordan Sherer 71ed0c1f10 Added menu for decode depth. Removed some WSPR. 2018-10-21 15:37:12 -04:00
Jordan Sherer 20a44171e4 Ripped out decoded.txt and houndcallers.txt junk 2018-10-20 09:04:03 -04:00
Jordan Sherer 644633721f Disable stations heard command: 2018-10-19 09:53:51 -04:00
Jordan Sherer 8529ef0982 Fixed allcall and groupcall counts to respect aging 2018-10-18 10:51:53 -04:00
Jordan Sherer 8bba574963 Fixed issue where whitespace broke ACKd messages 2018-10-17 14:36:15 -04:00
Jordan Sherer 80d798d7e3 Fixed APRS passcode warning 2018-10-17 14:31:23 -04:00
Jordan Sherer 23a554220b Fixed APRS passcode warning 2018-10-17 14:30:32 -04:00
Jordan Sherer 7e903349ae Added QTC, QTH, and Saved messages to the 'immediately transmit' setting 2018-10-17 14:23:17 -04:00
Jordan Sherer 55810e63a6 Transmit entry should be JS8 not FT8 2018-10-17 14:17:53 -04:00
Jordan Sherer 9162d851d4 Made some adjustments to the tx cycling...should help those having trouble with their audio interface not working fast enough. 2018-10-17 11:19:27 -04:00
Jordan Sherer 2022908509 Bump to 0.7.5 2018-10-17 09:11:05 -04:00
Jordan Sherer 2e2551519d Added ACTIVE/IDLE query. Fixed CQ start transmission. 2018-10-17 09:08:37 -04:00
Jordan Sherer 18052773f1 Added clarification labels to the configuration 2018-10-17 08:58:54 -04:00
Jordan Sherer 51010e7310 Allow out of period starts toggles 2018-10-16 20:15:04 -04:00
Jordan Sherer a3eaf1cf74 Fixed BEACON ACK printing overwrite 2018-10-16 17:47:38 -04:00
Jordan Sherer c731fa51ce Fixed menu shortkeys 2018-10-16 17:23:12 -04:00
Jordan Sherer a5f59019d3 Remove unused count message frames function 2018-10-16 17:09:19 -04:00
Jordan Sherer 4a87edc4c7 Fixed compound callsigns and directed messages (SNR reports) 2018-10-16 16:11:28 -04:00
Jordan Sherer 2da25c3171 Move around the force update to be more reliable 2018-10-16 09:49:53 -04:00
Jordan Sherer 87a6e10bd6 Added async frame counting 2018-10-15 22:06:31 -04:00
Jordan Sherer cf9c74b99e Fixed issue with multiple beacon acks not displaying in rx window 2018-10-15 12:43:49 -04:00
Jordan Sherer dae50d3a99 Added constants for NEAR thresholds 2018-10-15 12:10:13 -04:00
Jordan Sherer 83268fbdaf Added groupcall and allcall callsign counts 2018-10-15 12:01:28 -04:00
Jordan Sherer 3b2242e258 Fixed display of APRS frames where a space after the colon causes concern 2018-10-15 11:53:54 -04:00
Jordan Sherer c42c3b7ad1 Added lookup cache to the lookup function 2018-10-15 03:03:26 -04:00
Jordan Sherer 9496d5ed81 Deslect callsign on click cq button 2018-10-15 02:41:35 -04:00
Jordan Sherer 83174bc6fa Fixed stations heard ordering (by time) 2018-10-15 02:37:21 -04:00
Jordan Sherer d74850b8e1 Fixed reversed qtc qth macro buttons 2018-10-15 02:30:46 -04:00
Jordan Sherer 2f1dca3c49 Updated comments 2018-10-15 02:29:40 -04:00
Jordan Sherer 4a38778808 Removed single shot timer from gui loop 2018-10-15 02:10:48 -04:00
Jordan Sherer 960b9b14d1 Rip out fox/hound junk 2018-10-15 01:04:57 -04:00
Jordan Sherer 9e93745587 Instrumentation and pull ui update async 2018-10-15 00:59:38 -04:00
Jordan Sherer 8aa28108ea Fixed font dialog for OSX 2018-10-11 10:49:48 -04:00
Jordan Sherer 4168e1937c Fixed beacon scheduling with a beacon now context menu item 2018-10-11 01:11:48 -04:00
Jordan Sherer f4b640df75 Fixed incremental directed decode for compound calls 2018-10-11 01:01:38 -04:00
Jordan Sherer cf1cece11c Added log button back in. Moved halt button up to balance. Added pressed state 2018-10-11 00:21:34 -04:00
Jordan Sherer 59893f6dfa Fixed label for relay dialog message notifications 2018-10-11 00:16:07 -04:00
Jordan Sherer ead5c225b5 Fixed separator for restore previous message action 2018-10-11 00:15:52 -04:00
Jordan Sherer 4744952a1a Fixed issue with button and text display in the gui event loop 2018-10-10 17:43:11 -04:00
Jordan Sherer a30bff5589 Bump to 0.7.3 2018-10-10 16:01:54 -04:00
Jordan Sherer e7e2f8357f Fixed idle timer alert 2018-10-10 15:36:53 -04:00
Jordan Sherer 4ffa82f695 Fixed default idle timer 2018-10-10 15:29:48 -04:00
Jordan Sherer 3e38067561 Fixed incremental directed message receipt for ALLCALL and GROUPCALL 2018-10-10 13:35:52 -04:00
Jordan Sherer 52177a0513 Fixed parsing of commands to not split up command words 2018-10-10 10:10:30 -04:00
Jordan Sherer f79ca47a93 Fixed incremental print for directed messages.
Fixed compound calls in the heard list
2018-10-10 09:04:56 -04:00
Jordan Sherer f0e30dc7b0 Fixed compound calls / beacon / cq differentiation 2018-10-09 20:09:53 -04:00
Jordan Sherer d20fe46447 Fixed tx first dependence on checkbox and potential delay caused by event processing 2018-10-09 17:44:36 -04:00
Jordan Sherer aa2c41f124 Initial tx cycle cleanup 2018-10-09 17:33:30 -04:00
Jordan Sherer ad563c0aed LDPC codeword update 2018-10-09 15:36:50 -04:00
Jordan Sherer 60b58fb50f Fixed display of beacons and beacon acks when not beaconining 2018-10-09 15:26:13 -04:00
Jordan Sherer ca79a450ca Fixed beacon queue reset on beacon toggle 2018-10-09 15:03:30 -04:00
Jordan Sherer 3c8c80a5d7 Fixed side-effect of double space fix, where F characters were not being encoded correctly 2018-10-09 14:12:00 -04:00
Jordan Sherer fc43c7fbb4 Fixed issue with directed commands splitting up words that appear in the command. E.g., 'NO' 'T' 2018-10-09 09:31:33 -04:00
Jordan Sherer 353d75ac49 Fixed double space compression issue by word replacement for a space character 2018-10-08 15:36:09 -04:00
Jordan Sherer 2d392dd676 Fixed trimming of trailing whitespace for configuration messages and grids 2018-10-08 15:04:10 -04:00
Jordan Sherer 18fac2e4ba Fixed BEACON ACK replies to CQs 2018-10-08 15:00:54 -04:00
Jordan Sherer 5275c0916f Fixed window frame on windows 2018-10-07 11:30:02 -04:00
Jordan Sherer 676aa3c78e Don't close the app when expired...just be really annoying 2018-10-07 11:01:01 -04:00
Jordan Sherer 4e8a65b5ee Move EOL to Oct 31 2018-10-07 10:52:03 -04:00
Jordan Sherer 329ca0b23f Bump to 0.7.2 2018-10-07 10:51:30 -04:00
Jordan Sherer 29cb01697a Bump to 25Hz buffer 2018-10-07 10:51:08 -04:00
Jordan Sherer e27e7baec9 Added groupcall to compound parsing. 2018-10-07 08:44:47 -04:00
Jordan Sherer 9cd17a4441 Only one beacon ack per frame 2018-10-06 23:37:32 -04:00
Jordan Sherer 9d371c474a Fixed truncated grid issue 2018-10-06 23:28:00 -04:00
Jordan Sherer 5e54b85fe0 Changed SELCAL label to SELCALL 2018-10-06 09:07:26 -04:00
Jordan Sherer 286e32bf4e Added save directory. Tweaked groupcall Hz 2018-10-06 09:06:47 -04:00
Jordan Sherer 48dbe28031 Added a groupcall row while in selcal mode to replace 'allcall' 2018-10-06 08:22:43 -04:00
Jordan Sherer f95df562f7 Fix SELCAL button band activity table restoration 2018-10-06 04:12:16 -04:00
Jordan Sherer 1f210bba63 GROUPCALL easter egg 2018-10-06 03:59:54 -04:00
Jordan Sherer 4df77ac774 Bump to v0.7.1 2018-10-06 03:16:25 -04:00
Jordan Sherer aa151c10e1 Added drift protection in message buffers. Up to 10Hz per 15-second transmission cycles 2018-10-06 02:55:59 -04:00
Jordan Sherer db5e9e6520 Widen grid column 2018-10-06 02:15:09 -04:00
Jordan Sherer f22d51b53e Fixed send button highlight 2018-10-06 02:13:08 -04:00
Jordan Sherer 68f9b2a5ff Fix beacon grids 2018-10-06 02:12:12 -04:00
Jordan Sherer 444abf57ff Mark beacon sub-channel in waterfall 2018-10-06 02:03:39 -04:00
Jordan Sherer ffb6bb679a SELCAL should restore band activity 2018-10-06 01:56:55 -04:00
Jordan Sherer 34773a3b98 Fix button label 2018-10-06 01:51:15 -04:00
Jordan Sherer b2e623a488 Smaller dictionary. Realtime text computation 2018-10-06 01:43:47 -04:00
Jordan Sherer 0e82edc9ea Turn off counting to start... 2018-10-05 18:40:56 -04:00
Jordan Sherer cfa93839df Make sure costas is completely updated 2018-10-05 18:10:06 -04:00
Jordan Sherer 6a8b3960d7 Default to 2 bins per pixel 2018-10-05 10:23:28 -04:00
Jordan Sherer 97ccbbd049 Fixed bug with send button not disabling on text clear 2018-10-05 09:01:25 -04:00
Jordan Sherer f4090ece63 Remove UDP_NO_EXPORT 2018-10-04 18:52:28 -04:00
Jordan Sherer c7a1f6c72a Remove UDP_EXPORT 2018-10-04 18:51:11 -04:00
Jordan Sherer 1a61dc53cc Remove foxcom 2018-10-04 18:20:35 -04:00
Jordan Sherer cbb6cf9a24 Remove foxcom for OSX 2018-10-04 18:17:56 -04:00
Jordan Sherer 3c46f8e276 Fix revisiontag target 2018-10-04 16:51:40 -04:00
Jordan Sherer f56af06140 Window title 2018-10-04 16:39:54 -04:00
Jordan Sherer 877c6e1d9d Rename in JSC codebooks 2018-10-04 13:58:39 -04:00
Jordan Sherer 75bf51072a Rename to JS8Call 2018-10-04 13:52:52 -04:00
Jordan Sherer d5c22a0c91 JS8 Mode 2018-10-04 12:03:21 -04:00
Jordan Sherer 5d136fa1b8 General cleanup 2018-10-04 11:58:55 -04:00
Jordan Sherer 05f0c3f111 Remove extraneous files 2018-10-04 11:55:08 -04:00
Jordan Sherer 1935f610d3 Rename INSTALL 2018-10-04 11:52:53 -04:00
Jordan Sherer 6b20cda1c0 Cleanup old files, documentation, samples, and other remnants 2018-10-04 11:52:02 -04:00
Jordan Sherer bbae64f923 Updated README 2018-10-04 08:43:10 -04:00
Jordan Sherer cb48947e9f Mode name is now JS8 2018-10-03 22:27:50 -04:00
Jordan Sherer beec31c9b8 Extracted function to write messages to log file 2018-10-03 21:32:00 -04:00
Jordan Sherer 383f5d0943 Add beacon option to transmit anywhere 2018-10-03 18:55:57 -04:00
Jordan Sherer cb682748c7 Draw warning on the upper edge of the band 2018-10-03 18:55:45 -04:00
Jordan Sherer 6cce8230f2 Removed block for lower frequencies, but keeping the orange caution 2018-10-03 18:29:38 -04:00
Jordan Sherer 0ca7c332f6 Beacon between 750Hz and 1250Hz 2018-10-03 18:27:43 -04:00
Jordan Sherer 075b041b0d Removed CRC mod 2018-10-03 18:25:55 -04:00
Jordan Sherer 302e59e403 Merge branch 'ft8call-costas' into ft8call-develop 2018-10-03 18:15:26 -04:00
Jordan Sherer 1461f00a84 UI Tweaks for sanity: 2018-10-03 17:10:43 -04:00
Jordan Sherer 10f4049e68 Do not transmit if callsign isnt selected in selcal mode 2018-10-03 16:54:25 -04:00
Jordan Sherer f1db556598 Hide allcall when selcal enabled 2018-10-03 16:30:53 -04:00
Jordan Sherer 93299ec7da Don't buffer if its a directed command and its the last frame (unless it's a compound call) 2018-10-03 15:13:43 -04:00
Jordan Sherer 289d38538a Do not start at < 1000Hz 2018-10-03 14:59:10 -04:00
Jordan Sherer 60fde40f58 Added menus to the context menus 2018-10-03 14:56:35 -04:00
Jordan Sherer 646848cba1 Added QRZ short command 2018-10-03 14:50:25 -04:00
Jordan Sherer b5d7aa8fa8 Buffer all directed free text 2018-10-03 14:37:34 -04:00
Jordan Sherer 6bb3c22bec Added fallback huffman table for basic text packing 2018-10-03 12:36:45 -04:00
Jordan Sherer 1fd3b60ba3 Fixed color of the send button when issued a directed cmd 2018-10-03 09:57:40 -04:00
Jordan Sherer fe1cbcf6c6 APRS call cache 2018-10-03 09:55:43 -04:00
Jordan Sherer 119499afa4 Added better debounce logic for text counting 2018-10-03 08:59:14 -04:00
Jordan Sherer c26a042a92 Removed debounce comment 2018-10-03 08:09:21 -04:00
Jordan Sherer 48c33157f4 Optimizing list and map 2018-10-02 23:00:26 -04:00
Jordan Sherer 8c5ba5edf0 Optimizing list and map 2018-10-02 22:58:40 -04:00
Jordan Sherer 3ba51a1085 Tweaking list and map 2018-10-02 22:45:22 -04:00
Jordan Sherer 7fd792ba82 Updated JSC list 2018-10-02 22:07:00 -04:00
Jordan Sherer 4e1ff07d7f Updated jsc list and map definitions 2018-10-02 21:46:02 -04:00
Jordan Sherer 7f992433dc Add Tuple struct with precomputed inverse index 2018-10-02 18:03:15 -04:00
Jordan Sherer 2cb1665e2e Added background thread to compute message frames 2018-10-02 14:38:14 -04:00
Jordan Sherer 862e702b2d Only update count for send button if the text box is dirty 2018-10-02 14:37:12 -04:00
Jordan Sherer 2f6ed1b89c Working through compression implementation for data frames 2018-10-02 14:37:12 -04:00
Jordan Sherer 489cf3a85c Added static built data list 2018-10-02 14:37:12 -04:00
Jordan Sherer 188d775b7f Initial commit of SCDC compression 2018-10-02 14:37:12 -04:00
Jordan Sherer ec4df58787 Woops. Extra class qualifier. 2018-10-02 14:32:49 -04:00
Jordan Sherer 4e1c04f74a Fixed packet format for APRS 2018-10-02 14:28:33 -04:00
Jordan Sherer d042fffe75 Do not have the palette button as the default 2018-10-02 14:20:05 -04:00
Jordan Sherer 2199b8b057 Deselect callsign after 1 hour 2018-10-02 14:10:16 -04:00
Jordan Sherer 344635c75f Bump EOL and message 2018-10-02 09:54:09 -04:00
Jordan Sherer 41977d6b61 Added directed menu to the edit context menu 2018-10-02 09:54:00 -04:00
Jordan Sherer ef8bc26474 Turn off tx before remembering our tune settings 2018-10-01 13:06:31 -04:00
Jordan Sherer d000925ecb Allow ini overide 2018-09-29 17:42:15 -04:00
Jordan Sherer b3fd715063 We do not need these null checks 2018-09-29 17:31:01 -04:00
Jordan Sherer 85ccc14549 Added ack sorting 2018-09-29 17:30:27 -04:00
Jordan Sherer e5f4cd4753 Added indicators for callsigns who can hear you 2018-09-29 17:04:05 -04:00
Jordan Sherer 4426dc77dc Added Joe 2018-09-29 12:20:11 -04:00
Jordan Sherer 17f07caf72 Added callsign to directed button 2018-09-24 21:23:24 -04:00
Jordan Sherer 420f8d0fcc Disabled menu item for ALLCALL SNR query 2018-09-24 21:06:12 -04:00
Jordan Sherer 434942ad29 Labeling 2018-09-24 21:02:23 -04:00
Jordan Sherer aab859a580 Added column hiding for band and call activity 2018-09-24 16:46:33 -04:00
Jordan Sherer f71a5f2174 Turned off SELCAL until I can figure out an operating pattern 2018-09-24 15:34:11 -04:00
Jordan Sherer cd30ac1d3d Removed WSJT-X executables that are not needed 2018-09-24 15:07:55 -04:00
Jordan Sherer f6138f4c4b Removed legacy UDPExamples 2018-09-24 14:34:11 -04:00
Jordan Sherer 573fa4f8f9 Added drift offset to UTC label 2018-09-23 16:47:07 -04:00
Jordan Sherer 522f5cf743 Renamed Runaway Tx to Idle Watchdog 2018-09-23 16:41:06 -04:00
Jordan Sherer a0abda9313 Cleaning up stopTx 2018-09-23 16:20:26 -04:00
Jordan Sherer 8591512800 Fixed bug in synchronizer with empty audio frames (hopefully) 2018-09-23 15:14:40 -04:00
Jordan Sherer db650e970a Ripped out a bunch of fox mode crap 2018-09-23 10:22:28 -04:00
Jordan Sherer a5b2eeab5d Started basic selcal functionality 2018-09-21 22:41:20 -04:00
Jordan Sherer f3f051d17c Removed aprs.py 2018-09-21 14:43:19 -04:00
Jordan Sherer 0451f6aca9 Fixing some APRS packet structures 2018-09-21 14:43:02 -04:00
Jordan Sherer 25e7631c09 Added automatic BEACON acknowledgment and BEACON REQ commands 2018-09-21 01:47:21 -04:00
Jordan Sherer fe1509c94b Renamed macros to saved messages. Added menu and buttons for quick access to all messages configured 2018-09-20 10:46:04 -04:00
Jordan Sherer 8b94c01ff6 Added methods to grab default huff tables 2018-09-20 10:04:18 -04:00
Jordan Sherer 2ab31a663a Updated costas to actually be a costas array. See 7x7 array enumeration here: http://jameskbeard.com/jameskbeard/Files.html#CostasArrays 2018-09-19 14:27:28 -04:00
Jordan Sherer f6edea8753 Fixed show/hide default for time drift 2018-09-18 21:22:00 -04:00
Jordan Sherer 00cede3763 Bump to 0.7.0 2018-09-18 18:08:45 -04:00
Jordan Sherer 79bc33bcb7 Added menu item to show time drift controls 2018-09-18 18:07:49 -04:00
Jordan Sherer d08096a934 Initial commit of manual clock drift syncronization 2018-09-18 17:24:07 -04:00
Jordan Sherer 4e094b791c Added new CQ parsing to be more intuitive 2018-09-18 10:53:43 -04:00
Jordan Sherer 1817e298b1 Fixed split rig offset bug during restore freq 2018-09-16 11:30:13 -04:00
272 changed files with 529932 additions and 16604 deletions
+34 -10
View File
@@ -2,15 +2,16 @@
#include <cmath>
#include "DriftingDateTime.h"
#include "varicode.h"
const int PACKET_TIMEOUT_SECONDS = 300;
APRSISClient::APRSISClient(QString host, quint16 port, QObject *parent):
QTcpSocket(parent),
m_host(host),
m_port(port)
QTcpSocket(parent)
{
setServer(host, port);
connect(&m_timer, &QTimer::timeout, this, &APRSISClient::sendReports);
m_timer.setInterval(60*1000); // every 60 seconds
m_timer.start();
@@ -37,7 +38,7 @@ QString APRSISClient::loginFrame(QString callsign){
auto loginFrame = QString("user %1 pass %2 ver %3\n");
loginFrame = loginFrame.arg(callsign);
loginFrame = loginFrame.arg(hashCallsign(callsign));
loginFrame = loginFrame.arg("FT8Call");
loginFrame = loginFrame.arg("JS8Call");
return loginFrame;
}
@@ -183,13 +184,35 @@ QPair<QString, QString> APRSISClient::grid2aprs(QString grid){
};
}
QString APRSISClient::stripSSID(QString call){
return QString(call.split("-").first().toUpper());
}
QString APRSISClient::replaceCallsignSuffixWithSSID(QString call, QString base){
if(call != base){
QRegularExpression re("[/](?<ssid>(P|\\d+))");
auto matcher = re.globalMatch(call);
if(matcher.hasNext()){
auto match = matcher.next();
auto ssid = match.captured("ssid");
if(ssid == "P"){
ssid = "16";
}
call = base + "-" + ssid;
} else {
call = base;
}
}
return call;
}
void APRSISClient::enqueueSpot(QString theircall, QString grid, QString comment){
if(m_localCall.isEmpty()) return;
auto geo = APRSISClient::grid2aprs(grid);
auto spotFrame = QString("%1>%2,APRS,TCPIP*:=%3/%4nFT8CALL %5\n");
auto spotFrame = QString("%1>APRS,%2,TCPIP*:=%3/%4nJS8 %5\n");
spotFrame = spotFrame.arg(theircall);
spotFrame = spotFrame.arg(m_localCall);
spotFrame = spotFrame.arg(stripSSID(m_localCall));
spotFrame = spotFrame.arg(geo.first);
spotFrame = spotFrame.arg(geo.second);
spotFrame = spotFrame.arg(comment.left(43));
@@ -201,15 +224,15 @@ void APRSISClient::enqueueThirdParty(QString theircall, QString payload){
return;
}
auto frame = QString("%1>%2,APRS,TCPIP*:%3\n");
auto frame = QString("%1>APRS,%2,TCPIP*:%3\n");
frame = frame.arg(theircall);
frame = frame.arg(m_localCall);
frame = frame.arg(stripSSID(m_localCall));
frame = frame.arg(payload);
enqueueRaw(frame);
}
void APRSISClient::enqueueRaw(QString aprsFrame){
m_frameQueue.enqueue({ aprsFrame, QDateTime::currentDateTimeUtc() });
m_frameQueue.enqueue({ aprsFrame, DriftingDateTime::currentDateTimeUtc() });
}
void APRSISClient::processQueue(bool disconnect){
@@ -225,6 +248,7 @@ void APRSISClient::processQueue(bool disconnect){
// 4. disconnect
if(state() != QTcpSocket::ConnectedState){
qDebug() << "APRSISClient Connecting:" << m_host << m_port;
connectToHost(m_host, m_port);
if(!waitForConnected(5000)){
qDebug() << "APRSISClient Connection Error:" << errorString();
@@ -263,7 +287,7 @@ void APRSISClient::processQueue(bool disconnect){
auto timestamp = pair.second;
// if the packet is older than the timeout, drop it.
if(timestamp.secsTo(QDateTime::currentDateTimeUtc()) > PACKET_TIMEOUT_SECONDS){
if(timestamp.secsTo(DriftingDateTime::currentDateTimeUtc()) > PACKET_TIMEOUT_SECONDS){
qDebug() << "APRSISClient Packet Timeout:" << frame;
m_frameQueue.dequeue();
continue;
+4
View File
@@ -17,6 +17,8 @@ public:
static QString loginFrame(QString callsign);
static QPair<float, float> grid2deg(QString grid);
static QPair<QString, QString> grid2aprs(QString grid);
static QString stripSSID(QString call);
static QString replaceCallsignSuffixWithSSID(QString call, QString base);
void setServer(QString host, quint16 port){
if(state() == QTcpSocket::ConnectedState){
@@ -25,6 +27,8 @@ public:
m_host = host;
m_port = port;
qDebug() << "APRSISClient Server Change:" << m_host << m_port;
}
void setPaused(bool paused){
-4
View File
@@ -1,4 +0,0 @@
Joe Taylor, K1JT <k1jt@arrl.net>
See also about.cpp or "Help->About WSJT-X" in the application for
details of other contributions.
-14
View File
@@ -1,14 +0,0 @@
__ __ ______ _____ ________ __ __
| \ _ | \ / \ | \| \ | \ | \
| $$ / \ | $$| $$$$$$\ \$$$$$ \$$$$$$$$ | $$ | $$
| $$/ $\| $$| $$___\$$ | $$ | $$ ______ \$$\/ $$
| $$ $$$\ $$ \$$ \ __ | $$ | $$| \ >$$ $$
| $$ $$\$$\$$ _\$$$$$$\| \ | $$ | $$ \$$$$$$/ $$$$\
| $$$$ \$$$$| \__| $$| $$__| $$ | $$ | $$ \$$\
| $$$ \$$$ \$$ $$ \$$ $$ | $$ | $$ | $$
\$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$
There are some defects remaining in WSJT-X.
+14 -15
View File
@@ -9,8 +9,8 @@ set (CPACK_PACKAGE_CONTACT "@PROJECT_CONTACT@")
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "@PROJECT_SUMMARY_DESCRIPTION@")
set (CPACK_RESOURCE_FILE_LICENSE "@PROJECT_SOURCE_DIR@/COPYING")
set (CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
set (CPACK_PACKAGE_EXECUTABLES ft8call "@PROJECT_NAME@")
set (CPACK_CREATE_DESKTOP_LINKS ft8call)
set (CPACK_PACKAGE_EXECUTABLES js8call "@PROJECT_NAME@")
set (CPACK_CREATE_DESKTOP_LINKS js8call)
set (CPACK_STRIP_FILES TRUE)
#
@@ -24,7 +24,7 @@ if (CPACK_GENERATOR MATCHES "NSIS")
set (CPACK_SET_DESTDIR FALSE)
set (CPACK_STRIP_FILES FALSE) # breaks Qt packaging on Windows
# set (CPACK_NSIS_INSTALL_ROOT "C:\\FT8Call")
# set (CPACK_NSIS_INSTALL_ROOT "C:\\JS8Call")
if(CMAKE_CL_64)
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
@@ -38,23 +38,22 @@ if (CPACK_GENERATOR MATCHES "NSIS")
# set the install/unistall icon used for the installer itself
# There is a bug in NSI that does not handle full unix paths properly.
set (CPACK_NSIS_MUI_ICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\ft8call.ico")
set (CPACK_NSIS_MUI_UNIICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\ft8call.ico")
set (CPACK_NSIS_MUI_ICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\js8call.ico")
set (CPACK_NSIS_MUI_UNIICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\js8call.ico")
# set the package header icon for MUI
set (CPACK_PACKAGE_ICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\installer_logo.bmp")
# tell cpack to create links to the doc files
set (CPACK_NSIS_MENU_LINKS
"@PROJECT_MANUAL_DIRECTORY_URL@/@PROJECT_MANUAL@" "@PROJECT_NAME@ Documentation"
"@PROJECT_HOMEPAGE@" "@PROJECT_NAME@ Web Site"
)
# Use the icon from wsjtx for add-remove programs
set (CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\ft8call.exe")
set (CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\js8call.exe")
set (CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
set (CPACK_NSIS_HELP_LINK "@PROJECT_MANUAL_DIRECTORY_URL@/@PROJECT_MANUAL@")
set (CPACK_NSIS_HELP_LINK "@PROJECT_HOMEPAGE@")
set (CPACK_NSIS_URL_INFO_ABOUT "@PROJECT_HOMEPAGE@")
set (CPACK_NSIS_CONTACT "${CPACK_PACKAGE_CONTACT}")
set (CPACK_NSIS_MUI_FINISHPAGE_RUN "ft8call.exe")
set (CPACK_NSIS_MUI_FINISHPAGE_RUN "js8call.exe")
set (CPACK_NSIS_MODIFY_PATH ON)
endif ()
@@ -67,11 +66,11 @@ endif ()
if ("${CPACK_GENERATOR}" STREQUAL "DragNDrop")
set (CPACK_DMG_VOLUME_NAME "@PROJECT_NAME@")
set (CPACK_DMG_BACKGROUND_IMAGE "@PROJECT_SOURCE_DIR@/icons/Darwin/DragNDrop Background.png")
set (CPACK_DMG_DS_STORE "@PROJECT_SOURCE_DIR@/Darwin/ft8call_DMG.DS_Store")
set (CPACK_DMG_DS_STORE "@PROJECT_SOURCE_DIR@/Darwin/js8call_DMG.DS_Store")
set (CPACK_BUNDLE_NAME "@WSJTX_BUNDLE_NAME@")
set (CPACK_PACKAGE_ICON "@PROJECT_BINARY_DIR@/ft8call.icns")
set (CPACK_BUNDLE_ICON "@PROJECT_BINARY_DIR@/ft8call.icns")
set (CPACK_BUNDLE_STARTUP_COMMAND "@PROJECT_SOURCE_DIR@/Mac-ft8call-startup.sh")
set (CPACK_PACKAGE_ICON "@PROJECT_BINARY_DIR@/js8call.icns")
set (CPACK_BUNDLE_ICON "@PROJECT_BINARY_DIR@/js8call.icns")
set (CPACK_BUNDLE_STARTUP_COMMAND "@PROJECT_SOURCE_DIR@/Mac-js8call-startup.sh")
set (CPACK_PACKAGING_INSTALL_PREFIX "/")
endif ()
@@ -79,9 +78,9 @@ if ("${CPACK_GENERATOR}" STREQUAL "WIX")
# Reset CPACK_PACKAGE_VERSION to deal with WiX restriction.
# But the file names still use the full CMake_VERSION value:
set (CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-@ft8call_VERSION@-${CPACK_SYSTEM_NAME}")
"${CPACK_PACKAGE_NAME}-@js8call_VERSION@-${CPACK_SYSTEM_NAME}")
set (CPACK_SOURCE_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-@ft8call_VERSION@-Source")
"${CPACK_PACKAGE_NAME}-@js8call_VERSION@-Source")
if (NOT CPACK_WIX_SIZEOF_VOID_P)
set (CPACK_WIX_SIZEOF_VOID_P "@CMAKE_SIZEOF_VOID_P@")
+56 -318
View File
@@ -22,7 +22,7 @@ Change this to the newest SDK available that you can install on your system (10.
Do not override this if you intend to build an official deployable installer.")
endif (APPLE)
project (ft8call C CXX Fortran)
project (js8call C CXX Fortran)
#
# CMake policies
@@ -45,80 +45,15 @@ message (STATUS "Building ${CMAKE_PROJECT_NAME}-${wsjtx_VERSION}")
#
# project information
#
set (PROJECT_NAME "FT8Call")
set (PROJECT_NAME "JS8Call")
set (PROJECT_VENDOR "Jordan Sherer, KN4CRD")
set (PROJECT_CONTACT "Jordan Sherer <kn4crd@gmail.com>")
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2018 by Joe Taylor, K1JT, (C) 2018 by Jordan Sherer, KN4CRD")
set (PROJECT_HOMEPAGE http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html)
set (PROJECT_MANUAL wsjtx-main)
set (PROJECT_MANUAL_DIRECTORY_URL http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/)
set (PROJECT_SAMPLES_URL http://downloads.sourceforge.net/project/wsjt/)
set (PROJECT_SAMPLES_UPLOAD_DEST frs.sourceforge.net:/home/frs/project/wsjt/)
set (PROJECT_HOMEPAGE https://groups.io/g/js8call)
set (PROJECT_SUMMARY_DESCRIPTION "${PROJECT_NAME} - Digital Modes for Weak Signal Communicaitons in Amateur Radio.")
set (PROJECT_DESCRIPTION "${PROJECT_SUMMARY_DESCRIPTION}
${PROJECT_NAME} is a computer program designed to facilitate basic amateur
radio communication using very weak signals. The first four letters in
the program name stand for `(W)eak (S)ignal communication by
K1(JT),` while the suffix `-X` indicates that ${PROJECT_NAME} started as
an extended and experimental branch of the program
WSJT.
.
${PROJECT_NAME} Version 1.8 offers nine different protocols or modes: FT8,
JT4, JT9, JT65, QRA64, ISCAT, MSK144, WSPR, and Echo.
The first five are designed for making reliable QSOs under extreme
weak-signal conditions. They use nearly identical message structure
and source encoding. JT65 and QRA64 were designed for EME
(`moonbounce`) on the VHF/UHF bands and have also proven very
effective for worldwide QRP communication on the HF bands. QRA64 has
a number of advantages over JT65, including better performance on the
very weakest signals. We imagine that over time it may replace JT65
for EME use. JT9 was originally designed for the LF, MF, and lower HF
bands. Its submode JT9A is 2 dB more sensitive than JT65 while using
less than 10% of the bandwidth. JT4 offers a wide variety of tone
spacings and has proven highly effective for EME on microwave bands up
to 24 GHz. These four `slow` modes use one-minute timed sequences
of alternating transmission and reception, so a minimal QSO takes four
to six minutes — two or three transmissions by each station, one
sending in odd UTC minutes and the other even. FT8 is operationally
similar but four times faster (15-second T/R sequences) and less
sensitive by a few dB. On the HF bands, world-wide QSOs are possible
with any of these modes using power levels of a few watts (or even
milliwatts) and compromise antennas. On VHF bands and higher, QSOs
are possible (by EME and other propagation types) at signal levels 10
to 15 dB below those required for CW.
.
ISCAT, MSK144, and optionally submodes JT9E-H are `fast`
protocols designed to take advantage of brief signal enhancements from
ionized meteor trails, aircraft scatter, and other types of scatter
propagation. These modes use timed sequences of 5, 10, 15, or 30 s
duration. User messages are transmitted repeatedly at high rate (up
to 250 characters per second, for MSK144) to make good use of the
shortest meteor-trail reflections or `pings`. ISCAT uses free-form
messages up to 28 characters long, while MSK144 uses the same
structured messages as the slow modes and optionally an abbreviated
format with hashed callsigns.
.
WSPR (pronounced `whisper`) stands for (W)eak (S)ignal
(P)ropagation (R)eporter. The WSPR protocol was designed for probing
potential propagation paths using low-power transmissions. WSPR
messages normally carry the transmitting stations callsign, grid
locator, and transmitter power in dBm, and they can be decoded at
signal-to-noise ratios as low as -28 dB in a 2500 Hz bandwidth. WSPR
users with internet access can automatically upload reception
reports to a central database called wsprnet that provides a mapping
facility, archival storage, and many other features.
.
Echo mode allows you to detect and measure your own station's echoes
from the moon, even if they are far below the audible threshold.
.
${PROJECT_NAME} provides spectral displays for receiver passbands as wide as
5 kHz, flexible rig control for nearly all modern radios used by
amateurs, and a wide variety of special aids such as automatic Doppler
tracking for EME QSOs and Echo testing. The program runs equally well
on Windows, Macintosh, and Linux systems, and installation packages
are available for all three platforms.
.
Be sure to read the online ${PROJECT_NAME} User's Guide.")
${PROJECT_NAME} is a computer program designed to facilitate amateur
radio communication using very weak signals.")
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake/Modules ${CMAKE_MODULE_PATH})
@@ -159,8 +94,7 @@ option (WSJT_TRACE_CAT "Debugging option that turns on CAT diagnostics.")
option (WSJT_TRACE_CAT_POLLS "Debugging option that turns on CAT diagnostics during polling.")
option (WSJT_HAMLIB_TRACE "Debugging option that turns on minimal Hamlib internal diagnostics.")
option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients." ON)
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation." ON)
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
CMAKE_DEPENDENT_OPTION (WSJT_HAMLIB_VERBOSE_TRACE "Debugging option that turns on full Hamlib internal diagnostics." OFF WSJT_HAMLIB_TRACE OFF)
@@ -169,7 +103,7 @@ CMAKE_DEPENDENT_OPTION (WSJT_QDEBUG_IN_RELEASE "Leave Qt debugging statements in
CMAKE_DEPENDENT_OPTION (WSJT_ENABLE_EXPERIMENTAL_FEATURES "Enable features not fully ready for public releases." ON
is_debug_build OFF)
CMAKE_DEPENDENT_OPTION (WSJT_CREATE_WINMAIN
"The wsjtx target is normally built as GUI executable with a WinMain entry point on Windows,
"The target is normally built as GUI executable with a WinMain entry point on Windows,
if you want a console application instead then set this option to OFF.
If you just want to see the debug output from the application then the easiest way is to
@@ -249,11 +183,6 @@ set (wsjt_qt_CXXSRCS
HintedSpinBox.cpp
RestrictedSpinBox.cpp
HelpTextWindow.cpp
SampleDownloader.cpp
SampleDownloader/DirectoryDelegate.cpp
SampleDownloader/Directory.cpp
SampleDownloader/FileNode.cpp
SampleDownloader/RemoteFile.cpp
DisplayManual.cpp
MultiSettings.cpp
MaidenheadLocatorValidator.cpp
@@ -268,16 +197,17 @@ set (wsjt_qtmm_CXXSRCS
Audio/BWFFile.cpp
)
set (jt9_FSRCS
set (js8_FSRCS
lib/jt9.f90
lib/jt9a.f90
)
set (jt9_CXXSRCS
set (js8_CXXSRCS
lib/ipcomm.cpp
)
set (wsjtx_CXXSRCS
DriftingDateTime.cpp
logbook/adif.cpp
logbook/countrydat.cpp
logbook/countriesworked.cpp
@@ -304,6 +234,9 @@ set (wsjtx_CXXSRCS
messageaveraging.cpp
WsprTxScheduler.cpp
varicode.cpp
jsc.cpp
jsc_list.cpp
jsc_map.cpp
SelfDestructMessageBox.cpp
messagereplydialog.cpp
keyeater.cpp
@@ -673,32 +606,6 @@ set (wsjtx_UISRCS
messagereplydialog.ui
)
set (UDP_library_CXXSRCS
Radio.cpp
RadioMetaType.cpp
NetworkMessage.cpp
MessageServer.cpp
)
set (UDP_library_HEADERS
Radio.hpp
MessageServer.hpp
${PROJECT_BINARY_DIR}/udp_export.h
)
set (message_aggregator_CXXSRCS
UDPExamples/MessageAggregator.cpp
UDPExamples/MessageAggregatorMainWindow.cpp
UDPExamples/DecodesModel.cpp
UDPExamples/BeaconsModel.cpp
UDPExamples/ClientWidget.cpp
MaidenheadLocatorValidator.cpp
)
set (message_aggregator_STYLESHEETS
UDPExamples/qss/default.qss
)
set (qcp_CXXSRCS
qcustomplot-source/qcustomplot.cpp
)
@@ -707,7 +614,7 @@ set (all_CXXSRCS
${wsjt_CXXSRCS}
${wsjt_qt_CXXSRCS}
${wsjt_qtmm_CXXSRCS}
${jt9_CXXSRCS}
${js8_CXXSRCS}
${wsjtx_CXXSRCS}
${qcp_CXXSRCS}
)
@@ -720,11 +627,8 @@ set (all_C_and_CXXSRCS
)
set (TOP_LEVEL_RESOURCES
shortcuts.txt
mouse_commands.txt
prefixes.txt
cty.dat
icons/Darwin/FT8Call.iconset/icon_128x128.png
icons/Darwin/JS8Call.iconset/icon_128x128.png
contrib/gpl-v3-logo.svg
artwork/splash.png
)
@@ -891,14 +795,6 @@ if (WIN32)
find_package (Qt5AxContainer REQUIRED)
endif (WIN32)
#
# sub-directories
#
add_subdirectory (samples)
if (WSJT_GENERATE_DOCS)
add_subdirectory (doc)
endif (WSJT_GENERATE_DOCS)
#
# Library building setup
@@ -1146,7 +1042,7 @@ if (${OPENMP_FOUND} OR APPLE)
if (APPLE)
# On Mac we don't have working OpenMP support in the C/C++
# compilers so we have to manually set the correct flags to get
# OpenMP support in jt9.
# OpenMP support in js8.
target_compile_options (wsjt_fort_omp
PRIVATE
$<$<COMPILE_LANGUAGE:Fortran>:-fopenmp> # assumes GNU style Fortran compiler
@@ -1172,140 +1068,49 @@ endif (WIN32)
add_library (wsjt_qtmm STATIC ${wsjt_qtmm_CXXSRCS} ${wsjt_qtmm_GENUISRCS})
target_link_libraries (wsjt_qtmm Qt5::Multimedia)
add_executable (jt4sim lib/jt4sim.f90 wsjtx.rc)
target_link_libraries (jt4sim wsjt_fort wsjt_cxx)
add_executable (jt65sim lib/jt65sim.f90 wsjtx.rc)
target_link_libraries (jt65sim wsjt_fort wsjt_cxx)
add_executable (qra64sim lib/qra/qra64/qra64sim.f90 wsjtx.rc)
target_link_libraries (qra64sim wsjt_fort wsjt_cxx)
add_executable (jt49sim lib/jt49sim.f90 wsjtx.rc)
target_link_libraries (jt49sim wsjt_fort wsjt_cxx)
add_executable (allsim lib/allsim.f90 wsjtx.rc)
target_link_libraries (allsim wsjt_fort wsjt_cxx)
add_executable (jt65code lib/jt65code.f90 wsjtx.rc)
target_link_libraries (jt65code wsjt_fort wsjt_cxx)
add_executable (qra64code lib/qra64code.f90 wsjtx.rc)
target_link_libraries (qra64code wsjt_fort wsjt_cxx)
add_executable (jt9code lib/jt9code.f90 wsjtx.rc)
target_link_libraries (jt9code wsjt_fort wsjt_cxx)
add_executable (wsprcode lib/wsprcode/wsprcode.f90 lib/wsprcode/nhash.c
wsjtx.rc)
target_link_libraries (wsprcode wsjt_fort wsjt_cxx)
add_executable (wsprd ${wsprd_CSRCS})
target_include_directories (wsprd PRIVATE ${FFTW3_INCLUDE_DIRS})
target_link_libraries (wsprd ${FFTW3_LIBRARIES})
add_executable (wsprsim ${wsprsim_CSRCS})
add_executable (jt4code lib/jt4code.f90 wsjtx.rc)
target_link_libraries (jt4code wsjt_fort wsjt_cxx)
add_executable (msk144code lib/msk144code.f90 wsjtx.rc)
target_link_libraries (msk144code wsjt_fort wsjt_cxx)
add_executable (jt65 lib/jt65.f90 lib/jt65_test.f90 wsjtx.rc)
target_link_libraries (jt65 wsjt_fort wsjt_cxx)
add_executable (ldpcsim40 lib/ldpcsim40.f90 wsjtx.rc)
target_link_libraries (ldpcsim40 wsjt_fort wsjt_cxx)
add_executable (ldpcsim120 lib/fsk4hf/ldpcsim120.f90 wsjtx.rc)
target_link_libraries (ldpcsim120 wsjt_fort wsjt_cxx)
add_executable (ldpcsim174 lib/ft8/ldpcsim174.f90 wsjtx.rc)
target_link_libraries (ldpcsim174 wsjt_fort wsjt_cxx)
add_executable (ldpcsim144 lib/ldpcsim144.f90 wsjtx.rc)
target_link_libraries (ldpcsim144 wsjt_fort wsjt_cxx)
add_executable (ldpcsim168 lib/fsk4hf/ldpcsim168.f90 wsjtx.rc)
target_link_libraries (ldpcsim168 wsjt_fort wsjt_cxx)
add_executable (fsk4hf lib/fsk4hf/fsk4hf.f90 wsjtx.rc)
target_link_libraries (fsk4hf wsjt_fort wsjt_cxx)
add_executable (ft8code lib/ft8/ft8code.f90 wsjtx.rc)
target_link_libraries (ft8code wsjt_fort wsjt_cxx)
add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc)
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
add_executable (wsprlfsim lib/fsk4hf/wsprlfsim.f90 wsjtx.rc)
target_link_libraries (wsprlfsim wsjt_fort wsjt_cxx)
add_executable (wspr_fsk8d lib/fsk4hf/wspr_fsk8d.f90 wsjtx.rc)
target_link_libraries (wspr_fsk8d wsjt_fort wsjt_cxx)
add_executable (wspr_fsk8_sim lib/fsk4hf/wspr_fsk8_sim.f90 wsjtx.rc)
target_link_libraries (wspr_fsk8_sim wsjt_fort wsjt_cxx)
add_executable (mskhfsim lib/fsk4hf/mskhfsim.f90 wsjtx.rc)
target_link_libraries (mskhfsim wsjt_fort wsjt_cxx)
add_executable (msk144sd lib/msk144sd.f90 wsjtx.rc)
target_link_libraries (msk144sd wsjt_fort wsjt_cxx)
add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc)
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)
add_executable (msk144d2 lib/msk144d2.f90 wsjtx.rc)
target_link_libraries (msk144d2 wsjt_fort wsjt_cxx)
add_executable (fmtave lib/fmtave.f90 wsjtx.rc)
add_executable (fcal lib/fcal.f90 wsjtx.rc)
add_executable (fmeasure lib/fmeasure.f90 wsjtx.rc)
add_executable (jt9 ${jt9_FSRCS} ${jt9_CXXSRCS} wsjtx.rc)
add_executable (js8 ${js8_FSRCS} ${js8_CXXSRCS} wsjtx.rc)
if (${OPENMP_FOUND} OR APPLE)
if (APPLE)
# On Mac we don't have working OpenMP support in the C/C++
# compilers so we have to manually set the correct linking flags
# and libraries to get OpenMP support in jt9.
set_target_properties (jt9
# and libraries to get OpenMP support in js8.
set_target_properties (js8
PROPERTIES
Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
LINK_LIBRARIES "gomp;gcc_s.1" # assume GNU libgcc OpenMP
)
target_compile_options (jt9
target_compile_options (js8
PRIVATE
$<$<COMPILE_LANGUAGE:Fortran>:-fopenmp> # assumes GNU style Fortran compiler
)
else (APPLE)
if (OpenMP_C_FLAGS)
set_target_properties (jt9
set_target_properties (js8
PROPERTIES
COMPILE_FLAGS "${OpenMP_C_FLAGS}"
LINK_FLAGS "${OpenMP_C_FLAGS}"
)
endif ()
set_target_properties (jt9
set_target_properties (js8
PROPERTIES
Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
)
endif (APPLE)
if (WIN32)
# set_target_properties (jt9 PROPERTIES
# set_target_properties (js8 PROPERTIES
# LINK_FLAGS -Wl,--stack,16777216
# )
endif ()
target_link_libraries (jt9 wsjt_fort_omp wsjt_cxx Qt5::Core)
target_link_libraries (js8 wsjt_fort_omp wsjt_cxx Qt5::Core)
else (${OPENMP_FOUND} OR APPLE)
target_link_libraries (jt9 wsjt_fort wsjt_cxx Qt5::Core)
target_link_libraries (js8 wsjt_fort wsjt_cxx Qt5::Core)
endif (${OPENMP_FOUND} OR APPLE)
# build the main application
add_executable (ft8call MACOSX_BUNDLE
add_executable (js8call MACOSX_BUNDLE
${wsjtx_CXXSRCS}
${wsjtx_GENUISRCS}
wsjtx.rc
@@ -1314,10 +1119,10 @@ add_executable (ft8call MACOSX_BUNDLE
)
if (WSJT_CREATE_WINMAIN)
set_target_properties (ft8call PROPERTIES WIN32_EXECUTABLE ON)
set_target_properties (js8call PROPERTIES WIN32_EXECUTABLE ON)
endif (WSJT_CREATE_WINMAIN)
set_target_properties (ft8call PROPERTIES
set_target_properties (js8call PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}"
MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
@@ -1330,113 +1135,49 @@ set_target_properties (ft8call PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
)
target_include_directories (ft8call PRIVATE ${FFTW3_INCLUDE_DIRS})
target_include_directories (js8call PRIVATE ${FFTW3_INCLUDE_DIRS})
if (APPLE)
target_link_libraries (ft8call wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
target_link_libraries (js8call wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
else ()
target_link_libraries (ft8call wsjt_fort_omp wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
target_link_libraries (js8call wsjt_fort_omp wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
if (OpenMP_C_FLAGS)
set_target_properties (ft8call PROPERTIES
set_target_properties (js8call PROPERTIES
COMPILE_FLAGS "${OpenMP_C_FLAGS}"
LINK_FLAGS "${OpenMP_C_FLAGS}"
)
endif ()
set_target_properties (ft8call PROPERTIES
set_target_properties (js8call PROPERTIES
Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
)
if (WIN32)
set_target_properties (ft8call PROPERTIES
set_target_properties (js8call PROPERTIES
LINK_FLAGS -Wl,--stack,16777216
)
endif ()
endif ()
qt5_use_modules (ft8call SerialPort) # not sure why the interface link library syntax above doesn't work
qt5_use_modules (js8call SerialPort) # not sure why the interface link library syntax above doesn't work
# make a library for WSJT-X UDP servers
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
#target_include_directories (wsjtx_udp
# INTERFACE
# $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/wsjtx>
# )
target_include_directories (wsjtx_udp-static
INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/wsjtx>
)
#set_target_properties (wsjtx_udp PROPERTIES
# PUBLIC_HEADER "${UDP_library_HEADERS}"
# )
set_target_properties (wsjtx_udp-static PROPERTIES
OUTPUT_NAME wsjtx_udp
)
target_compile_definitions (wsjtx_udp-static PUBLIC UDP_STATIC_DEFINE)
#qt5_use_modules (wsjtx_udp Network)
qt5_use_modules (wsjtx_udp-static Network Gui)
generate_export_header (wsjtx_udp-static BASE_NAME udp)
add_executable (udp_daemon UDPExamples/UDPDaemon.cpp UDPExamples/udp_daemon.rc ${WSJTX_ICON_FILE})
target_link_libraries (udp_daemon wsjtx_udp-static)
add_resources (message_aggregator_RESOURCES /qss ${message_aggregator_STYLESHEETS})
configure_file (UDPExamples/message_aggregator.qrc.in message_aggregator.qrc @ONLY)
qt5_add_resources (message_aggregator_RESOURCES_RCC ${CMAKE_CURRENT_BINARY_DIR}/message_aggregator.qrc)
add_executable (message_aggregator
${message_aggregator_CXXSRCS}
${WSJTX_ICON_FILE}
UDPExamples/message_aggregator.rc
${message_aggregator_RESOURCES_RCC}
)
target_link_libraries (message_aggregator Qt5::Widgets wsjtx_udp-static)
if (WSJT_CREATE_WINMAIN)
set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
endif (WSJT_CREATE_WINMAIN)
if (UNIX)
if (NOT WSJT_SKIP_MANPAGES)
add_subdirectory (manpages)
add_dependencies (ft8call manpages)
endif (NOT WSJT_SKIP_MANPAGES)
if (NOT APPLE)
add_subdirectory (debian)
add_dependencies (ft8call debian)
endif (NOT APPLE)
endif (UNIX)
# if (UNIX)
# if (NOT WSJT_SKIP_MANPAGES)
# add_subdirectory (manpages)
# add_dependencies (js8call manpages)
# endif (NOT WSJT_SKIP_MANPAGES)
# if (NOT APPLE)
# add_subdirectory (debian)
# add_dependencies (js8call debian)
# endif (NOT APPLE)
# endif (UNIX)
#
# installation
#
install (TARGETS ft8call
install (TARGETS js8call
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
BUNDLE DESTINATION . COMPONENT runtime
)
# install (TARGETS wsjtx_udp EXPORT udp
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
# PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wsjtx
# )
# install (TARGETS wsjtx_udp-static EXPORT udp-static
# DESTINATION ${CMAKE_INSTALL_LIBDIR}
# )
# install (EXPORT udp NAMESPACE wsjtx::
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
# )
# install (EXPORT udp-static NAMESPACE wsjtx::
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
# )
install (TARGETS udp_daemon message_aggregator
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
)
install (TARGETS jt9 ft8code jt65code qra64code qra64sim jt9code jt4code
msk144code wsprd wspr_fsk8d fmtave fcal fmeasure
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
install (TARGETS js8 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
)
@@ -1444,24 +1185,21 @@ install (PROGRAMS
${RIGCTL_EXE}
DESTINATION ${CMAKE_INSTALL_BINDIR}
#COMPONENT runtime
RENAME rigctl-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
RENAME rigctl-local${CMAKE_EXECUTABLE_SUFFIX}
)
install (PROGRAMS
${RIGCTLD_EXE}
DESTINATION ${CMAKE_INSTALL_BINDIR}
#COMPONENT runtime
RENAME rigctld-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
RENAME rigctld-local${CMAKE_EXECUTABLE_SUFFIX}
)
install (FILES
README
COPYING
AUTHORS
THANKS
NEWS
INSTALL
BUGS
INSTALL-WSJTX
DESTINATION ${CMAKE_INSTALL_DOCDIR}
#COMPONENT runtime
)
@@ -1508,7 +1246,7 @@ add_custom_target (uninstall
# explicitly say that the wsjt_qt depends on custom target, this is
# done indirectly so that the revisiontag target gets built exactly
# once per build
add_dependencies(wsjt_qt revisiontag)
# add_dependencies(wsjt_qt)
#
@@ -1521,23 +1259,23 @@ configure_file (
if (NOT WIN32 AND NOT APPLE)
# install a desktop file so ft8call appears in the application start
# install a desktop file so js8call appears in the application start
# menu with an icon
install (
FILES ft8call.desktop
FILES js8call.desktop
DESTINATION /usr/share/applications
#COMPONENT runtime
)
install (
FILES icons/Unix/ft8call_icon.png
FILES icons/Unix/js8call_icon.png
DESTINATION /usr/share/pixmaps
#COMPONENT runtime
)
execute_process(COMMAND ln -s /opt/ft8call/bin/ft8call lft8call)
execute_process(COMMAND ln -s /opt/js8call/bin/js8call ljs8call)
install(FILES
${CMAKE_BINARY_DIR}/lft8call DESTINATION /usr/bin/ RENAME ft8call
${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call
#COMPONENT runtime
)
endif (NOT WIN32 AND NOT APPLE)
+87 -28
View File
@@ -454,6 +454,7 @@ private:
Q_SLOT void on_delete_macro_push_button_clicked (bool = false);
Q_SLOT void on_PTT_method_button_group_buttonClicked (int);
Q_SLOT void on_station_message_line_edit_textChanged(QString const&);
Q_SLOT void on_groups_line_edit_textChanged(QString const&);
Q_SLOT void on_qth_message_line_edit_textChanged(QString const&);
Q_SLOT void on_cq_message_line_edit_textChanged(QString const&);
Q_SLOT void on_reply_message_line_edit_textChanged(QString const&);
@@ -584,6 +585,7 @@ private:
QString my_callsign_;
QString my_grid_;
QString my_station_;
QStringList my_groups_;
QString my_qth_;
QString cq_;
QString reply_;
@@ -626,6 +628,7 @@ private:
bool spot_to_reporting_networks_;
bool transmit_directed_;
bool autoreply_off_at_startup_;
bool heartbeat_anywhere_;
bool relay_disabled_;
bool monitor_off_at_startup_;
bool monitor_last_used_;
@@ -639,7 +642,7 @@ private:
bool miles_;
bool quick_call_;
bool disable_TX_on_73_;
int beacon_;
int heartbeat_;
int watchdog_;
bool TX_messages_;
bool enable_VHF_features_;
@@ -756,6 +759,7 @@ void Configuration::set_spot_to_reporting_networks (bool spot)
bool Configuration::transmit_directed() const { return m_->transmit_directed_; }
bool Configuration::autoreply_off_at_startup () const {return m_->autoreply_off_at_startup_;}
bool Configuration::heartbeat_anywhere() const { return m_->heartbeat_anywhere_;}
bool Configuration::relay_off() const { return m_->relay_disabled_; }
bool Configuration::monitor_off_at_startup () const {return m_->monitor_off_at_startup_;}
bool Configuration::monitor_last_used () const {return m_->rig_is_dummy_ || m_->monitor_last_used_;}
@@ -769,7 +773,7 @@ bool Configuration::clear_DX () const {return m_->clear_DX_;}
bool Configuration::miles () const {return m_->miles_;}
bool Configuration::quick_call () const {return m_->quick_call_;}
bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;}
int Configuration::beacon () const {return m_->beacon_;}
int Configuration::heartbeat () const {return m_->heartbeat_;}
int Configuration::watchdog () const {return m_->watchdog_;}
bool Configuration::TX_messages () const {return m_->TX_messages_;}
bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features_;}
@@ -920,7 +924,7 @@ QString Configuration::my_grid() const
if (m_->use_dynamic_info_ && m_->dynamic_grid_.size () >= 4) {
grid = m_->dynamic_grid_;
}
return grid;
return grid.trimmed();
}
QString Configuration::my_station() const
@@ -929,22 +933,26 @@ QString Configuration::my_station() const
if(m_->use_dynamic_info_ && !m_->dynamic_qtc_.isEmpty()){
station = m_->dynamic_qtc_;
}
return station;
return station.trimmed();
}
QSet<QString> Configuration::my_groups() const {
return QSet<QString>::fromList(m_->my_groups_);
}
QString Configuration::my_qth() const
{
return m_->my_qth_;
return m_->my_qth_.trimmed();
}
QString Configuration::cq_message() const
{
return m_->cq_;
return m_->cq_.trimmed();
}
QString Configuration::reply_message() const
{
return m_->reply_;
return m_->reply_.trimmed();
}
int Configuration::callsign_aging() const
@@ -1298,6 +1306,7 @@ void Configuration::impl::initialize_models ()
ui_->callsign_aging_spin_box->setValue(callsign_aging_);
ui_->activity_aging_spin_box->setValue(activity_aging_);
ui_->station_message_line_edit->setText (my_station_.toUpper());
ui_->groups_line_edit->setText(my_groups_.join(", "));
ui_->qth_message_line_edit->setText (my_qth_.toUpper());
ui_->cq_message_line_edit->setText(cq_.toUpper());
ui_->reply_message_line_edit->setText (reply_.toUpper());
@@ -1329,6 +1338,7 @@ void Configuration::impl::initialize_models ()
ui_->psk_reporter_check_box->setChecked (spot_to_reporting_networks_);
ui_->transmit_directed_check_box->setChecked(transmit_directed_);
ui_->autoreply_off_check_box->setChecked (autoreply_off_at_startup_);
ui_->heartbeat_anywhere_check_box->setChecked(heartbeat_anywhere_);
ui_->relay_disabled_check_box->setChecked(relay_disabled_);
ui_->monitor_off_check_box->setChecked (monitor_off_at_startup_);
ui_->monitor_last_used_check_box->setChecked (monitor_last_used_);
@@ -1336,16 +1346,12 @@ void Configuration::impl::initialize_models ()
ui_->stations_table_view->setEnabled(ui_->auto_switch_bands_check_box->isChecked());
ui_->report_in_comments_check_box->setChecked (report_in_comments_);
ui_->prompt_to_log_check_box->setChecked (prompt_to_log_);
ui_->insert_blank_check_box->setChecked (insert_blank_);
ui_->DXCC_check_box->setChecked (DXCC_);
ui_->ppfx_check_box->setChecked (ppfx_);
ui_->clear_DX_check_box->setChecked (clear_DX_);
ui_->miles_check_box->setChecked (miles_);
ui_->quick_call_check_box->setChecked (quick_call_);
ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_);
ui_->beacon_spin_box->setValue (beacon_);
ui_->heartbeat_spin_box->setValue (heartbeat_);
ui_->tx_watchdog_spin_box->setValue (watchdog_);
ui_->TX_messages_check_box->setChecked (TX_messages_);
ui_->enable_VHF_features_check_box->setChecked(enable_VHF_features_);
ui_->decode_at_52s_check_box->setChecked(decode_at_52s_);
ui_->single_decode_check_box->setChecked(single_decode_);
@@ -1438,10 +1444,11 @@ void Configuration::impl::read_settings ()
my_callsign_ = settings_->value ("MyCall", QString {}).toString ();
my_grid_ = settings_->value ("MyGrid", QString {}).toString ();
my_station_ = settings_->value("MyStation", QString {}).toString();
my_groups_ = settings_->value("MyGroups", QStringList{}).toStringList();
callsign_aging_ = settings_->value ("CallsignAging", 0).toInt ();
activity_aging_ = settings_->value ("ActivityAging", 2).toInt ();
my_qth_ = settings_->value("MyQTH", QString {}).toString();
cq_ = settings_->value("CQMessage", QString {"CQCQCQ"}).toString();
cq_ = settings_->value("CQMessage", QString {"CQCQCQ <MYGRID4>"}).toString();
reply_ = settings_->value("Reply", QString {"HW CPY?"}).toString();
next_color_cq_ = color_cq_ = settings_->value("colorCQ","#66ff66").toString();
next_color_mycall_ = color_mycall_ = settings_->value("colorMyCall","#ff6666").toString();
@@ -1589,6 +1596,7 @@ void Configuration::impl::read_settings ()
transmit_directed_ = settings_->value ("TransmitDirected", true).toBool();
autoreply_off_at_startup_ = settings_->value ("AutoreplyOFF", false).toBool ();
heartbeat_anywhere_ = settings_->value("BeaconAnywhere", false).toBool();
relay_disabled_ = settings_->value ("RelayOFF", false).toBool ();
monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool ();
monitor_last_used_ = settings_->value ("MonitorLastUsed", false).toBool ();
@@ -1649,8 +1657,8 @@ void Configuration::impl::read_settings ()
miles_ = settings_->value ("Miles", false).toBool ();
quick_call_ = settings_->value ("QuickCall", false).toBool ();
disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool ();
beacon_ = settings_->value ("TxBeacon", 30).toInt ();
watchdog_ = settings_->value ("TxWatchdog", 0).toInt ();
heartbeat_ = settings_->value ("TxBeacon", 30).toInt ();
watchdog_ = settings_->value ("TxIdleWatchdog", 60).toInt ();
if(watchdog_){
watchdog_ = qMax(5, watchdog_);
}
@@ -1692,6 +1700,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("MyCall", my_callsign_);
settings_->setValue ("MyGrid", my_grid_);
settings_->setValue ("MyStation", my_station_);
settings_->setValue ("MyGroups", my_groups_);
settings_->setValue ("MyQTH", my_qth_);
settings_->setValue ("CQMessage", cq_);
settings_->setValue ("Reply", reply_);
@@ -1753,6 +1762,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_));
settings_->setValue ("TransmitDirected", transmit_directed_);
settings_->setValue ("AutoreplyOFF", autoreply_off_at_startup_);
settings_->setValue ("BeaconAnywhere", heartbeat_anywhere_);
settings_->setValue ("RelayOFF", relay_disabled_);
settings_->setValue ("MonitorOFF", monitor_off_at_startup_);
settings_->setValue ("MonitorLastUsed", monitor_last_used_);
@@ -1781,8 +1791,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("Miles", miles_);
settings_->setValue ("QuickCall", quick_call_);
settings_->setValue ("73TxDisable", disable_TX_on_73_);
settings_->setValue ("TxBeacon", beacon_);
settings_->setValue ("TxWatchdog", watchdog_);
settings_->setValue ("TxBeacon", heartbeat_);
settings_->setValue ("TxIdleWatchdog", watchdog_);
settings_->setValue ("Tx2QSO", TX_messages_);
settings_->setValue ("CATForceDTR", rig_params_.force_dtr);
settings_->setValue ("DTR", rig_params_.dtr_high);
@@ -1947,8 +1957,39 @@ void Configuration::impl::set_rig_invariants ()
|| TransceiverFactory::basic_transceiver_name_ != rig);
}
QStringList splitGroups(QString groupsString, bool filter){
QStringList groups;
if(groupsString.isEmpty()){
return groups;
}
foreach(QString group, groupsString.split(",")){
auto g = group.trimmed();
if(filter && !g.startsWith("@")){
continue;
}
groups.append(group.trimmed());
}
return groups;
}
bool Configuration::impl::validate ()
{
auto callsign = ui_->callsign_line_edit->text().trimmed();
if(!Varicode::isValidCallsign(callsign, nullptr) || callsign.startsWith("@")){
MessageBox::critical_message (this, tr ("The callsign format you provided is not supported"));
return false;
}
foreach(auto group, splitGroups(ui_->groups_line_edit->text(), false)){
if(!Varicode::isCompoundCallsign(group)){
MessageBox::critical_message (this, QString("%1 is not a valid group").arg(group));
return false;
}
}
if (ui_->sound_input_combo_box->currentIndex () < 0
&& !QAudioDeviceInfo::availableDevices (QAudio::AudioInput).empty ())
{
@@ -2200,6 +2241,9 @@ void Configuration::impl::accept ()
my_callsign_ = ui_->callsign_line_edit->text ();
my_grid_ = ui_->grid_line_edit->text ();
my_station_ = ui_->station_message_line_edit->text().toUpper();
my_groups_ = splitGroups(ui_->groups_line_edit->text().toUpper().trimmed(), true);
cq_ = ui_->cq_message_line_edit->text().toUpper();
reply_ = ui_->reply_message_line_edit->text().toUpper();
my_qth_ = ui_->qth_message_line_edit->text().toUpper();
@@ -2216,6 +2260,7 @@ void Configuration::impl::accept ()
tx_qsy_allowed_ = ui_->tx_qsy_check_box->isChecked ();
transmit_directed_ = ui_->transmit_directed_check_box->isChecked();
autoreply_off_at_startup_ = ui_->autoreply_off_check_box->isChecked ();
heartbeat_anywhere_ = ui_->heartbeat_anywhere_check_box->isChecked();
relay_disabled_ = ui_->relay_disabled_check_box->isChecked();
monitor_off_at_startup_ = ui_->monitor_off_check_box->isChecked ();
monitor_last_used_ = ui_->monitor_last_used_check_box->isChecked ();
@@ -2223,16 +2268,12 @@ void Configuration::impl::accept ()
log_as_DATA_ = ui_->log_as_RTTY_check_box->isChecked ();
report_in_comments_ = ui_->report_in_comments_check_box->isChecked ();
prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked ();
insert_blank_ = ui_->insert_blank_check_box->isChecked ();
DXCC_ = ui_->DXCC_check_box->isChecked ();
ppfx_ = ui_->ppfx_check_box->isChecked ();
clear_DX_ = ui_->clear_DX_check_box->isChecked ();
miles_ = ui_->miles_check_box->isChecked ();
quick_call_ = ui_->quick_call_check_box->isChecked ();
disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked ();
beacon_ = ui_->beacon_spin_box->value ();
heartbeat_ = ui_->heartbeat_spin_box->value ();
watchdog_ = ui_->tx_watchdog_spin_box->value ();
TX_messages_ = ui_->TX_messages_check_box->isChecked ();
data_mode_ = static_cast<DataMode> (ui_->TX_mode_button_group->checkedId ());
save_directory_ = ui_->save_path_display_label->text ();
azel_directory_ = ui_->azel_path_display_label->text ();
@@ -2340,14 +2381,23 @@ void Configuration::impl::reject ()
void Configuration::impl::on_font_push_button_clicked ()
{
next_font_ = QFontDialog::getFont (0, next_font_, this);
next_font_ = QFontDialog::getFont (0, next_font_, this
, tr ("Font Chooser")
#if QT_VERSION >= 0x050201
, QFontDialog::DontUseNativeDialog
#endif
);
ui_->font_push_button->setText(QString("Application Font (%1 %2)").arg(next_font_.family()).arg(next_font_.pointSize()));
}
void Configuration::impl::on_tableFontButton_clicked ()
{
next_table_font_ = QFontDialog::getFont (0, next_table_font_, this);
next_table_font_ = QFontDialog::getFont (0, next_table_font_, this
, tr ("Font Chooser")
#if QT_VERSION >= 0x050201
, QFontDialog::DontUseNativeDialog
#endif
);
ui_->tableFontButton->setText(QString("Table Font (%1 %2)").arg(next_table_font_.family()).arg(next_table_font_.pointSize()));
}
@@ -2455,7 +2505,7 @@ void Configuration::impl::on_rxFontButton_clicked ()
next_rx_text_font_ = QFontDialog::getFont (0, next_rx_text_font_ , this
, tr ("Font Chooser")
#if QT_VERSION >= 0x050201
, 0
, QFontDialog::DontUseNativeDialog
#endif
);
ui_->rxFontButton->setText(QString("Font (%1 %2)").arg(next_rx_text_font_.family()).arg(next_rx_text_font_.pointSize()));
@@ -2497,7 +2547,7 @@ void Configuration::impl::on_txFontButton_clicked ()
next_tx_text_font_ = QFontDialog::getFont (0, next_tx_text_font_ , this
, tr ("Font Chooser")
#if QT_VERSION >= 0x050201
, 0
, QFontDialog::DontUseNativeDialog
#endif
);
@@ -2509,7 +2559,7 @@ void Configuration::impl::on_composeFontButton_clicked ()
next_compose_text_font_ = QFontDialog::getFont (0, next_compose_text_font_ , this
, tr ("Font Chooser")
#if QT_VERSION >= 0x050201
, 0
, QFontDialog::DontUseNativeDialog
#endif
);
ui_->composeFontButton->setText(QString("Font (%1 %2)").arg(next_compose_text_font_.family()).arg(next_compose_text_font_.pointSize()));
@@ -2624,6 +2674,15 @@ void Configuration::impl::on_station_message_line_edit_textChanged(QString const
}
}
void Configuration::impl::on_groups_line_edit_textChanged(QString const &text)
{
QString upper = text.toUpper();
if(text != upper){
ui_->groups_line_edit->setText (upper);
}
}
void Configuration::impl::on_qth_message_line_edit_textChanged(QString const &text)
{
QString upper = text.toUpper();
+3 -1
View File
@@ -98,6 +98,7 @@ public:
QString my_callsign () const;
QString my_grid () const;
QString my_station () const;
QSet<QString> my_groups() const;
int activity_aging() const;
int callsign_aging() const;
QString my_qth () const;
@@ -120,6 +121,7 @@ public:
void set_spot_to_reporting_networks (bool);
bool transmit_directed() const;
bool autoreply_off_at_startup () const;
bool heartbeat_anywhere() const;
bool relay_off() const;
bool monitor_off_at_startup () const;
bool monitor_last_used () const;
@@ -133,7 +135,7 @@ public:
bool miles () const;
bool quick_call () const;
bool disable_TX_on_73 () const;
int beacon () const;
int heartbeat () const;
int watchdog () const;
bool TX_messages () const;
bool split_mode () const;
+996 -1014
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -6,6 +6,8 @@
#include <QThread>
#include <QDateTime>
#include "DriftingDateTime.h"
#include "NetworkServerLookup.hpp"
#include "moc_DXLabSuiteCommanderTransceiver.cpp"
@@ -151,10 +153,10 @@ void DXLabSuiteCommanderTransceiver::do_ptt (bool on)
simple_command (on ? "<command:5>CmdTX<parameters:0>" : "<command:5>CmdRX<parameters:0>");
bool tx {!on};
auto start = QDateTime::currentMSecsSinceEpoch ();
auto start = DriftingDateTime::currentMSecsSinceEpoch ();
// we must now wait for Tx on the rig, we will wait a short while
// before bailing out
while (tx != on && QDateTime::currentMSecsSinceEpoch () - start < 1000)
while (tx != on && DriftingDateTime::currentMSecsSinceEpoch () - start < 1000)
{
auto reply = command_with_reply ("<command:9>CmdSendTx<parameters:0>");
if (0 == reply.indexOf ("<CmdTX:"))
@@ -1,7 +1,7 @@
#!/bin/sh
WSJTX_BUNDLE="`echo "$0" | sed -e 's/\/Contents\/MacOS\/.*//'`"
WSJTX_RESOURCES="$WSJTX_BUNDLE/Contents/Resources"
WSJTX_TEMP="/tmp/ft8call/$UID"
WSJTX_TEMP="/tmp/js8call/$UID"
echo "running $0"
echo "WSJTX_BUNDLE: $WSJTX_BUNDLE"
@@ -13,4 +13,4 @@ export "DYLD_LIBRARY_PATH=$WSJTX_RESOURCES/lib"
export "PATH=$WSJTX_RESOURCES/bin:$PATH"
#export
exec "$WSJTX_RESOURCES/bin/ft8call"
exec "$WSJTX_RESOURCES/bin/js8call"
+2 -2
View File
@@ -1,6 +1,6 @@
Notes on FT8Call Installation for Mac OS X
(replace all instances of WSJT-X with FT8Call)
Notes on JS8Call Installation for Mac OS X
(replace all instances of WSJT-X with JS8Call)
Notes on WSJT-X Installation for Mac OS X
-----------------------------------------
+4 -2
View File
@@ -4,6 +4,8 @@
#include <QDebug>
#include "commons.h"
#include "DriftingDateTime.h"
#include "moc_Detector.cpp"
extern "C" {
@@ -42,7 +44,7 @@ bool Detector::reset ()
void Detector::clear ()
{
// set index to roughly where we are in time (1ms resolution)
// qint64 now (QDateTime::currentMSecsSinceEpoch ());
// qint64 now (DriftingDateTime::currentMSecsSinceEpoch ());
// unsigned msInPeriod ((now % 86400000LL) % (m_period * 1000));
// dec_data.params.kin = qMin ((msInPeriod * m_frameRate) / 1000, static_cast<unsigned> (sizeof (dec_data.d2) / sizeof (dec_data.d2[0])));
dec_data.params.kin = 0;
@@ -125,7 +127,7 @@ unsigned Detector::secondInPeriod () const
{
// we take the time of the data as the following assuming no latency
// delivering it to us (not true but close enough for us)
qint64 now (QDateTime::currentMSecsSinceEpoch ());
qint64 now (DriftingDateTime::currentMSecsSinceEpoch ());
unsigned secondInToday ((now % 86400000LL) / 1000);
return secondInToday % m_period;
+28
View File
@@ -0,0 +1,28 @@
#include "DriftingDateTime.h"
qint64 driftms = 0;
QDateTime DriftingDateTime::currentDateTime(){
return QDateTime::currentDateTime().addMSecs(driftms);
}
QDateTime DriftingDateTime::currentDateTimeUtc(){
return QDateTime::currentDateTimeUtc().addMSecs(driftms);
}
qint64 DriftingDateTime::currentMSecsSinceEpoch(){
return QDateTime::currentMSecsSinceEpoch() + driftms;
}
qint64 DriftingDateTime::drift(){
return driftms;
}
void DriftingDateTime::setDrift(qint64 ms){
driftms = ms;
}
qint64 DriftingDateTime::incrementDrift(qint64 msdelta){
driftms += msdelta;
return driftms;
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef DRIFTINGDATETIME_H
#define DRIFTINGDATETIME_H
#include <QDateTime>
class DriftingDateTime /*: QDateTime*/
{
public:
static QDateTime currentDateTime();
static QDateTime currentDateTimeUtc();
static qint64 currentMSecsSinceEpoch();
static qint64 drift();
static void setDrift(qint64 ms);
static qint64 incrementDrift(qint64 msdelta);
private:
};
#endif // DRIFTINGDATETIME_H
+10 -10
View File
@@ -26,16 +26,16 @@ namespace
{
FrequencyList_v2::FrequencyItems const default_frequency_list =
{
{ 1842000, Modes::FT8CALL, IARURegions::ALL}, // 2 above
{ 3578000, Modes::FT8CALL, IARURegions::ALL}, // 5 above
{ 7078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{10130000, Modes::FT8CALL, IARURegions::ALL}, // 6 below
{14078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{18104000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{21078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{24922000, Modes::FT8CALL, IARURegions::ALL}, // 9 above
{28078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{50318000, Modes::FT8CALL, IARURegions::ALL}, // 5 above
{ 1842000, Modes::JS8, IARURegions::ALL}, // 2 above
{ 3578000, Modes::JS8, IARURegions::ALL}, // 5 above
{ 7078000, Modes::JS8, IARURegions::ALL}, // 4 above
{10130000, Modes::JS8, IARURegions::ALL}, // 6 below
{14078000, Modes::JS8, IARURegions::ALL}, // 4 above
{18104000, Modes::JS8, IARURegions::ALL}, // 4 above
{21078000, Modes::JS8, IARURegions::ALL}, // 4 above
{24922000, Modes::JS8, IARURegions::ALL}, // 9 above
{28078000, Modes::JS8, IARURegions::ALL}, // 4 above
{50318000, Modes::JS8, IARURegions::ALL}, // 5 above
};
}
-32
View File
@@ -1,32 +0,0 @@
JT4 JT9 9+65 JT65 QRA SCAT M144 WSPR Echo
---------------------------------------------------------------------
0. txFirstCheckBox 11 111 1 11 11 11 1
1. TxFreqSpinBox 11 111 1 11 11
2. RxFreqSpinBox 11 111 1 11 11 1
3. sbFtol 1 11 1 11 11 1
4. rptSpinBox 11 111 1 11 11 11 1
5. sbTR 11 1
6. sbCQRxFreq 1
7. cbShMsgs 1 1
8. cbFast9 11
9. cbAutoSeq 1
10. cbTx6 1
11. pbTxMode 1
12. pbR2T 11 11 1 11 11
13. pbT2R 11 11 1 11 11
14. cbTxLock 1 11 1 11 11
15. sbSubMode 1 1 1 11 11
16. syncSpinBox 1 1 1 11 11
17. WSPR_Controls_Widget 1
18. ClrAvgButton 11 1
---------------------------------------------------------------------
19. FastNormalDeep 11 11 1 11 1 1
20. IncludeAveraging 1 1
21. IncludeCorrelation 1 1
22. EchoGraph 1
---------------------------------------------------------------------
For each mode:
Column 1 applies when VHF features is OFF (or col 2 absent)
Column 2 (if present) applies when VHF features is ON
Column 3 (JT9 only) applies for submodes E-H with Fast checked
+1 -416
View File
@@ -1,416 +1 @@
__ __ ______ _____ ________ __ __
| \ _ | \ / \ | \| \ | \ | \
| $$ / \ | $$| $$$$$$\ \$$$$$ \$$$$$$$$ | $$ | $$
| $$/ $\| $$| $$___\$$ | $$ | $$ ______ \$$\/ $$
| $$ $$$\ $$ \$$ \ __ | $$ | $$| \ >$$ $$
| $$ $$\$$\$$ _\$$$$$$\| \ | $$ | $$ \$$$$$$/ $$$$\
| $$$$ \$$$$| \__| $$| $$__| $$ | $$ | $$ \$$\
| $$$ \$$$ \$$ $$ \$$ $$ | $$ | $$ | $$
\$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$
Installing WSJT-X
=================
Binary packages of WSJT-X are available from the project web site:
http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html
Building from Source
====================
On Linux systems some of the prerequisite libraries are available in
the mainstream distribution repositories. They are Qt v5 and FFTW v3.
For MS Windows see the section "Building from Source on MS Windows"
below. For Apple Mac see the section "Building from Source on Apple
Mac".
Qt v5, preferably v5.1 or later is required to build WSJT-X.
Qt v5 multimedia support and serial port is necessary as well as the
core Qt v5 components, normally installing the Qt multimedia
development package and Qt serialport development package are
sufficient to pull in all the required Qt components and dependants as
a single transaction. On some systems the Qt multimedia plugin
component is separate in the distribution repository an it may also
need installing.
The single precision FFTW v3 library libfftw3f is required along with
the libfftw library development package. Normally installing the
library development package pulls in all the FFTW v3 libraries
including the single precision variant.
The Hamlib library optionally requires the libusb-1.0 library, if the
development version (libusb-1.0-dev) is available Hamlib will
configure its custom USB device back end drivers. Most rigs do not
require this so normally you can choose not to install libusb-1.0-dev
but if you have a SoftRock USB or similar SDR that uses a custom USB
interface then it is required.
The Hamlib library is required. Currently WSJT-X needs to be built
using a forked version of the Hamlib git master. This fork contains
patches not yet accepted by the Hamlib development team which are
essential for correct operation of WSJT-X. To build the Hamlib fork
from sources something like the following recipe should suffice:
$ mkdir ~/hamlib-prefix
$ cd ~/hamlib-prefix
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
$ cd src
$ git checkout integration
$ ./bootstrap
$ mkdir ../build
$ cd ../build
$ ../src/configure --prefix=$HOME/hamlib-prefix \
--disable-shared --enable-static \
--without-cxx-binding --disable-winradio \
CFLAGS="-g -O2 -fdata-sections -ffunction-sections" \
LDFLAGS="-Wl,--gc-sections"
$ make
$ make install-strip
This will build a binary hamlib package located at ~/hamlib-prefix so
you will need to add that to your CMAKE_PREFIX_PATH variable in your
WSJT-X build. On Linux that is probably the only path you have on
CMAKE_PREFIX_PATH unless you are using a locally installed Qt
installation.
To get the sources either download and extract a source tarball from
the project web site or preferably fetch the sources directly from the
project's subversion repository. The project svn repository has a
non-standard layout in that the WSJT-X project is not on the trunk,
instead the main code line is in a branch at ^/branches/wsjtx
$ mkdir -p ~/wsjtx-prefix/build
$ cd ~/wsjtx-prefix
$ svn checkout svn://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx src
To build WSJT-X you will need CMake and asciidoc installed.
$ cd ~/wsjtx-prefix/build
$ cmake -D CMAKE_PREFIX_PATH=~/hamlib-prefix ../src
$ cmake --build .
$ cmake --build . --target install
The recipe above will install into /usr by default, if you wish to
install in you own directory you can add a prefix-path to the
configure step like:
$ cd ~/wsjtx-prefix/build
$ cmake -D CMAKE_PREFIX_PATH=~/hamlib-prefix \
-D CMAKE_INSTALL_PREFIX=~/wsjtx-prefix ../src
$ cmake --build .
$ cmake --build . --target install
this will install WSJT-X at ~/wsjtx-prefix.
Building from Source on MS Windows
==================================
Because building on MS Windows is quite complicated there is an
Software Development Kit available that provides all the prerequisite
libraries and tools for building WSJT-X. This SDK is called JT-SDK-QT
which is documented here:
http://physics.princeton.edu/pulsar/K1JT/wsjtx-doc/dev-guide-main.html
If you need to build Hamlib rather than use the Hamlib kit included in
the JT-SDK the following recipe should help. Reasons for building
Hamlib from source might include picking up the very latest patches or
building a different branch that you wish to contribute to.
Hamlib optionally depends upon libusb-1.0, see "Building from Source"
above for more details. If you wish to include support for the
optional custom USB Hamlib rig drivers then you must install
libusb-1.0 before building Hamlib. The package may be obtained from
http://libusb.info/, install it in a convenient location like
C:\Tools.
On Windows there is a complication in that the compilers used to build
Qt and WSJT-X are the MinGW ones bundled with the Qt package but
Hamlib needs to be build from an MSYS shell with the tools required to
build an autotools project. This means that you need to tell the
Hamlib configuration to use the Qt bundled MinGW compilers (if you
don't then the thread support library use by Hamlib will be
incompatible with that used by Qt and WSJT-X). So on Windows the
Hamlib build recipe is something like:
In an MSYS shell:-
$ mkdir ~/hamib-prefix
$ cd ~/hamlib-prefix
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
$ cd src
$ git checkout integration
$ ./bootstrap
$ mkdir ../build
$ cd ../build
../src/configure --prefix=$HOME/hamlib-prefix \
--disable-shared --enable-static \
--without-cxx-binding --disable-winradio \
CC=<path-to-Qt-MinGW-tools>/gcc \
CXX=<path-to-Qt-MinGW-tools>/g++ \
CFLAGS="-g -O2 -fdata-sections -ffunction-sections -I<path-to-libusb-1.0>/include" \
LDFLAGS="-Wl,--gc-sections" \
LIBUSB_LIBS="-L<path-to-libusb-1.0>/MinGW32/dll -lusb-1.0"
$ make
$ make install
NOTE: <path-to-Qt-MinGQ-tools> should be substituted with the actual
path to your Qt bundled tools e.g on my system it is
C:\Tools\Qt\Tools\mingw530_32\bin
NOTE: <path-to-libusb-1.0> should be substituted with the actual path
to your libusb-1.0 installation directory e.g. on my system it is
C:\Tools\libusb-1.0.20
This will leave a Hamlib binary package installed at
c:/Users/<user-name>/hamlib-prefix which is what needs to be on your
CMAKE_PREFIX_PATH. On Windows you almost certainly will be using a
CMake tool chain file and this is where you will need to specify the
Hamlib binary location as one of the paths in CMAKE_PREFIX_PATH.
Building from Source on Apple Mac
=================================
These instructions are adapted from my Evernote page at:
https://www.evernote.com/pub/bsomervi/wsjt-xmacbuilds
There are several ways to get the required GNU and other open source
tools and libraries installed, my preference is MacPorts because it is
easy to use and does everything we need.
You will need Xcode, MacPorts, CMake and, Qt. The Xcode install
instructions are included in the MacPorts documentation.
MacPorts
--------
Install MacPorts from instructions here:
http://www.macports.org/install.php
More detailed instructions are available in the documentation:
https://guide.macports.org
The ports that need to be installed are:
autoconf
automake
libtool
pkgconfig
texinfo
gcc5
fftw-3-single +gcc5
asciidoc
libusb-devel
These are installed by typing:
$ sudo port install autoconf automake \
libtool pkgconfig texinfo gcc5 asciidoc \
fftw-3-single +gcc5 libusb-devel
Once complete you should have all the tools required to build WSJT-X.
Uninstalling MacPorts
---------------------
If at some point you wish to remove the ports from your machine. The
instructions are here:
https://guide.macports.org/#installing.macports.uninstalling .
Hamlib
------
First fetch hamlib from the repository, in this case my fork of Hamlib
3 until the official repository has all the fixes we need:
$ mkdir -p ~/hamlib-prefix/build
$ cd ~/hamlib-prefix
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
$ cd src
$ git checkout integration
$ ./bootstrap
The integration branch is my system testing branch which has all my
latest published changes.
To build:
$ cd ~/hamlib-prefix/build
$ ../src/configure \
--enable-static \
--disable-shared \
--disable-winradio \
--prefix=$HOME/hamlib-prefix \
CFLAGS="-g -O2 -mmacosx-version-min=10.7 -I/opt/local/include" \
LIBUSB_LIBS="-L/opt/local/lib -lusb-1.0"
$ make
$ make install-strip
The above commands will build hamlib and install it into
~/hamlib-prefix. If `make install-strip` fails, try `make install`.
Qt
--
NOTE: As of Qt v5.4 building Qt from source on Mac OS X is no longer
necessary since the Qt team have switched to using the modern libc++
Standard C++ Library for all distributable run time
components. Instead you may simply download a binary installer for OS
X 64-bit. The binary installer is here:
http://www.qt.io/download
The binary Qt distributions prior to Qt v5.4 from
http://www.qt.io/download unfortunately are built to use the libstdc++
C++ support library, WSJT-X uses a less geriatric C++ dialect which
uses the libc++ C++ support library. This means that you need to
build Qt from sources. This is not difficult but does take some time.
Download the Qt source tarball from
http://www.qt.io/download-open-source/, the link is about half way
down the page, you want the full sources tar ball shown as a 'tar.gz'
link.
Unpack the sources and cd into the top level directory then type:
$ ./configure -prefix ~/local/qt-macx-clang -opensource \
-confirm-license -platform macx-clang -silent -nomake tests \
-nomake examples -sdk macosx10.10 -skip qtwebkit \
-skip qtwebkit-examples -skip qtquick1 -skip qtconnectivity \
-skip qtlocation -skip qtsensors -skip qtscript \
-skip qtwebsockets -skip qtwebengine -skip qtwebchannel \
-skip qtwayland -skip qtquickcontrols -skip qtdeclarative \
-skip qtxmlpatterns -skip qtenginio
$ make -j4
$ make install
If you are building on 10.8 or don't have the 10.10 Mac SDK (Xcode 6)
available, you can substitute '-sdk macosx10.9' above.
The build above will take a few hours to complete.
CMake
-----
Although CMake is available via MacPorts I prefer to use the binary
installer from cake.org as the MacPorts port doesn't include the
graphical CMake tool cmake-gui which I find quite useful.
Fetch the latest CMake universal 64-bit DMG from
http://www.cmake.org/download/ open the DMG then drag and drop the
application bundle onto the supplied /Applications link.
To complete the install process you need to run the CMake-gui
application as root from a terminal shell as follows:
$ sudo "/Applications/CMake.app/Contents/MacOS/cmake" --install
that installs the CMake command line tools which you can verify by
typing into a terminal window:
$ cmake --version
If the install command above fails with a "No such file or directory"
error, that probably means that /usr/local/bin does not exist. You can
create it correctly with the following commands:
$ sudo mkdir -p /usr/local/bin
$ sudo chmod 755 /usr/local/bin
$ sudo chgrp wheel /usr/local/bin
and then retry the install command.
WSJT-X
------
First fetch the source from the repository:
$ mkdir -p ~/wsjtx-prefix/build
$ cd ~/wsjtx-prefix
$ svn checkout svn://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx src
this links to the Subversion repository in a read-only fashion, if you
intend to contribute to the project then you probably want to get a
developer login and use a read-write checkout. Even if you don't it
can be upgraded at a later date.
The checkout is of the latest code on the project trunk, i.e. the
development branch. You can easily switch the checkout to another
branch or even a tag if you want to build a prior published
generation. For now we will build the latest development sources. To
configure:
$ cd ~/wsjtx-prefix/build
$ FC=gfortran-mp-5 \
cmake \
-D CMAKE_PREFIX_PATH="~/Qt/5.7/clang_64;~/hamlib-prefix;/opt/local" \
-D CMAKE_INSTALL_PREFIX=~/wsjtx-prefix \
-D CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \
~/wsjtx-prefix/src
Substitute the Mac OS X SDK version you have installed in the above
command if you have a different version from 10.11.
The CMAKE_PREFIX_PATH variable specifies where CMake should look first
for other packages, the two elements may be different depending where
you have installed Qt and what version you have (~/local/qt-macx-clang
if you have built Qt from sources as described above in the Qt
section) and where you installed Hamlib (i.e. the --prefix configure
option above in the Hamlib section).
If you already have the fftw3-dev package installed on your system it
may well get selected in preference to the one you built above in the
MacPorts installation. It is unlikely that a prior installation of
libfftw3f is correctly configured for use in a WSJT-X package, the
CMAKE_PREFIX_PATH above is augmented with the MacPorts installation
location (/opt/local) to ensure the correct libfftw3f.dylib and
headers are located.
To build:
$ cmake --build .
$ cmake --build . --target install
which installs the WSJT-X application bundle into ~/wsjtx-prefix
Updating and Rebuilding Hamlib
==============================
From time to time new fixes will be pushed to the Hamlib fork
repository integration branch. To pick them up type:
$ cd ~/hamlib-prefix/src
$ git pull
To rebuild hamlib with the changed sources:
$ cd ~/hamlib-prefix/build
$ make
$ make install-strip
Updating and Rebuilding WSJT-X
==============================
To update to the latest sources type:
$ cd ~/wsjtx-prefix/src
$ svn update
$ cd ~/wsjtx-prefix/build
$ cmake --build .
$ cmake --build . --target install
73
Bill
G4WJS.
Detailed instructions coming soon. In the meantime, follow INSTALL-WSJTX instructions, substituting the WSJT-X repository with this one.
+416
View File
@@ -0,0 +1,416 @@
__ __ ______ _____ ________ __ __
| \ _ | \ / \ | \| \ | \ | \
| $$ / \ | $$| $$$$$$\ \$$$$$ \$$$$$$$$ | $$ | $$
| $$/ $\| $$| $$___\$$ | $$ | $$ ______ \$$\/ $$
| $$ $$$\ $$ \$$ \ __ | $$ | $$| \ >$$ $$
| $$ $$\$$\$$ _\$$$$$$\| \ | $$ | $$ \$$$$$$/ $$$$\
| $$$$ \$$$$| \__| $$| $$__| $$ | $$ | $$ \$$\
| $$$ \$$$ \$$ $$ \$$ $$ | $$ | $$ | $$
\$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$
Installing WSJT-X
=================
Binary packages of WSJT-X are available from the project web site:
http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html
Building from Source
====================
On Linux systems some of the prerequisite libraries are available in
the mainstream distribution repositories. They are Qt v5 and FFTW v3.
For MS Windows see the section "Building from Source on MS Windows"
below. For Apple Mac see the section "Building from Source on Apple
Mac".
Qt v5, preferably v5.1 or later is required to build WSJT-X.
Qt v5 multimedia support and serial port is necessary as well as the
core Qt v5 components, normally installing the Qt multimedia
development package and Qt serialport development package are
sufficient to pull in all the required Qt components and dependants as
a single transaction. On some systems the Qt multimedia plugin
component is separate in the distribution repository an it may also
need installing.
The single precision FFTW v3 library libfftw3f is required along with
the libfftw library development package. Normally installing the
library development package pulls in all the FFTW v3 libraries
including the single precision variant.
The Hamlib library optionally requires the libusb-1.0 library, if the
development version (libusb-1.0-dev) is available Hamlib will
configure its custom USB device back end drivers. Most rigs do not
require this so normally you can choose not to install libusb-1.0-dev
but if you have a SoftRock USB or similar SDR that uses a custom USB
interface then it is required.
The Hamlib library is required. Currently WSJT-X needs to be built
using a forked version of the Hamlib git master. This fork contains
patches not yet accepted by the Hamlib development team which are
essential for correct operation of WSJT-X. To build the Hamlib fork
from sources something like the following recipe should suffice:
$ mkdir ~/hamlib-prefix
$ cd ~/hamlib-prefix
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
$ cd src
$ git checkout integration
$ ./bootstrap
$ mkdir ../build
$ cd ../build
$ ../src/configure --prefix=$HOME/hamlib-prefix \
--disable-shared --enable-static \
--without-cxx-binding --disable-winradio \
CFLAGS="-g -O2 -fdata-sections -ffunction-sections" \
LDFLAGS="-Wl,--gc-sections"
$ make
$ make install-strip
This will build a binary hamlib package located at ~/hamlib-prefix so
you will need to add that to your CMAKE_PREFIX_PATH variable in your
WSJT-X build. On Linux that is probably the only path you have on
CMAKE_PREFIX_PATH unless you are using a locally installed Qt
installation.
To get the sources either download and extract a source tarball from
the project web site or preferably fetch the sources directly from the
project's subversion repository. The project svn repository has a
non-standard layout in that the WSJT-X project is not on the trunk,
instead the main code line is in a branch at ^/branches/wsjtx
$ mkdir -p ~/wsjtx-prefix/build
$ cd ~/wsjtx-prefix
$ svn checkout svn://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx src
To build WSJT-X you will need CMake and asciidoc installed.
$ cd ~/wsjtx-prefix/build
$ cmake -D CMAKE_PREFIX_PATH=~/hamlib-prefix ../src
$ cmake --build .
$ cmake --build . --target install
The recipe above will install into /usr by default, if you wish to
install in you own directory you can add a prefix-path to the
configure step like:
$ cd ~/wsjtx-prefix/build
$ cmake -D CMAKE_PREFIX_PATH=~/hamlib-prefix \
-D CMAKE_INSTALL_PREFIX=~/wsjtx-prefix ../src
$ cmake --build .
$ cmake --build . --target install
this will install WSJT-X at ~/wsjtx-prefix.
Building from Source on MS Windows
==================================
Because building on MS Windows is quite complicated there is an
Software Development Kit available that provides all the prerequisite
libraries and tools for building WSJT-X. This SDK is called JT-SDK-QT
which is documented here:
http://physics.princeton.edu/pulsar/K1JT/wsjtx-doc/dev-guide-main.html
If you need to build Hamlib rather than use the Hamlib kit included in
the JT-SDK the following recipe should help. Reasons for building
Hamlib from source might include picking up the very latest patches or
building a different branch that you wish to contribute to.
Hamlib optionally depends upon libusb-1.0, see "Building from Source"
above for more details. If you wish to include support for the
optional custom USB Hamlib rig drivers then you must install
libusb-1.0 before building Hamlib. The package may be obtained from
http://libusb.info/, install it in a convenient location like
C:\Tools.
On Windows there is a complication in that the compilers used to build
Qt and WSJT-X are the MinGW ones bundled with the Qt package but
Hamlib needs to be build from an MSYS shell with the tools required to
build an autotools project. This means that you need to tell the
Hamlib configuration to use the Qt bundled MinGW compilers (if you
don't then the thread support library use by Hamlib will be
incompatible with that used by Qt and WSJT-X). So on Windows the
Hamlib build recipe is something like:
In an MSYS shell:-
$ mkdir ~/hamib-prefix
$ cd ~/hamlib-prefix
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
$ cd src
$ git checkout integration
$ ./bootstrap
$ mkdir ../build
$ cd ../build
../src/configure --prefix=$HOME/hamlib-prefix \
--disable-shared --enable-static \
--without-cxx-binding --disable-winradio \
CC=<path-to-Qt-MinGW-tools>/gcc \
CXX=<path-to-Qt-MinGW-tools>/g++ \
CFLAGS="-g -O2 -fdata-sections -ffunction-sections -I<path-to-libusb-1.0>/include" \
LDFLAGS="-Wl,--gc-sections" \
LIBUSB_LIBS="-L<path-to-libusb-1.0>/MinGW32/dll -lusb-1.0"
$ make
$ make install
NOTE: <path-to-Qt-MinGQ-tools> should be substituted with the actual
path to your Qt bundled tools e.g on my system it is
C:\Tools\Qt\Tools\mingw530_32\bin
NOTE: <path-to-libusb-1.0> should be substituted with the actual path
to your libusb-1.0 installation directory e.g. on my system it is
C:\Tools\libusb-1.0.20
This will leave a Hamlib binary package installed at
c:/Users/<user-name>/hamlib-prefix which is what needs to be on your
CMAKE_PREFIX_PATH. On Windows you almost certainly will be using a
CMake tool chain file and this is where you will need to specify the
Hamlib binary location as one of the paths in CMAKE_PREFIX_PATH.
Building from Source on Apple Mac
=================================
These instructions are adapted from my Evernote page at:
https://www.evernote.com/pub/bsomervi/wsjt-xmacbuilds
There are several ways to get the required GNU and other open source
tools and libraries installed, my preference is MacPorts because it is
easy to use and does everything we need.
You will need Xcode, MacPorts, CMake and, Qt. The Xcode install
instructions are included in the MacPorts documentation.
MacPorts
--------
Install MacPorts from instructions here:
http://www.macports.org/install.php
More detailed instructions are available in the documentation:
https://guide.macports.org
The ports that need to be installed are:
autoconf
automake
libtool
pkgconfig
texinfo
gcc5
fftw-3-single +gcc5
asciidoc
libusb-devel
These are installed by typing:
$ sudo port install autoconf automake \
libtool pkgconfig texinfo gcc5 asciidoc \
fftw-3-single +gcc5 libusb-devel
Once complete you should have all the tools required to build WSJT-X.
Uninstalling MacPorts
---------------------
If at some point you wish to remove the ports from your machine. The
instructions are here:
https://guide.macports.org/#installing.macports.uninstalling .
Hamlib
------
First fetch hamlib from the repository, in this case my fork of Hamlib
3 until the official repository has all the fixes we need:
$ mkdir -p ~/hamlib-prefix/build
$ cd ~/hamlib-prefix
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
$ cd src
$ git checkout integration
$ ./bootstrap
The integration branch is my system testing branch which has all my
latest published changes.
To build:
$ cd ~/hamlib-prefix/build
$ ../src/configure \
--enable-static \
--disable-shared \
--disable-winradio \
--prefix=$HOME/hamlib-prefix \
CFLAGS="-g -O2 -mmacosx-version-min=10.7 -I/opt/local/include" \
LIBUSB_LIBS="-L/opt/local/lib -lusb-1.0"
$ make
$ make install-strip
The above commands will build hamlib and install it into
~/hamlib-prefix. If `make install-strip` fails, try `make install`.
Qt
--
NOTE: As of Qt v5.4 building Qt from source on Mac OS X is no longer
necessary since the Qt team have switched to using the modern libc++
Standard C++ Library for all distributable run time
components. Instead you may simply download a binary installer for OS
X 64-bit. The binary installer is here:
http://www.qt.io/download
The binary Qt distributions prior to Qt v5.4 from
http://www.qt.io/download unfortunately are built to use the libstdc++
C++ support library, WSJT-X uses a less geriatric C++ dialect which
uses the libc++ C++ support library. This means that you need to
build Qt from sources. This is not difficult but does take some time.
Download the Qt source tarball from
http://www.qt.io/download-open-source/, the link is about half way
down the page, you want the full sources tar ball shown as a 'tar.gz'
link.
Unpack the sources and cd into the top level directory then type:
$ ./configure -prefix ~/local/qt-macx-clang -opensource \
-confirm-license -platform macx-clang -silent -nomake tests \
-nomake examples -sdk macosx10.10 -skip qtwebkit \
-skip qtwebkit-examples -skip qtquick1 -skip qtconnectivity \
-skip qtlocation -skip qtsensors -skip qtscript \
-skip qtwebsockets -skip qtwebengine -skip qtwebchannel \
-skip qtwayland -skip qtquickcontrols -skip qtdeclarative \
-skip qtxmlpatterns -skip qtenginio
$ make -j4
$ make install
If you are building on 10.8 or don't have the 10.10 Mac SDK (Xcode 6)
available, you can substitute '-sdk macosx10.9' above.
The build above will take a few hours to complete.
CMake
-----
Although CMake is available via MacPorts I prefer to use the binary
installer from cake.org as the MacPorts port doesn't include the
graphical CMake tool cmake-gui which I find quite useful.
Fetch the latest CMake universal 64-bit DMG from
http://www.cmake.org/download/ open the DMG then drag and drop the
application bundle onto the supplied /Applications link.
To complete the install process you need to run the CMake-gui
application as root from a terminal shell as follows:
$ sudo "/Applications/CMake.app/Contents/MacOS/cmake" --install
that installs the CMake command line tools which you can verify by
typing into a terminal window:
$ cmake --version
If the install command above fails with a "No such file or directory"
error, that probably means that /usr/local/bin does not exist. You can
create it correctly with the following commands:
$ sudo mkdir -p /usr/local/bin
$ sudo chmod 755 /usr/local/bin
$ sudo chgrp wheel /usr/local/bin
and then retry the install command.
WSJT-X
------
First fetch the source from the repository:
$ mkdir -p ~/wsjtx-prefix/build
$ cd ~/wsjtx-prefix
$ svn checkout svn://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx src
this links to the Subversion repository in a read-only fashion, if you
intend to contribute to the project then you probably want to get a
developer login and use a read-write checkout. Even if you don't it
can be upgraded at a later date.
The checkout is of the latest code on the project trunk, i.e. the
development branch. You can easily switch the checkout to another
branch or even a tag if you want to build a prior published
generation. For now we will build the latest development sources. To
configure:
$ cd ~/wsjtx-prefix/build
$ FC=gfortran-mp-5 \
cmake \
-D CMAKE_PREFIX_PATH="~/Qt/5.7/clang_64;~/hamlib-prefix;/opt/local" \
-D CMAKE_INSTALL_PREFIX=~/wsjtx-prefix \
-D CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \
~/wsjtx-prefix/src
Substitute the Mac OS X SDK version you have installed in the above
command if you have a different version from 10.11.
The CMAKE_PREFIX_PATH variable specifies where CMake should look first
for other packages, the two elements may be different depending where
you have installed Qt and what version you have (~/local/qt-macx-clang
if you have built Qt from sources as described above in the Qt
section) and where you installed Hamlib (i.e. the --prefix configure
option above in the Hamlib section).
If you already have the fftw3-dev package installed on your system it
may well get selected in preference to the one you built above in the
MacPorts installation. It is unlikely that a prior installation of
libfftw3f is correctly configured for use in a WSJT-X package, the
CMAKE_PREFIX_PATH above is augmented with the MacPorts installation
location (/opt/local) to ensure the correct libfftw3f.dylib and
headers are located.
To build:
$ cmake --build .
$ cmake --build . --target install
which installs the WSJT-X application bundle into ~/wsjtx-prefix
Updating and Rebuilding Hamlib
==============================
From time to time new fixes will be pushed to the Hamlib fork
repository integration branch. To pick them up type:
$ cd ~/hamlib-prefix/src
$ git pull
To rebuild hamlib with the changed sources:
$ cd ~/hamlib-prefix/build
$ make
$ make install-strip
Updating and Rebuilding WSJT-X
==============================
To update to the latest sources type:
$ cd ~/wsjtx-prefix/src
$ svn update
$ cd ~/wsjtx-prefix/build
$ cmake --build .
$ cmake --build . --target install
73
Bill
G4WJS.
+3 -1
View File
@@ -13,6 +13,8 @@
#include <QHostAddress>
#include <QColor>
#include "DriftingDateTime.h"
#include "pimpl_impl.hpp"
#include "moc_MessageClient.cpp"
@@ -232,7 +234,7 @@ void MessageClient::impl::heartbeat ()
Message m("PING", "", QMap<QString, QVariant>{
{"NAME", QVariant(QApplication::applicationName())},
{"VERSION", QVariant(QApplication::applicationVersion())},
{"UTC", QVariant(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch())}
{"UTC", QVariant(DriftingDateTime::currentDateTimeUtc().toMSecsSinceEpoch())}
});
writeDatagram (m.toJson(), server_, server_port_);
}
+2 -3
View File
@@ -7,7 +7,6 @@
#include <QHostAddress>
#include <QColor>
#include "udp_export.h"
#include "Radio.hpp"
#include "pimpl_h.hpp"
@@ -23,7 +22,7 @@ class QString;
// applications that use the Qt framework. Other applications should
// use this classes' implementation as a reference implementation.
//
class UDP_EXPORT MessageServer
class MessageServer
: public QObject
{
Q_OBJECT;
@@ -96,7 +95,7 @@ public:
Q_SIGNAL void error (QString const&) const;
private:
class UDP_NO_EXPORT impl;
class impl;
pimpl<impl> m_;
};
+1 -1
View File
@@ -14,7 +14,7 @@ namespace
char const * const mode_names[] =
{
"All",
"FT8CALL",
"JS8",
};
std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]);
}
+1 -1
View File
@@ -40,7 +40,7 @@ public:
enum Mode
{
ALL, // matches with all modes
FT8CALL,
JS8,
MODES_END_SENTINAL_AND_COUNT // this must be last
};
Q_ENUM (Mode)
+4 -6
View File
@@ -7,6 +7,8 @@
#include "soundout.h"
#include "commons.h"
#include "DriftingDateTime.h"
#include "moc_Modulator.cpp"
extern float gran(); // Noise generator (for tests only)
@@ -49,7 +51,7 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
{
Q_ASSERT (stream);
// Time according to this computer which becomes our base time
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
qint64 ms0 = DriftingDateTime::currentMSecsSinceEpoch() % 86400000;
if (m_state != Idle)
{
@@ -176,7 +178,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
if(m_TRperiod==3) slowCwId=false;
bool fastCwId=false;
static bool bCwId=false;
qint64 ms = QDateTime::currentMSecsSinceEpoch();
qint64 ms = DriftingDateTime::currentMSecsSinceEpoch();
float tsec=0.001*(ms % (1000*m_TRperiod));
if(m_bFastMode and (icw[0]>0) and (tsec>(m_TRperiod-5.0))) fastCwId=true;
if(!m_bFastMode) m_nspd=2560; // 22.5 WPM
@@ -289,10 +291,6 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
if (m_ic > i1) m_amp = 0.0;
sample=qRound(m_amp*qSin(m_phi));
if(m_toneSpacing < 0) sample=qRound(m_amp*foxcom_.wave[m_ic]);
// if(m_ic < 100) qDebug() << "Mod C" << m_ic << m_amp << foxcom_.wave[m_ic] << sample;
samples = load(postProcessSample(sample), samples);
++framesGenerated;
++m_ic;
-1318
View File
File diff suppressed because it is too large Load Diff
+24 -69
View File
@@ -1,80 +1,35 @@
# JS8Call
__ __ ______ _____ ________ __ __
| \ _ | \ / \ | \| \ | \ | \
| $$ / \ | $$| $$$$$$\ \$$$$$ \$$$$$$$$ | $$ | $$
| $$/ $\| $$| $$___\$$ | $$ | $$ ______ \$$\/ $$
| $$ $$$\ $$ \$$ \ __ | $$ | $$| \ >$$ $$
| $$ $$\$$\$$ _\$$$$$$\| \ | $$ | $$ \$$$$$$/ $$$$\
| $$$$ \$$$$| \__| $$| $$__| $$ | $$ | $$ \$$\
| $$$ \$$$ \$$ $$ \$$ $$ | $$ | $$ | $$
\$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$
Copyright (C) 2001 - 2017 by Joe Taylor, K1JT.
FT8 has taken over the airwaves as the digital communication mode for making QSOs over HF/VHF/UHF. The mode has been widely popular as the latest offering in K1JTs WSJT-X application. FT8 is based on the same foundation as JT65, JT9, and WSPR modes for weak signal communication, but transmits faster with only slightly reduced sensitivity.
WSJT-X is a computer program designed to facilitate basic amateur
radio communication using very weak signals. The first four letters in
the program name stand for “Weak Signal communication by K1JT,” while
the suffix “-X” indicates that WSJT-X started as an extended (and
experimental) branch of the program WSJT.
While FT8 is an incredibly robust weak signal mode, it is designed heavily to take advantage of short band openings on HF/VHF/UHF and only offers a minimal QSO framework. However, many operators are using these weak signal qualities to make successful QSOs on the HF bands where other modes fail.
WSJT-X Version 1.6 offers five protocols or “modes”: JT4, JT9, JT65
WSPR, and Echo. The first three are designed for making reliable QSOs
under extreme weak-signal conditions. They use nearly identical
message structure and source encoding. JT65 was designed for EME
(“moonbounce”) on the VHF/UHF bands and has also proven very effective
for worldwide QRP communication on the HF bands. JT9 is optimized for
the LF, MF, and lower HF bands. It is 2 dB more sensitive than JT65
while using less than 10% of the bandwidth. JT4 offers a wide variety
of tone spacings and has proved very effective for EME on microwave
bands up to 24 GHz. All three of these modes use one-minute timed
sequences of alternating transmission and reception, so a minimal QSO
takes four to six minutes — two or three transmissions by each
station, one sending in odd UTC minutes and the other even. On the HF
bands, world-wide QSOs are possible using power levels of a few watts
and compromise antennas. On VHF bands and higher, QSOs are possible
(by EME and other propagation types) at signal levels 10 to 15 dB
below those required for CW.
JS8Call is an experiment to test the feasibility of a digital mode with the robustness of FT8, combined with a messaging and network protocol layer for weak signal communication on HF, using keyboard-to-keyboard style interface. JS8Call is heavily inspired by WSJT-X, Fldigi, and FSQCall and would not exist without the hard work and dedication of the many developers in the amateur radio community.
WSPR (pronounced “whisper”) stands for Weak Signal Propagation
Reporter. The WSPR protocol was designed for probing potential
propagation paths using low-power transmissions. WSPR messages
normally carry the transmitting stations callsign, grid locator, and
transmitter power in dBm, and they can be decoded at signal-to-noise
ratios as low as -28 dB in a 2500 Hz bandwidth. WSPR users with
internet access can automatically upload their reception reports to a
central database called {wsprnet} that provides a mapping facility,
archival storage, and many other features.
* Read more on the original design inspiration here: https://github.com/jsherer/js8call
Echo mode allows you to detect and measure your own lunar echoes, even
if they are far below the audible threshold.
WSJT-X provides spectral displays for passbands up to 5 kHz, flexible
rig control for nearly all modern radios used by amateurs, and a wide
variety of special aids such as automatic Doppler tracking for EME
QSOs and Echo testing. The program runs equally well on Windows,
Macintosh, and Linux systems, and installation packages are available
for all three platforms.
WSJT-X is an open-source project released under the GPL license (See
COPYING). If you have programming or documentation skills or would
like to contribute to the project in other ways, please make your
interests known to the development team. The projects source-code
repository can be found at https://sourceforge.net/projects/wsjt, and
most communication among the developers takes place on the email
reflector https://sourceforge.net/p/wsjt/mailman. User-level
questions and answers, and general communication among users is found
on the https://groups.yahoo.com/neo/groups/wsjtgroup/info email
reflector.
* For release announcements and discussion, join the JS8Call mailing list here: https://groups.io/g/js8call
Project web site:
# Notice
http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html
JS8Call is a derivative of the WSJT-X application, restructured and redesigned for message passing using FT8 modulation. It is not supported by nor endorsed by the WSJT-X development group. While the WSJT-X group maintains copyright over the original work and code, JS8Call is a derivative work licensed under and in accordance with the terms of the GPLv3 license. The source code modifications are public and can be found in this repository: https://bitbucket.org/widefido/wsjtx/
Project mailing list (shared with other applications from the same
team):
https://groups.yahoo.com/neo/groups/wsjtgroup
# History
* July 6, 2017 - The initial idea of using a modification to the FT8 protocol to support long-form QSOs was developed by Jordan, KN4CRD, and submitted to the WSJT-X mailing list: https://sourceforge.net/p/wsjt/mailman/message/35931540/
* August 31, 2017 - Jordan, KN4CRD, did a little development and modified WSJT-X to support long-form QSOs using the existing FT8 protocol: https://sourceforge.net/p/wsjt/mailman/message/36020051/ He sent a video example to the WSJT-X group: https://widefido.wistia.com/medias/7bb1uq62ga
* January 8, 2018 - Jordan, KN4CRD, started working on the design of a long-form QSO application built on top of FT8 with a redesigned interface.
* February 9, 2018 - Jordan, KN4CRD, submitted question to the WSJT-X group to see if there was any interest in pursuing the idea: https://sourceforge.net/p/wsjt/mailman/message/36221549/
* February 10, 2018 - Jordan KN4CRD, Julian OH8STN, John N0JDS, and the Portable Digital QRP group did an experiment using FSQ. The idea of JS8Call, combining FT8, long-form QSOs, and FSQCall like features was born.
* February 11, 2018 - Jordan, KN4CRD, inquired about the idea of integrating long-form messages into WSJT-X: https://sourceforge.net/p/wsjt/mailman/message/36223372/
* February 12, 2018 - Joe Taylor, K1JT, wrote back: https://sourceforge.net/p/wsjt/mailman/message/36224507/ saying that “Please don't let my comment discourage you from proceeding as you wish, toward something new.”
* March 4, 2018 - Jordan, KN4CRD, published a design document for JS8Call: https://github.com/jsherer/js8call
* July 6, 2018 - Version 0.0.1 of JS8Call released to the development group
* July 15, 2018 - Version 0.1 released - a dozen testers
* July 21, 2018 - Version 0.2 released - 75 testers
* July 27, 2018 - Version 0.3 released - 150 testers
* August 12, 2018 - Version 0.4 released - (“leaked” on QRZ) - 500 testers
* September 2, 2018 - Version 0.5 released - 3000 testers
* September 14, 2018 - Version 0.6 released - 5000 testers
+12 -14
View File
@@ -5,8 +5,6 @@
#include <QLocale>
#include <QList>
#include "udp_export.h"
class QVariant;
class QString;
@@ -26,7 +24,7 @@ namespace Radio
//
// Qt type registration
//
void UDP_NO_EXPORT register_types ();
void register_types ();
//
// Frequency type conversion.
@@ -34,27 +32,27 @@ namespace Radio
// QVariant argument is convertible to double and is assumed to
// be scaled by (10 ** -scale).
//
Frequency UDP_EXPORT frequency (QVariant const&, int scale,
Frequency frequency (QVariant const&, int scale,
bool * ok = nullptr, QLocale const& = QLocale ());
FrequencyDelta UDP_EXPORT frequency_delta (QVariant const&, int scale,
FrequencyDelta frequency_delta (QVariant const&, int scale,
bool * ok = nullptr, QLocale const& = QLocale ());
//
// Frequency type formatting
//
QString UDP_EXPORT frequency_MHz_string (Frequency, QLocale const& = QLocale ());
QString UDP_EXPORT frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ());
QString UDP_EXPORT pretty_frequency_MHz_string (Frequency, QLocale const& = QLocale ());
QString UDP_EXPORT pretty_frequency_MHz_string (double, int scale, QLocale const& = QLocale ());
QString UDP_EXPORT pretty_frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ());
QString frequency_MHz_string (Frequency, QLocale const& = QLocale ());
QString frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ());
QString pretty_frequency_MHz_string (Frequency, QLocale const& = QLocale ());
QString pretty_frequency_MHz_string (double, int scale, QLocale const& = QLocale ());
QString pretty_frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ());
//
// Callsigns
//
bool UDP_EXPORT is_callsign (QString const&);
bool UDP_EXPORT is_compound_callsign (QString const&);
QString UDP_EXPORT base_callsign (QString);
QString UDP_EXPORT effective_prefix (QString);
bool is_callsign (QString const&);
bool is_compound_callsign (QString const&);
QString base_callsign (QString);
QString effective_prefix (QString);
}
Q_DECLARE_METATYPE (Radio::Frequency);
-410
View File
@@ -1,410 +0,0 @@
__ __ ______ _____ ________ __ __
| \ _ | \ / \ | \| \ | \ | \
| $$ / \ | $$| $$$$$$\ \$$$$$ \$$$$$$$$ | $$ | $$
| $$/ $\| $$| $$___\$$ | $$ | $$ ______ \$$\/ $$
| $$ $$$\ $$ \$$ \ __ | $$ | $$| \ >$$ $$
| $$ $$\$$\$$ _\$$$$$$\| \ | $$ | $$ \$$$$$$/ $$$$\
| $$$$ \$$$$| \__| $$| $$__| $$ | $$ | $$ \$$\
| $$$ \$$$ \$$ $$ \$$ $$ | $$ | $$ | $$
\$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$
Copyright 2001 - 2018 by Joe Taylor, K1JT.
Release: WSJT-X Version 1.9.1
June 1, 2018
-----------------------------
This critical bug fix release repairs an unintended restriction in the FT8
DXpedition mode. It supersedes v1.9.0 and must be used for DXpedition Fox
operators.
Release: WSJT-X Version 1.9.0
May 28, 2018
-----------------------------
Changes from WSJT-X Version 1.9.0-rc4 include the following:
- Display in the right text window of MSK144 messages addressed to
"MyCall" has been restored.
- Fox is not allowed to transmit in any of the default FT8 sub-bands.
- Fox can now work Hounds using compound callsigns.
- Fox can now transmit free-text messages (and any standard FT8 message)
by using Tab 1 or Tab 2.
- Added a checkbox to enable more frequent programmed CQs by Fox.
Default is OFF.
- Alt+N keyboard shortcut has been restored.
- MacOS program crash on unexpected decode request has been fixed.
- Several minor bug fixes and added convenience features.
- Hamlib, support for TRXManger added.
- Hamlib, improved support for flrig.
Release: WSJT-X Version 1.9.0-rc4
April 30, 2018
---------------------------------
Changes from WSJT-X Version 1.9.0-rc3 include the following:
- Corrected a number of flaws in Fox and Hound behavior, FT8
DXpedition Mode
- Decoded CQ calls where a prefix has been used as a suffix should
have the DXCC entity name assigned correctly in almost all cases
- Improved AFC capability for the wider JT65 sub-modes to help with
drifting signals
- Better support for macOS using hi-DPI Retina displays
- New UDP message that allows external applications to highlight
decoded callsigns
- Main-screen geometry and state of the "splitter" setting between its
two text windows is now properly restored after program restart.
- New simulator jt49sim[.exe] replaces jt4sim and jt9sim
- Correct S/N measurements for the JT9 slow/wide submodes
- Other minor bug fixes
- Updated copy of cty.dat
Release: WSJT-X Version 1.9.0-rc3
March 18, 2018
---------------------------------
Changes from WSJT-X Version 1.9.0-rc2 include the following:
- Corrected a number of flaws in Fox behavior, FT8 DXpedition Mode
- Allow Hounds to use compound callsigns
- Write debugging information to FoxQSO.txt.
- Fix the "Blue Decode Button" bug
- Allow partial processing of incoming UDP Reply messages so that
non-CQ/QRZ decodes can be processed. The processing is the same as
double-clicking the same decoded message within WSJT-X except that
"Enable Tx" will not be enabled.
- Send DX grid locator to wsjt_status.txt, for use by applications like
PstRotatorAZ
- Correct the display of DXCC status of KG4 calls
- Updated copy of cty.dat
- Updates to documentation
- Other minor bug fixes
- This release contains updated Hamlib functionality including changes
to the Yaesu FT-817 back end that allows the uBITx kit transceiver
to be CAT controlled by WSJT-X.
Release: WSJT-X Version 1.9.0-rc2
February 26, 2018
---------------------------------
Changes from WSJT-X Version 1.8.0 include the following:
- New FT8 DXpedition Mode to facilitate high QSO rates in pileup
situations
- Decoding improvements for JT65 mode, including a priori (AP)
decoding when VHF/UHF/Microwave features are enabled
- Optional Auto-Sequencing in JT4, JT9, and JT65 when
VHF/UHF/Microwave features are enabled
- Better suppression of low-confidence false decodes generated by AP
decoding in FT8 mode
- Improved decoding performance for WSPR mode, especially effective at
LF and MF
- Minor adjustments to auto-sequencing behavior
- More flexible Doppler control features for EME
- Improved waterfall sensitivity for very weak signals
- Automatic real-time forwarding of logged information to N1MM Logger+
- Expanded and improved UDP messages sent to companion programs
- Bug fixes and other minor tweaks to user interface
A primary purpose of this beta release is to allow field testing of
FT8 DXpedition Mode. Instructions for this mode are posted here:
http://physics.princeton.edu/pulsar/k1jt/FT8_DXpedition_Mode.pdf
Contacts in FT8 DXpedition Mode must use WSJT-X v1.9.0 at both ends of
the QSO. Please report any anomalous behavior to email list
wsjt-devel@lists.sourceforge.net. You must be a subscriber in order
to post there.
Release: WSJT-X Version 1.8.0
October 27, 2017
-----------------------------
This is the full General Availability release of WSJT-X Version 1.8.0.
Changes from WSJT-X Version 1.8.0-rc3 are very minor:
- Right-click on the Wide Graph now pops up a Context Menu. Select
the item *Set Rx & Tx Offset* to complete a one-handed setting of
both red and green frequency markers.
- Several clarifications and additions to Tool Tips and the User Guide.
We recommend that all users should upgrade to WSJT-X Version 1.8.0.
If you upgrade from v1.8.0-rc1 it may be necessary to do a one-time
reset of the default list of suggested operating frequencies. Go to
*File->Settings->Frequencies*, right click on the table and select
*Reset*.
Release: WSJT-X Version 1.8.0-rc3
October 16, 2017
---------------------------------
Most (but not all) changes since Version 1.8.0-rc2 involve user
control of the increasingly popular FT8 mode. The "RC3" release also
includes minor bug fixes and updates to the WSJT-X User Guide.
The following list includes all of the more important changes:
- New optimization of GUI for simplex and split behavior in FT8 mode.
1. Checkbox "Lock Tx Freq" on main window is relabeled "Hold Tx Freq".
2. Double-clicking on decoded messages that do not contain your own
call moves both Rx and Tx frequencies. If the first callsign is
your own call, only Rx freq moves.
3. Double-clicking on decoded messages moves the Rx frequency. If
"Hold Tx Freq" is checked, Tx frequency is moved only if CTRL was
held down.
4. Clicking on the waterfall moves Rx and Tx frequencies as
before: Rx only on a simple click, Tx only on SHIFT-click, and
both on CTRL-click. This happens even if "Hold Tx Freq" is
checked.
- Add a semi-automated "FreqCal" procedure: see *Solve for calibration
parameters* on the Tools menu.
- Improv auto-sequencing behavior: stop and on-frequency
transmission if a called station comes back to someone else.
- Improve S/N estimation in some situations involving QRM.
- Fix an initialization issue with user-modified application fonts.
- Fix an issue with Tx5 message generation with Type 2 compound calls.
- Enhance and improve the ADIF parser of logbook records. Update
the band limits as per ADIF 3.0.6 specification.
- Increase the FT8 DT range to +/- 2.5 s.
- Do not allow window manager events to close the astronomical data
window.
- Add an "Erase" item to the context (right-click) menu for decoded
text.
- Extend UDP messages with an "off air" boolean field indicating that
the decode was derived from a .WAV file playback rather than an on air
reception.
- Extend reference applications to use the new off air decode message
field.
- Improve performance of FT8 decoder, especially for overlapping
signals.
- Allow specialized use of "x2 Tone Spacing" in FT8 and slow JT9
modes.
- Move "NA VHF Contest Mode" checkbox to main screen. Query the
operator if d > 10000 km.
- Adjust UI to improve portability with font size changes and between
platforms.
- Extend UDP Reply message to support keyboard modifiers. This allows
UDP servers to emulate keyboard modified double-clicks on decoded
messages, e.g. ALT+double-click for replying to a CQ or QRZ call
without changing ones Tx frequency offset.
- Update the cty.dat file (21st Sept 2017).
- Ensure that Fast Graph is properly initialized.
- Better handling of worked before and country name display. Appended
text is added at a fixed column unless the message overlaps in which
case the appended information floats to the right.
- Restore printing of MSK144 decode quality information.
- Display Echo Graph automatically when Echo mode is started.
- Fix a bug that prevented double-click on a JT65 EME-style "OOO"
message from populating the Tx message boxes.
- Fixed behavior with double-click on 'CQ <AA-ZZ> <call> <grid>.'
- Update the "blank line" divider with band ID at 4*TRperiod/5.
- Fix cty.dat lookups that were not honouring exact match flags
- Add some further Copyright protections.
- Fix a bug involving "firstcall contains mycall" but not equal to mycall.
- Fix an issue with editing IARU regions in the working frequencies table.
Release: WSJT-X Version 1.8.0-rc2
September 2, 2017
---------------------------------
Implementation of FT8 and its auto-sequencing feature is now more
capable and more polished. The decoder is faster and better: it now
includes signal subtraction, multi-pass decoding, and the use of
accumulated "a priori" information as a QSO progresses. Sensitivity
extends downward as far as -24 dB in some circumstances. Overlapping
signals 2 and 3 deep are frequently decoded at essentially the same
frequency. On a crowded band we sometimes see more than 30 decodes in
a single 15-second interval, over a 2 kHz window. The North American
VHF Contesting Mode has been extended to include both FT8 and MSK144
modes.
The "RC2" release also includes many minor bug fixes and an
extensively updated WSJT-X User Guide.
Depending on what code revision you upgrade from, it may be necessary
to do a one-time reset of the default list of suggested operating
frequencies. Go to *File->Settings->Frequencies*, right click on
the table and select *Reset*.
Release: WSJT-X Version 1.8.0
-----------------------------
NEW FEATURES IN WSJT-X Version 1.8.0
------------------------------------
1. New mode called FT8: sensitivity down to -20 dB on the AWGN
channel; QSOs 4 times faster than JT65 or JT9; auto-sequencing
includes an option to respond automatically to first decoded
reply to your CQ.
2. New mode for accurate Frequency Calibration of your radio.
3. Improved performance of decoders for JT65, QRA64, and MSK144.
MSK144 includes facilities for amplitide and phase equalization
and an "SWL" mode for short-format messages.
4. Options to minimize screen space used by Main and Wide Graph
windows.
5. Enhanced management scheme for table of operating frequencies, and
a new set of default frequencies specific to the three IARU
Regions.
6. Improved CAT control for many rigs, including those controlled
through Commander or OmniRig.
7. New keyboard shortcuts to set "Tx even/1st" ON or OFF.
8. A number of (mostly minor) bug fixes and tweaks to the user
interface. For example: new behavior for the audio level slider;
correctly logged QSO start times in certain situations; correct
control of FT-891/991 and some other radios via rigctld.
At the time of the v1.8.0-rc1 release the following tasks are yet to
be completed:
1. Updates to WSJT-X User Guide.
2. Sample files for FT8.
3. Enhanced decoding using AP ("a priori") information.
4. Signal subtraction and multi-pass decoding.
5. Option to Auto-respond to the weakest responder to your CQ.
Installation packages for Windows, Linux, OS X, and Raspbian can be
downloaded from the WSJT web site:
http://physics.princeton.edu/pulsar/K1JT/wsjtx.html
Please send bug reports to either wsjtgroup@yahoogroups.com or
wsjt-devel@lists.sourceforge.net. Such reports should include a full
prescription of steps to reproduce the undesired behavior. You must
be a subscriber to post to either of these lists.
Brief Description of the FT8 Protocol
-------------------------------------
WSJT-X Version 1.8.0 includes a new mode called FT8, developed by K9AN
and K1JT. The mode name "FT8" stands for "Franke and Taylor, 8-FSK
modulation". FT8 uses 15-second T/R sequences and provides 50% or
better decoding probability down to -20 dB on an AWGN channel. An
auto-sequencing facility includes an option to respond automatically
to the first decoded reply to your CQ. FT8 QSOs are 4 times faster
than those made with JT65 or JT9. FT8 is an excellent mode for HF
DXing and for situations like multi-hop E_s on 6 meters, where deep
QSB may make fast and reliable completion of QSOs desirable.
Some important characteristics of FT8:
- T/R sequence length: 15 s
- Message length: 75 bits + 12-bit CRC
- FEC code: LDPC(174,87)
- Modulation: 8-FSK, tone spacing 6.25 Hz
- Constant-envelope waveform
- Occupied bandwidth: 50 Hz
- Synchronization: 7x7 Costas arrays at start, middle, and end
- Transmission duration: 79*1920/12000 = 12.64 s
- Decoding threshold: -20 dB; several dB lower with AP decoding
- Multi-decoder finds and decodes all FT8 signals in passband
- Optional auto-sequencing and auto-reply to a CQ response
- Operational behavior similar to JT9, JT65
We plan to implement signal subtraction, two-pass decoding, and use of
a priori (AP) information in the decoder. These features are not yet
activated in v1.8.0.
We haven't yet finalized what the three extra bits in the message
payload will be used for. Suggestions are welcome!
-- Joe, K1JT, for the WSJT Development Team
-159
View File
@@ -1,159 +0,0 @@
#include "SampleDownloader.hpp"
#include <QString>
#include <QSettings>
#include <QtWidgets>
#include "pimpl_impl.hpp"
#include "SettingsGroup.hpp"
#include "SampleDownloader/Directory.hpp"
#include "MessageBox.hpp"
#include "moc_SampleDownloader.cpp"
namespace
{
char const * const title = "Download Samples";
}
class SampleDownloader::impl final
: public QDialog
{
Q_OBJECT
public:
explicit impl (QSettings * settings, Configuration const *, QNetworkAccessManager *, QWidget * parent);
~impl () {save_window_state ();}
void refresh ()
{
show ();
raise ();
activateWindow ();
directory_.refresh (http_only_check_box_.isChecked ());
}
protected:
void closeEvent (QCloseEvent * e) override
{
save_window_state ();
QDialog::closeEvent (e);
}
private:
void save_window_state ()
{
SettingsGroup g (settings_, title);
settings_->setValue ("geometry", saveGeometry ());
settings_->setValue ("SamplesURL", url_line_edit_.text ());
settings_->setValue ("HTTPOnly", http_only_check_box_.isChecked ());
}
Q_SLOT void button_clicked (QAbstractButton *);
QSettings * settings_;
Directory directory_;
QGridLayout main_layout_;
QVBoxLayout left_layout_;
QDialogButtonBox button_box_;
QWidget details_widget_;
QFormLayout details_layout_;
QLineEdit url_line_edit_;
QCheckBox http_only_check_box_;
};
#include "SampleDownloader.moc"
SampleDownloader::SampleDownloader (QSettings * settings, Configuration const * configuration
, QNetworkAccessManager * network_manager, QWidget * parent)
: m_ {settings, configuration, network_manager, parent}
{
}
SampleDownloader::~SampleDownloader ()
{
}
void SampleDownloader::show ()
{
m_->refresh ();
}
SampleDownloader::impl::impl (QSettings * settings
, Configuration const * configuration
, QNetworkAccessManager * network_manager
, QWidget * parent)
: QDialog {parent, Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint}
, settings_ {settings}
, directory_ {configuration, network_manager}
, button_box_ {QDialogButtonBox::Close, Qt::Vertical}
{
setWindowTitle (windowTitle () + ' ' + tr (title));
resize (500, 600);
{
SettingsGroup g {settings_, title};
restoreGeometry (settings_->value ("geometry", saveGeometry ()).toByteArray ());
url_line_edit_.setText (settings_->value ("SamplesURL", PROJECT_SAMPLES_URL).toString ());
http_only_check_box_.setChecked (settings_->value ("HTTPOnly", false).toBool ());
directory_.url_root (url_line_edit_.text ());
}
setWindowTitle (QApplication::applicationName () + " - " + tr ("Download Samples"));
button_box_.button (QDialogButtonBox::Close)->setDefault (true);
button_box_.addButton ("&Abort", QDialogButtonBox::DestructiveRole);
button_box_.addButton ("&Refresh", QDialogButtonBox::ResetRole);
left_layout_.addWidget (&directory_);
auto details_button = button_box_.addButton ("&Details", QDialogButtonBox::HelpRole);
details_button->setCheckable (true);
details_widget_.hide ();
details_layout_.setMargin (0);
details_layout_.addRow ("Base URL for samples:", &url_line_edit_);
details_layout_.addRow ("Only use HTTP:", &http_only_check_box_);
http_only_check_box_.setToolTip ("Check this is you get SSL/TLS errors");
details_widget_.setLayout (&details_layout_);
main_layout_.addLayout (&left_layout_, 0, 0);
main_layout_.addWidget (&button_box_, 0, 1);
main_layout_.addWidget (&details_widget_, 1, 0, 1, 2);
main_layout_.setRowStretch (1, 2);
setLayout (&main_layout_);
connect (&button_box_, &QDialogButtonBox::clicked, this, &SampleDownloader::impl::button_clicked);
connect (details_button, &QAbstractButton::clicked, &details_widget_, &QWidget::setVisible);
connect (&url_line_edit_, &QLineEdit::editingFinished, [this] () {
if (directory_.url_root (url_line_edit_.text ()))
{
directory_.refresh (http_only_check_box_.isChecked ());
}
else
{
MessageBox::warning_message (this, tr ("Input Error"), tr ("Invalid URL format"));
}
});
connect (&http_only_check_box_, &QAbstractButton::toggled, [this] (bool checked) {
directory_.refresh (checked);
});
}
void SampleDownloader::impl::button_clicked (QAbstractButton * button)
{
switch (button_box_.buttonRole (button))
{
case QDialogButtonBox::RejectRole:
hide ();
break;
case QDialogButtonBox::DestructiveRole:
directory_.abort ();
break;
case QDialogButtonBox::ResetRole:
directory_.refresh (http_only_check_box_.isChecked ());
break;
default:
break;
}
}
-50
View File
@@ -1,50 +0,0 @@
#ifndef SAMPLE_DOWNLOADER_HPP__
#define SAMPLE_DOWNLOADER_HPP__
#include <QObject>
#include "pimpl_h.hpp"
class QSettings;
class QWidget;
class QNetworkAccessManager;
class Configuration;
//
// SampleDownloader - A Dialog to maintain sample files
//
// This uses a Qt Dialog window that contains a tree view of the
// available sample files on a web or ftp server. The files can be
// installed locally by ticking a check box or removed from the local
// machine by un-ticking the check boxes.
//
// The class requires a pointer to an open QSettings instance where it
// will save its persistent state, a pointer to a WSJT-X Configuration
// instance that is used to obtain configuration information like the
// current file save location and, a pointer to a
// QNetworkAccessManager instance which is used for network requests.
//
// An instance of SampleDownloader need not be destroyed after use,
// just call SampleDownloader::show() to make the dialog visible
// again.
//
class SampleDownloader final
: public QObject
{
Q_OBJECT;
public:
SampleDownloader (QSettings * settings
, Configuration const *
, QNetworkAccessManager *
, QWidget * parent = nullptr);
~SampleDownloader ();
Q_SLOT void show ();
private:
class impl;
pimpl<impl> m_;
};
#endif
-319
View File
@@ -1,319 +0,0 @@
#include "Directory.hpp"
#include <QVariant>
#include <QString>
#include <QHeaderView>
#include <QStringList>
#include <QFileInfo>
#include <QDir>
#include <QNetworkAccessManager>
#include <QAuthenticator>
#include <QNetworkReply>
#include <QTreeWidgetItem>
#include <QTreeWidgetItemIterator>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonArray>
#include <QJsonObject>
#include <QRegularExpression>
#include "Configuration.hpp"
#include "DirectoryNode.hpp"
#include "FileNode.hpp"
#include "revision_utils.hpp"
#include "MessageBox.hpp"
#include "moc_Directory.cpp"
namespace
{
char const * samples_dir_name = "samples";
QString const contents_file_name = "contents_" + version (false) + ".json";
}
Directory::Directory (Configuration const * configuration
, QNetworkAccessManager * network_manager
, QWidget * parent)
: QTreeWidget {parent}
, configuration_ {configuration}
, network_manager_ {network_manager}
, http_only_ {false}
, root_dir_ {configuration_->save_directory ()}
, contents_ {this
, network_manager_
, QDir {root_dir_.absoluteFilePath (samples_dir_name)}.absoluteFilePath (contents_file_name)}
{
dir_icon_.addPixmap (style ()->standardPixmap (QStyle::SP_DirClosedIcon), QIcon::Normal, QIcon::Off);
dir_icon_.addPixmap (style ()->standardPixmap (QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On);
file_icon_.addPixmap (style ()->standardPixmap (QStyle::SP_FileIcon));
setColumnCount (2);
setHeaderLabels ({"File", "Progress"});
header ()->setSectionResizeMode (QHeaderView::ResizeToContents);
setItemDelegate (&item_delegate_);
connect (network_manager_, &QNetworkAccessManager::authenticationRequired
, this, &Directory::authentication);
connect (this, &Directory::itemChanged, [this] (QTreeWidgetItem * item) {
switch (item->type ())
{
case FileNode::Type:
{
FileNode * node = static_cast<FileNode *> (item);
if (!node->sync (node->checkState (0) == Qt::Checked))
{
FileNode::sync_blocker b {node};
node->setCheckState (0, node->checkState (0) == Qt::Checked ? Qt::Unchecked : Qt::Checked);
}
}
break;
default:
break;
}
});
}
bool Directory::url_root (QUrl root)
{
if (!root.path ().endsWith ('/'))
{
root.setPath (root.path () + '/');
}
bool valid = root.isValid ();
if (valid)
{
url_root_ = root;
}
return valid;
}
void Directory::error (QString const& title, QString const& message)
{
MessageBox::warning_message (this, title, message);
}
bool Directory::refresh (bool http_only)
{
abort ();
clear ();
// update locations
root_dir_ = configuration_->save_directory ();
QDir contents_dir {root_dir_.absoluteFilePath (samples_dir_name)};
contents_.local_file_path (contents_dir.absoluteFilePath (contents_file_name));
contents_.http_only (http_only_ = http_only);
QUrl url {url_root_.resolved (QDir {root_dir_.relativeFilePath (samples_dir_name)}.filePath (contents_file_name))};
if (url.isValid ())
{
return contents_.sync (url, true, true); // attempt to fetch contents
}
else
{
MessageBox::warning_message (this
, tr ("URL Error")
, tr ("Invalid URL:\n\"%1\"")
.arg (url.toDisplayString ()));
}
return false;
}
void Directory::download_finished (bool success)
{
if (success)
{
QFile contents {contents_.local_file_path ()};
if (contents.open (QFile::ReadOnly | QFile::Text))
{
QJsonParseError json_status;
auto content = QJsonDocument::fromJson (contents.readAll (), &json_status);
if (json_status.error)
{
MessageBox::warning_message (this
, tr ("JSON Error")
, tr ("Contents file syntax error %1 at character offset %2")
.arg (json_status.errorString ()).arg (json_status.offset));
return;
}
if (!content.isArray ())
{
MessageBox::warning_message (this, tr ("JSON Error")
, tr ("Contents file top level must be a JSON array"));
return;
}
QTreeWidgetItem * parent {invisibleRootItem ()};
parent = new DirectoryNode {parent, samples_dir_name};
parent->setIcon (0, dir_icon_);
parent->setExpanded (true);
parse_entries (content.array (), root_dir_.relativeFilePath (samples_dir_name), parent);
}
else
{
MessageBox::warning_message (this, tr ("File System Error")
, tr ("Failed to open \"%1\"\nError: %2 - %3")
.arg (contents.fileName ())
.arg (contents.error ())
.arg (contents.errorString ()));
}
}
}
void Directory::parse_entries (QJsonArray const& entries, QDir const& dir, QTreeWidgetItem * parent)
{
if (dir.isRelative () && !dir.path ().startsWith ('.'))
{
for (auto const& value: entries)
{
if (value.isObject ())
{
auto const& entry = value.toObject ();
auto const& name = entry["name"].toString ();
if (name.size () && !name.contains (QRegularExpression {R"([/:;])"}))
{
auto const& type = entry["type"].toString ();
if ("file" == type)
{
QUrl url {url_root_.resolved (dir.filePath (name))};
if (url.isValid ())
{
auto node = new FileNode {parent, network_manager_
, QDir {root_dir_.filePath (dir.path ())}.absoluteFilePath (name)
, url, http_only_};
FileNode::sync_blocker b {node};
node->setIcon (0, file_icon_);
node->setCheckState (0, node->local () ? Qt::Checked : Qt::Unchecked);
update (parent);
}
else
{
MessageBox::warning_message (this
, tr ("URL Error")
, tr ("Invalid URL:\n\"%1\"")
.arg (url.toDisplayString ()));
}
}
else if ("directory" == type)
{
auto node = new DirectoryNode {parent, name};
node->setIcon (0, dir_icon_);
auto const& entries = entry["entries"];
if (entries.isArray ())
{
parse_entries (entries.toArray ()
, QDir {root_dir_.relativeFilePath (dir.path ())}.filePath (name)
, node);
}
else
{
MessageBox::warning_message (this, tr ("JSON Error")
, tr ("Contents entries must be a JSON array"));
}
}
else
{
MessageBox::warning_message (this, tr ("JSON Error")
, tr ("Contents entries must have a valid type"));
}
}
else
{
MessageBox::warning_message (this, tr ("JSON Error")
, tr ("Contents entries must have a valid name"));
}
}
else
{
MessageBox::warning_message (this, tr ("JSON Error")
, tr ("Contents entries must be JSON objects"));
}
}
}
else
{
MessageBox::warning_message (this, tr ("JSON Error")
, tr ("Contents directories must be relative and within \"%1\"")
.arg (samples_dir_name));
}
}
void Directory::abort ()
{
QTreeWidgetItemIterator iter {this};
while (*iter)
{
if ((*iter)->type () == FileNode::Type)
{
auto * node = static_cast<FileNode *> (*iter);
node->abort ();
}
++iter;
}
}
namespace
{
//
// traverse the passed subtree accumulating the number of items, the
// number we have size data for, the bytes downloaded so far and the
// maximum bytes to expect
//
int recurse_children (QTreeWidgetItem const * item, int * counted
, qint64 * bytes, qint64 * max)
{
int items {0};
for (int index {0}; index < item->childCount (); ++index)
{
auto const * child = item->child (index);
if (child->type () == FileNode::Type) // only count files
{
++items;
if (auto size = child->data (1, Qt::UserRole).toLongLong ())
{
*max += size;
++*counted;
}
*bytes += child->data (1, Qt::DisplayRole).toLongLong ();
}
else
{
// recurse into sub-directory subtrees
items += recurse_children (child, counted, bytes, max);
}
}
return items;
}
}
void Directory::update (QTreeWidgetItem * item)
{
// iterate the tree under item and accumulate the progress
if (item)
{
Q_ASSERT (item->type () == DirectoryNode::Type);
qint64 max {0};
qint64 bytes {0};
int counted {0};
// get the count, progress and size of children
int items {recurse_children (item, &counted, &bytes, &max)};
// estimate size of items not yet downloaded as average of
// those actually present
if (counted)
{
max += (items - counted) * max / counted;
}
// save as our progress
item->setData (1, Qt::UserRole, max);
item->setData (1, Qt::DisplayRole, bytes);
// recurse up to top
update (item->parent ());
}
}
void Directory::authentication (QNetworkReply * /* reply */
, QAuthenticator * /* authenticator */)
{
MessageBox::warning_message (this, tr ("Network Error"), tr ("Authentication required"));
}
-60
View File
@@ -1,60 +0,0 @@
#ifndef SAMPLE_DOWNLOADER_DIRECTORY_HPP__
#define SAMPLE_DOWNLOADER_DIRECTORY_HPP__
#include <QObject>
#include <QString>
#include <QTreeWidget>
#include <QIcon>
#include <QSize>
#include <QDir>
#include <QUrl>
#include "DirectoryDelegate.hpp"
#include "RemoteFile.hpp"
class Configuration;
class QNetworkAccessManager;
class QTreeWidgetItem;
class QNetworkReply;
class QAuthenticator;
class QJsonArray;
class Directory final
: public QTreeWidget
, protected RemoteFile::ListenerInterface
{
Q_OBJECT
public:
explicit Directory (Configuration const * configuration
, QNetworkAccessManager * network_manager
, QWidget * parent = nullptr);
QSize sizeHint () const override {return {400, 500};}
bool url_root (QUrl);
bool refresh (bool http_only);
void abort ();
void update (QTreeWidgetItem * item);
protected:
void error (QString const& title, QString const& message) override;
bool redirect_request (QUrl const&) override {return true;} // allow
void download_finished (bool success) override;
private:
Q_SLOT void authentication (QNetworkReply *, QAuthenticator *);
void parse_entries (QJsonArray const& entries, QDir const& dir, QTreeWidgetItem * parent);
Configuration const * configuration_;
QNetworkAccessManager * network_manager_;
bool http_only_;
QDir root_dir_;
QUrl url_root_;
RemoteFile contents_;
DirectoryDelegate item_delegate_;
QIcon dir_icon_;
QIcon file_icon_;
};
#endif
-44
View File
@@ -1,44 +0,0 @@
#include "DirectoryDelegate.hpp"
#include <QApplication>
#include <QVariant>
#include <QString>
#include <QStyle>
#include <QModelIndex>
#include <QPainter>
#include <QStyleOptionViewItem>
#include <QStyleOptionProgressBar>
void DirectoryDelegate::paint (QPainter * painter, QStyleOptionViewItem const& option
, QModelIndex const& index) const
{
if (1 == index.column ())
{
QStyleOptionProgressBar progress_bar_option;
progress_bar_option.rect = option.rect;
progress_bar_option.state = QStyle::State_Enabled;
progress_bar_option.direction = QApplication::layoutDirection ();
progress_bar_option.fontMetrics = QApplication::fontMetrics ();
progress_bar_option.minimum = 0;
progress_bar_option.maximum = 100;
auto progress = index.data ().toLongLong ();
if (progress > 0)
{
auto percent = int (progress * 100 / index.data (Qt::UserRole).toLongLong ());
progress_bar_option.progress = percent;
progress_bar_option.text = QString::number (percent) + '%';
progress_bar_option.textVisible = true;
progress_bar_option.textAlignment = Qt::AlignCenter;
}
else
{
// not started
progress_bar_option.progress = -1;
}
QApplication::style ()->drawControl (QStyle::CE_ProgressBar, &progress_bar_option, painter);
}
else
{
QStyledItemDelegate::paint (painter, option, index);
}
}
-30
View File
@@ -1,30 +0,0 @@
#ifndef DIRECTORY_DELEGATE_HPP__
#define DIRECTORY_DELEGATE_HPP__
#include <QStyledItemDelegate>
class QObject;
class QStyleOptionVoew;
class QModelIndex;
class QPainter;
//
// Styled item delegate that renders a progress bar in column #1
//
// model column #1 DisplayRole is the progress in bytes
// model column #1 UserRole is the expected number of bytes
//
class DirectoryDelegate final
: public QStyledItemDelegate
{
public:
explicit DirectoryDelegate (QObject * parent = nullptr)
: QStyledItemDelegate {parent}
{
}
void paint (QPainter * painter, QStyleOptionViewItem const& option
, QModelIndex const& index) const override;
};
#endif
-51
View File
@@ -1,51 +0,0 @@
#ifndef DIRECTORY_NODE_HPP__
#define DIRECTORY_NODE_HPP__
#include <QTreeWidgetItem>
#include <QString>
//
// Tree widget item representing a file system directory.
//
// It renders the directory name in the first column and progress
// information in the 2nd column. The progress information consists of
// two 64 bit integer values, the 1st in the DisplayRole is the number
// of bytes received and the 2nd in the UserRole the total bytes
// expected. The progress information is not automatically
// maintained, see the Directory class for an example of how to
// dynamically maintain the DirectoryNode progress values. The 1st
// column also renders a tristate check box that controls the first
// column check boxes of child items.
//
class DirectoryNode final
: public QTreeWidgetItem
{
public:
explicit DirectoryNode (QTreeWidgetItem * parent, QString const& name)
: QTreeWidgetItem {parent, Type}
{
setFlags (flags () | Qt::ItemIsUserCheckable | Qt::ItemIsTristate);
setText (0, name);
setCheckState (0, Qt::Unchecked);
// initialize as empty, the owning QTreeWidget must maintain these
// progress values
setData (1, Qt::DisplayRole, 0ll); // progress in bytes
setData (1, Qt::UserRole, 0ll); // expected bytes
}
bool operator == (QString const& name) const
{
return name == text (0);
}
static int constexpr Type {UserType};
};
inline
bool operator == (QString const& lhs, DirectoryNode const& rhs)
{
return rhs == lhs;
}
#endif
-74
View File
@@ -1,74 +0,0 @@
#include "FileNode.hpp"
#include <QVariant>
#include <QUrl>
#include <QDir>
#include <QFileInfo>
#include "Directory.hpp"
#include "MessageBox.hpp"
FileNode::FileNode (QTreeWidgetItem * parent
, QNetworkAccessManager * network_manager
, QString const& local_file_path
, QUrl const& url
, bool http_only)
: QTreeWidgetItem {parent, Type}
, remote_file_ {this, network_manager, local_file_path, http_only}
, block_sync_ {false}
{
sync_blocker b {this};
setFlags (flags () | Qt::ItemIsUserCheckable);
setText (0, QFileInfo {local_file_path}.fileName ()); // display
setData (0, Qt::UserRole, url);
setData (0, Qt::UserRole + 1, local_file_path); // local absolute path
setCheckState (0, Qt::Unchecked);
}
void FileNode::error (QString const& title, QString const& message)
{
MessageBox::warning_message (treeWidget (), title, message);
}
bool FileNode::sync (bool local)
{
if (block_sync_)
{
return true;
}
return remote_file_.sync (data (0, Qt::UserRole).toUrl (), local);
}
void FileNode::download_progress (qint64 bytes_received, qint64 total_bytes)
{
sync_blocker b {this};
setData (1, Qt::UserRole, total_bytes);
if (bytes_received < 0)
{
setData (1, Qt::DisplayRole, 0ll);
setCheckState (0, Qt::Unchecked);
}
else
{
setData (1, Qt::DisplayRole, bytes_received);
}
static_cast<Directory *> (treeWidget ())->update (parent ());
}
void FileNode::download_finished (bool success)
{
sync_blocker b {this};
if (!success)
{
setData (1, Qt::UserRole, 0ll);
setData (1, Qt::DisplayRole, 0ll);
}
setCheckState (0, success ? Qt::Checked : Qt::Unchecked);
static_cast<Directory *> (treeWidget ())->update (parent ());
}
void FileNode::abort ()
{
sync_blocker b {this};
remote_file_.abort ();
}
-67
View File
@@ -1,67 +0,0 @@
#ifndef FILE_NODE_HPP__
#define FILE_NODE_HPP__
#include <QTreeWidgetItem>
#include "RemoteFile.hpp"
class QNetworkAccessManager;
class QString;
class QUrl;
//
// A holder for a RemoteFile object linked to a QTreeWidget row.
//
// It renders the file name in first column and holds download
// progress data in the second column. The progress information is a
// 64 bit integer number of bytes in the DisplayRole and a total bytes
// expected in the UserRole. The first column also renders a check box
// that downloads the file when checked and removes the downloaded
// file when unchecked. The URL and local absolute file path are
// stored in the UserData and UserData+1 roles of the first column.
//
class FileNode final
: public QTreeWidgetItem
, protected RemoteFile::ListenerInterface
{
public:
explicit FileNode (QTreeWidgetItem * parent
, QNetworkAccessManager * network_manager
, QString const& local_path
, QUrl const& url
, bool http_only);
bool local () const {return remote_file_.local ();}
bool sync (bool local);
void abort ();
static int constexpr Type {UserType + 1};
//
// Clients may use this RAII class to block nested calls to sync
// which may be troublesome, e.g. when UI updates cause recursion.
//
struct sync_blocker
{
sync_blocker (FileNode * node) : node_ {node} {node_->block_sync_ = true;}
sync_blocker (sync_blocker const&) = delete;
sync_blocker& operator = (sync_blocker const&) = delete;
~sync_blocker () {node_->block_sync_ = false;}
private:
FileNode * node_;
};
protected:
void error (QString const& title, QString const& message) override;
bool redirect_request (QUrl const&) override {return true;} // allow
void download_progress (qint64 bytes_received, qint64 total_bytes) override;
void download_finished (bool success) override;
private:
RemoteFile remote_file_; // active download
bool block_sync_;
friend struct sync_blocker;
};
#endif
-5
View File
@@ -1,5 +0,0 @@
A UI for downloading sample files from a web server.
Works in concert with samples/CMakeLists.txt which generates the JSON
contents description file and has a build target upload-samples that
uploads the samples and content file to the project files server.
-271
View File
@@ -1,271 +0,0 @@
#include "RemoteFile.hpp"
#include <utility>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QDir>
#include <QByteArray>
#include "moc_RemoteFile.cpp"
RemoteFile::RemoteFile (ListenerInterface * listener, QNetworkAccessManager * network_manager
, QString const& local_file_path, bool http_only, QObject * parent)
: QObject {parent}
, listener_ {listener}
, network_manager_ {network_manager}
, local_file_ {local_file_path}
, http_only_ {http_only}
, is_valid_ {false}
, redirect_count_ {0}
, file_ {local_file_path}
{
local_file_.setCaching (false);
}
void RemoteFile::local_file_path (QString const& name)
{
QFileInfo new_file {name};
new_file.setCaching (false);
if (new_file != local_file_)
{
if (local_file_.exists ())
{
QFile file {local_file_.absoluteFilePath ()};
if (!file.rename (new_file.absoluteFilePath ()))
{
listener_->error (tr ("File System Error")
, tr ("Cannot rename file:\n\"%1\"\nto: \"%2\"\nError(%3): %4")
.arg (file.fileName ())
.arg (new_file.absoluteFilePath ())
.arg (file.error ())
.arg (file.errorString ()));
}
}
std::swap (local_file_, new_file);
}
}
bool RemoteFile::local () const
{
auto is_local = (reply_ && !reply_->isFinished ()) || local_file_.exists ();
if (is_local)
{
auto size = local_file_.size ();
listener_->download_progress (size, size);
listener_->download_finished (true);
}
else
{
listener_->download_progress (-1, 0);
}
return is_local;
}
bool RemoteFile::sync (QUrl const& url, bool local, bool force)
{
if (local)
{
if (!reply_ || reply_->isFinished ()) // not active download
{
if (force || !local_file_.exists () || url != url_)
{
url_ = url;
redirect_count_ = 0;
Q_ASSERT (!is_valid_);
download (url_);
}
}
else
{
return false;
}
}
else
{
if (reply_ && reply_->isRunning ())
{
reply_->abort ();
}
if (local_file_.exists ())
{
auto path = local_file_.absoluteDir ();
if (path.remove (local_file_.fileName ()))
{
listener_->download_progress (-1, 0);
}
else
{
listener_->error (tr ("File System Error")
, tr ("Cannot delete file:\n\"%1\"")
.arg (local_file_.absoluteFilePath ()));
return false;
}
path.rmpath (".");
}
}
return true;
}
void RemoteFile::download (QUrl url)
{
if (QNetworkAccessManager::Accessible != network_manager_->networkAccessible ()) {
// try and recover network access for QNAM
network_manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
}
if (url.isValid () && (!QSslSocket::supportsSsl () || http_only_))
{
url.setScheme ("http");
}
QNetworkRequest request {url};
request.setRawHeader ("User-Agent", "WSJT Sample Downloader");
request.setOriginatingObject (this);
// this blocks for a second or two the first time it is used on
// Windows - annoying
if (!is_valid_)
{
reply_ = network_manager_->head (request);
}
else
{
reply_ = network_manager_->get (request);
}
connect (reply_.data (), &QNetworkReply::finished, this, &RemoteFile::reply_finished);
connect (reply_.data (), &QNetworkReply::readyRead, this, &RemoteFile::store);
connect (reply_.data (), &QNetworkReply::downloadProgress
, [this] (qint64 bytes_received, qint64 total_bytes) {
// report progress of wanted file
if (is_valid_)
{
listener_->download_progress (bytes_received, total_bytes);
}
});
}
void RemoteFile::abort ()
{
if (reply_ && reply_->isRunning ())
{
reply_->abort ();
}
}
void RemoteFile::reply_finished ()
{
if (!reply_) return; // we probably deleted it in an
// earlier call
QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()};
if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ())
{
if (listener_->redirect_request (redirect_url))
{
if (++redirect_count_ < 10) // maintain sanity
{
// follow redirect
download (reply_->url ().resolved (redirect_url));
}
else
{
listener_->download_finished (false);
listener_->error (tr ("Network Error")
, tr ("Too many redirects: %1")
.arg (redirect_url.toDisplayString ()));
is_valid_ = false; // reset
}
}
else
{
listener_->download_finished (false);
listener_->error (tr ("Network Error")
, tr ("Redirect not followed: %1")
.arg (redirect_url.toDisplayString ()));
is_valid_ = false; // reset
}
}
else if (reply_->error () != QNetworkReply::NoError)
{
file_.cancelWriting ();
file_.commit ();
listener_->download_finished (false);
is_valid_ = false; // reset
// report errors that are not due to abort
if (QNetworkReply::OperationCanceledError != reply_->error ())
{
listener_->error (tr ("Network Error"), reply_->errorString ());
}
}
else
{
auto path = QFileInfo {file_.fileName ()}.absoluteDir ();
if (is_valid_ && !file_.commit ())
{
listener_->error (tr ("File System Error")
, tr ("Cannot commit changes to:\n\"%1\"")
.arg (file_.fileName ()));
path.rmpath ("."); // tidy empty directories
listener_->download_finished (false);
is_valid_ = false; // reset
}
else
{
if (!is_valid_)
{
// now get the body content
is_valid_ = true;
download (reply_->url ().resolved (redirect_url));
}
else
{
listener_->download_finished (true);
is_valid_ = false; // reset
}
}
}
if (reply_ && reply_->isFinished ())
{
reply_->deleteLater ();
}
}
void RemoteFile::store ()
{
if (is_valid_)
{
if (!file_.isOpen ())
{
// create temporary file in the final location
auto path = QFileInfo {file_.fileName ()}.absoluteDir ();
if (path.mkpath ("."))
{
if (!file_.open (QSaveFile::WriteOnly))
{
abort ();
listener_->error (tr ("File System Error")
, tr ("Cannot open file:\n\"%1\"\nError(%2): %3")
.arg (path.path ())
.arg (file_.error ())
.arg (file_.errorString ()));
}
}
else
{
abort ();
listener_->error (tr ("File System Error")
, tr ("Cannot make path:\n\"%1\"")
.arg (path.path ()));
}
}
if (file_.write (reply_->read (reply_->bytesAvailable ())) < 0)
{
abort ();
listener_->error (tr ("File System Error")
, tr ("Cannot write to file:\n\"%1\"\nError(%2): %3")
.arg (file_.fileName ())
.arg (file_.error ())
.arg (file_.errorString ()));
}
}
}
-84
View File
@@ -1,84 +0,0 @@
#ifndef REMOTE_FILE_HPP__
#define REMOTE_FILE_HPP__
#include <QObject>
#include <QString>
#include <QUrl>
#include <QFileInfo>
#include <QSaveFile>
#include <QPointer>
class QNetworkAccessManager;
class QNetworkReply;
//
// Synchronize an individual file specified by a URL to the local file
// system
//
class RemoteFile final
: public QObject
{
Q_OBJECT
public:
//
// Clients of RemoteFile must provide an instance of this
// interface. It may be used to receive information and requests
// from the RemoteFile instance as it does its work.
//
class ListenerInterface
{
protected:
ListenerInterface () {}
public:
virtual void error (QString const& title, QString const& message) = 0;
virtual bool redirect_request (QUrl const&) {return false;} // disallow
virtual void download_progress (qint64 /* bytes_received */, qint64 /* total_bytes */) {}
virtual void download_finished (bool /* success */) {}
};
explicit RemoteFile (ListenerInterface * listener, QNetworkAccessManager * network_manager
, QString const& local_file_path, bool http_only = false
, QObject * parent = nullptr);
// true if local file exists or will do very soon
bool local () const;
// download/remove the local file
bool sync (QUrl const& url, bool local = true, bool force = false);
// abort an active download
void abort ();
// change the local location, this will rename if the file exists locally
void local_file_path (QString const&);
QString local_file_path () const {return local_file_.absoluteFilePath ();}
QUrl url () const {return url_;}
// always use an http scheme for remote URLs
void http_only (bool flag = true) {http_only_ = flag;}
private:
void download (QUrl url);
void reply_finished ();
Q_SLOT void store ();
Q_SIGNAL void redirect (QUrl const&, unsigned redirect_count);
Q_SIGNAL void downloadProgress (qint64 bytes_received, qint64 total_bytes);
Q_SIGNAL void finished ();
ListenerInterface * listener_;
QNetworkAccessManager * network_manager_;
QFileInfo local_file_;
bool http_only_;
QUrl url_;
QPointer<QNetworkReply> reply_;
bool is_valid_;
unsigned redirect_count_;
QSaveFile file_;
};
#endif
+3 -1
View File
@@ -16,6 +16,8 @@
#include <QDebug>
#include <QDebugStateSaver>
#include "DriftingDateTime.h"
#include "pimpl_impl.hpp"
#include "Radio.hpp"
@@ -631,7 +633,7 @@ bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction act
, [&band] (Station const& s) {return s.band_name_ == band;}))
{
// not found so add it
add (Station {band, 0, QDateTime::currentDateTimeUtc(), QDateTime::currentDateTimeUtc(), QString {}});
add (Station {band, 0, DriftingDateTime::currentDateTimeUtc(), DriftingDateTime::currentDateTimeUtc(), QString {}});
}
}
return true;
-58
View File
@@ -1,58 +0,0 @@
__ __ ______ _____ ________ __ __
| \ _ | \ / \ | \| \ | \ | \
| $$ / \ | $$| $$$$$$\ \$$$$$ \$$$$$$$$ | $$ | $$
| $$/ $\| $$| $$___\$$ | $$ | $$ ______ \$$\/ $$
| $$ $$$\ $$ \$$ \ __ | $$ | $$| \ >$$ $$
| $$ $$\$$\$$ _\$$$$$$\| \ | $$ | $$ \$$$$$$/ $$$$\
| $$$$ \$$$$| \__| $$| $$__| $$ | $$ | $$ \$$\
| $$$ \$$$ \$$ $$ \$$ $$ | $$ | $$ | $$
\$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$
Thanks to:
The FFTW library (http://www.fftw.org) without which the efficient
generation of discrete fast Fourier transformations essential to the
decoding DSP algorithms of WSJT-X would be a considerable part of the
project.
The Qt project (http://qt-project.org) that allows us to deliver a
rich industrial strength cross platform GUI application written in
C++.
Nate Bargmann, N0NB, and the Hamlib developer team for their
excellent library and for prompt review and acceptance of the many
pull requests for upstream patches to Hamlib.
Dave Bernstein, AA6YQ, for being so receptive to suggestions
allowing WSJT-X to cooperate with his excellent Amateur Radio DX and
award chasing suite (http://www.dxlabsuite.com).
Laurie Cowcher, VK3AMA, for developing the partner applications
JTAlertX and JTMacrosX (http://www.hamapps.com) that make DX chasing
with WSJT-X such an efficient and pleasurable experience.
The CMake build and packaging tools (http://www.cmake.org) for
their comprehensive scripting tools that make automation of building
and packaging on all supported platforms possible.
The NSIS MS Windows installer scripting and generator tools
(http://nsis.sourceforge.net) that, through the CPack NSIS generator,
allows us to build a comprehensive Windows installer package.
The GNU Compiler Collection (http://gcc.gnu.org) that allows us to
compile and link C++, Fortran and C code to the latest Standards and
with high quality optimization.
The clang C++ & C compiler front ends and LLVM compiler back end
tools (http://clang.llvm.org) that provide us with another, gcc
compatible, high quality C++ and C compiler and Standard Library suite
which, particularly on Apple Mac, allows our code to be ported to the
maximum number of platforms.
The MinGW project (http://www.mingw.org) that ports the gcc
compilers and related GNU tools to the MS Windows environment allowing
a high quality C++, Fortran and C application to be portable between
native MS Windows and other platforms such as Linux and Apple Mac.
-135
View File
@@ -1,135 +0,0 @@
#include "BeaconsModel.hpp"
#include <QStandardItem>
#include <QFont>
namespace
{
char const * const headings[] = {
QT_TRANSLATE_NOOP ("BeaconsModel", "Client"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Time"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Snr"),
QT_TRANSLATE_NOOP ("BeaconsModel", "DT"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Frequency"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Drift"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Grid"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Power"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Live"),
QT_TRANSLATE_NOOP ("BeaconsModel", "Callsign"),
};
QString live_string (bool off_air)
{
return off_air ? QT_TRANSLATE_NOOP ("BeaconsModel", "no") : QT_TRANSLATE_NOOP ("BeaconsModel", "yes");
}
QFont text_font {"Courier", 10};
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time
, Frequency frequency, qint32 drift, QString const& callsign
, QString const& grid, qint32 power, bool off_air)
{
auto time_item = new QStandardItem {time.toString ("hh:mm")};
time_item->setData (time);
time_item->setTextAlignment (Qt::AlignRight);
auto snr_item = new QStandardItem {QString::number (snr)};
snr_item->setData (snr);
snr_item->setTextAlignment (Qt::AlignRight);
auto dt = new QStandardItem {QString::number (delta_time)};
dt->setData (delta_time);
dt->setTextAlignment (Qt::AlignRight);
auto freq = new QStandardItem {Radio::pretty_frequency_MHz_string (frequency)};
freq->setData (frequency);
freq->setTextAlignment (Qt::AlignRight);
auto dri = new QStandardItem {QString::number (drift)};
dri->setData (drift);
dri->setTextAlignment (Qt::AlignRight);
auto gd = new QStandardItem {grid};
gd->setTextAlignment (Qt::AlignRight);
auto pwr = new QStandardItem {QString::number (power)};
pwr->setData (power);
pwr->setTextAlignment (Qt::AlignRight);
auto live = new QStandardItem {live_string (off_air)};
live->setTextAlignment (Qt::AlignHCenter);
QList<QStandardItem *> row {
new QStandardItem {client_id}, time_item, snr_item, dt, freq, dri, gd, pwr, live, new QStandardItem {callsign}};
Q_FOREACH (auto& item, row)
{
item->setEditable (false);
item->setFont (text_font);
item->setTextAlignment (item->textAlignment () | Qt::AlignVCenter);
}
return row;
}
}
BeaconsModel::BeaconsModel (QObject * parent)
: QStandardItemModel {0, sizeof (headings) / sizeof (headings[0]), parent}
{
int column {0};
for (auto const& heading : headings)
{
setHeaderData (column++, Qt::Horizontal, tr (heading));
}
}
void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, Frequency frequency, qint32 drift, QString const& callsign
, QString const& grid, qint32 power, bool off_air)
{
if (!is_new)
{
int target_row {-1};
for (auto row = 0; row < rowCount (); ++row)
{
if (data (index (row, 0)).toString () == client_id)
{
auto row_time = item (row, 1)->data ().toTime ();
if (row_time == time
&& item (row, 2)->data ().toInt () == snr
&& item (row, 3)->data ().toFloat () == delta_time
&& item (row, 4)->data ().value<Frequency> () == frequency
&& data (index (row, 5)).toInt () == drift
&& data (index (row, 7)).toString () == grid
&& data (index (row, 8)).toInt () == power
&& data (index (row, 6)).toString () == live_string (off_air)
&& data (index (row, 9)).toString () == callsign)
{
return;
}
if (time <= row_time)
{
target_row = row; // last row with same time
}
}
}
if (target_row >= 0)
{
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
return;
}
}
appendRow (make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
}
void BeaconsModel::clear_decodes (QString const& client_id)
{
for (auto row = rowCount () - 1; row >= 0; --row)
{
if (data (index (row, 0)).toString () == client_id)
{
removeRow (row);
}
}
}
#include "moc_BeaconsModel.cpp"
-38
View File
@@ -1,38 +0,0 @@
#ifndef WSJTX_UDP_BEACONS_MODEL_HPP__
#define WSJTX_UDP_BEACONS_MODEL_HPP__
#include <QStandardItemModel>
#include "MessageServer.hpp"
using Frequency = MessageServer::Frequency;
class QString;
class QTime;
//
// Beacons Model - simple data model for all beacon spots
//
// The model is a basic table with uniform row format. Rows consist of
// QStandardItem instances containing the string representation of the
// column data and if the underlying field is not a string then the
// UserRole+1 role contains the underlying data item.
//
// Two slots are provided to add a new decode and remove all spots for
// a client.
//
class BeaconsModel
: public QStandardItemModel
{
Q_OBJECT;
public:
explicit BeaconsModel (QObject * parent = nullptr);
Q_SLOT void add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, Frequency frequency, qint32 drift, QString const& callsign, QString const& grid
, qint32 power, bool off_air);
Q_SLOT void clear_decodes (QString const& client_id);
};
#endif
-310
View File
@@ -1,310 +0,0 @@
#include "ClientWidget.hpp"
#include <QRegExp>
#include <QColor>
#include "MaidenheadLocatorValidator.hpp"
namespace
{
//QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
QRegularExpression cq_re {"(CQ|CQDX|QRZ)[^A-Z0-9/]+"};
void update_dynamic_property (QWidget * widget, char const * property, QVariant const& value)
{
widget->setProperty (property, value);
widget->style ()->unpolish (widget);
widget->style ()->polish (widget);
widget->update ();
}
}
ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id)
: client_id_ {client_id}
, rx_df_ (-1)
{
}
QVariant ClientWidget::IdFilterModel::data (QModelIndex const& proxy_index, int role) const
{
if (role == Qt::BackgroundRole)
{
switch (proxy_index.column ())
{
case 8: // message
{
auto message = QSortFilterProxyModel::data (proxy_index).toString ();
if (base_call_re_.pattern ().size ()
&& message.contains (base_call_re_))
{
return QColor {255,200,200};
}
if (message.contains (cq_re))
{
return QColor {200, 255, 200};
}
}
break;
case 4: // DF
if (qAbs (QSortFilterProxyModel::data (proxy_index).toInt () - rx_df_) <= 10)
{
return QColor {255, 200, 200};
}
break;
default:
break;
}
}
return QSortFilterProxyModel::data (proxy_index, role);
}
bool ClientWidget::IdFilterModel::filterAcceptsRow (int source_row
, QModelIndex const& source_parent) const
{
auto source_index_col0 = sourceModel ()->index (source_row, 0, source_parent);
return sourceModel ()->data (source_index_col0).toString () == client_id_;
}
void ClientWidget::IdFilterModel::de_call (QString const& call)
{
if (call != call_)
{
beginResetModel ();
if (call.size ())
{
base_call_re_.setPattern ("[^A-Z0-9]*" + Radio::base_callsign (call) + "[^A-Z0-9]*");
}
else
{
base_call_re_.setPattern (QString {});
}
call_ = call;
endResetModel ();
}
}
void ClientWidget::IdFilterModel::rx_df (int df)
{
if (df != rx_df_)
{
beginResetModel ();
rx_df_ = df;
endResetModel ();
}
}
namespace
{
QString make_title (QString const& id, QString const& version, QString const& revision)
{
QString title {id};
if (version.size ())
{
title += QString {" v%1"}.arg (version);
}
if (revision.size ())
{
title += QString {" (%1)"}.arg (revision);
}
return title;
}
}
ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
, QString const& id, QString const& version, QString const& revision
, QListWidget const * calls_of_interest, QWidget * parent)
: QDockWidget {make_title (id, version, revision), parent}
, id_ {id}
, calls_of_interest_ {calls_of_interest}
, decodes_proxy_model_ {id_}
, decodes_table_view_ {new QTableView}
, beacons_table_view_ {new QTableView}
, message_line_edit_ {new QLineEdit}
, grid_line_edit_ {new QLineEdit}
, decodes_stack_ {new QStackedLayout}
, auto_off_button_ {new QPushButton {tr ("&Auto Off")}}
, halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}}
, de_label_ {new QLabel}
, mode_label_ {new QLabel}
, fast_mode_ {false}
, frequency_label_ {new QLabel}
, dx_label_ {new QLabel}
, rx_df_label_ {new QLabel}
, tx_df_label_ {new QLabel}
, report_label_ {new QLabel}
, columns_resized_ {false}
{
// set up widgets
decodes_proxy_model_.setSourceModel (decodes_model);
decodes_table_view_->setModel (&decodes_proxy_model_);
decodes_table_view_->verticalHeader ()->hide ();
decodes_table_view_->hideColumn (0);
decodes_table_view_->horizontalHeader ()->setStretchLastSection (true);
auto form_layout = new QFormLayout;
form_layout->addRow (tr ("Free text:"), message_line_edit_);
form_layout->addRow (tr ("Temporary grid:"), grid_line_edit_);
message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this});
grid_line_edit_->setValidator (new MaidenheadLocatorValidator {this});
connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) {
Q_EMIT do_free_text (id_, text, false);
});
connect (message_line_edit_, &QLineEdit::editingFinished, [this] () {
Q_EMIT do_free_text (id_, message_line_edit_->text (), true);
});
connect (grid_line_edit_, &QLineEdit::editingFinished, [this] () {
Q_EMIT location (id_, grid_line_edit_->text ());
});
auto decodes_page = new QWidget;
auto decodes_layout = new QVBoxLayout {decodes_page};
decodes_layout->setContentsMargins (QMargins {2, 2, 2, 2});
decodes_layout->addWidget (decodes_table_view_);
decodes_layout->addLayout (form_layout);
auto beacons_proxy_model = new IdFilterModel {id_};
beacons_proxy_model->setSourceModel (beacons_model);
beacons_table_view_->setModel (beacons_proxy_model);
beacons_table_view_->verticalHeader ()->hide ();
beacons_table_view_->hideColumn (0);
beacons_table_view_->horizontalHeader ()->setStretchLastSection (true);
auto beacons_page = new QWidget;
auto beacons_layout = new QVBoxLayout {beacons_page};
beacons_layout->setContentsMargins (QMargins {2, 2, 2, 2});
beacons_layout->addWidget (beacons_table_view_);
decodes_stack_->addWidget (decodes_page);
decodes_stack_->addWidget (beacons_page);
// stack alternative views
auto content_layout = new QVBoxLayout;
content_layout->setContentsMargins (QMargins {2, 2, 2, 2});
content_layout->addLayout (decodes_stack_);
// set up controls
auto control_button_box = new QDialogButtonBox;
control_button_box->addButton (auto_off_button_, QDialogButtonBox::ActionRole);
control_button_box->addButton (halt_tx_button_, QDialogButtonBox::ActionRole);
connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
Q_EMIT do_halt_tx (id_, true);
});
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
Q_EMIT do_halt_tx (id_, false);
});
content_layout->addWidget (control_button_box);
// set up status area
auto status_bar = new QStatusBar;
status_bar->addPermanentWidget (de_label_);
status_bar->addPermanentWidget (mode_label_);
status_bar->addPermanentWidget (frequency_label_);
status_bar->addPermanentWidget (dx_label_);
status_bar->addPermanentWidget (rx_df_label_);
status_bar->addPermanentWidget (tx_df_label_);
status_bar->addPermanentWidget (report_label_);
content_layout->addWidget (status_bar);
connect (this, &ClientWidget::topLevelChanged, status_bar, &QStatusBar::setSizeGripEnabled);
// set up central widget
auto content_widget = new QFrame;
content_widget->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken);
content_widget->setLayout (content_layout);
setWidget (content_widget);
// setMinimumSize (QSize {550, 0});
setFeatures (DockWidgetMovable | DockWidgetFloatable);
setAllowedAreas (Qt::BottomDockWidgetArea);
setFloating (true);
// connect up table view signals
connect (decodes_table_view_, &QTableView::doubleClicked, this, [this] (QModelIndex const& index) {
Q_EMIT do_reply (decodes_proxy_model_.mapToSource (index), QApplication::keyboardModifiers () >> 24);
});
// tell new client about calls of interest
for (int row = 0; row < calls_of_interest_->count (); ++row)
{
Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text (), QColor {Qt::blue}, QColor {Qt::yellow});
}
}
ClientWidget::~ClientWidget ()
{
for (int row = 0; row < calls_of_interest_->count (); ++row)
{
// tell client to forget calls of interest
Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text ());
}
}
void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df
, QString const& de_call, QString const& de_grid, QString const& dx_grid
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode)
{
if (id == id_)
{
fast_mode_ = fast_mode;
decodes_proxy_model_.de_call (de_call);
decodes_proxy_model_.rx_df (rx_df);
de_label_->setText (de_call.size () >= 0 ? QString {"DE: %1%2"}.arg (de_call)
.arg (de_grid.size () ? '(' + de_grid + ')' : QString {}) : QString {});
mode_label_->setText (QString {"Mode: %1%2%3%4"}
.arg (mode)
.arg (sub_mode)
.arg (fast_mode && !mode.contains (QRegularExpression {R"(ISCAT|MSK144)"}) ? "fast" : "")
.arg (tx_mode.isEmpty () || tx_mode == mode ? "" : '(' + tx_mode + ')'));
frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f));
dx_label_->setText (dx_call.size () >= 0 ? QString {"DX: %1%2"}.arg (dx_call)
.arg (dx_grid.size () ? '(' + dx_grid + ')' : QString {}) : QString {});
rx_df_label_->setText (rx_df >= 0 ? QString {"Rx: %1"}.arg (rx_df) : "");
tx_df_label_->setText (tx_df >= 0 ? QString {"Tx: %1"}.arg (tx_df) : "");
report_label_->setText ("SNR: " + report);
update_dynamic_property (frequency_label_, "transmitting", transmitting);
auto_off_button_->setEnabled (tx_enabled);
halt_tx_button_->setEnabled (transmitting);
update_dynamic_property (mode_label_, "decoding", decoding);
update_dynamic_property (tx_df_label_, "watchdog_timeout", watchdog_timeout);
}
}
void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
, float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/
, QString const& /*message*/, bool /*low_confidence*/, bool /*off_air*/)
{
if (client_id == id_ && !columns_resized_)
{
decodes_stack_->setCurrentIndex (0);
decodes_table_view_->resizeColumnsToContents ();
columns_resized_ = true;
}
decodes_table_view_->scrollToBottom ();
}
void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
, float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/
, QString const& /*callsign*/, QString const& /*grid*/, qint32 /*power*/
, bool /*off_air*/)
{
if (client_id == id_ && !columns_resized_)
{
decodes_stack_->setCurrentIndex (1);
beacons_table_view_->resizeColumnsToContents ();
columns_resized_ = true;
}
beacons_table_view_->scrollToBottom ();
}
void ClientWidget::clear_decodes (QString const& client_id)
{
if (client_id == id_)
{
columns_resized_ = false;
}
}
#include "moc_ClientWidget.cpp"
-94
View File
@@ -1,94 +0,0 @@
#ifndef WSJTX_UDP_CLIENT_WIDGET_MODEL_HPP__
#define WSJTX_UDP_CLIENT_WIDGET_MODEL_HPP__
#include <QObject>
#include <QSortFilterProxyModel>
#include <QString>
#include <QRegularExpression>
#include <QtWidgets>
#include "MessageServer.hpp"
class QAbstractItemModel;
class QModelIndex;
class QColor;
using Frequency = MessageServer::Frequency;
class ClientWidget
: public QDockWidget
{
Q_OBJECT;
public:
explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
, QString const& id, QString const& version, QString const& revision
, QListWidget const * calls_of_interest, QWidget * parent = nullptr);
~ClientWidget ();
bool fast_mode () const {return fast_mode_;}
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df
, QString const& de_call, QString const& de_grid, QString const& dx_grid
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode);
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime, qint32 snr
, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message, bool low_confidence, bool off_air);
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime, qint32 snr
, float delta_time, Frequency delta_frequency, qint32 drift
, QString const& callsign, QString const& grid, qint32 power
, bool off_air);
Q_SLOT void clear_decodes (QString const& client_id);
Q_SIGNAL void do_reply (QModelIndex const&, quint8 modifier);
Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only);
Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool);
Q_SIGNAL void location (QString const& id, QString const& text);
Q_SIGNAL void highlight_callsign (QString const& id, QString const& call
, QColor const& bg = QColor {}, QColor const& fg = QColor {}
, bool last_only = false);
private:
QString id_;
QListWidget const * calls_of_interest_;
class IdFilterModel final
: public QSortFilterProxyModel
{
public:
IdFilterModel (QString const& client_id);
void de_call (QString const&);
void rx_df (int);
QVariant data (QModelIndex const& proxy_index, int role = Qt::DisplayRole) const override;
protected:
bool filterAcceptsRow (int source_row, QModelIndex const& source_parent) const override;
private:
QString client_id_;
QString call_;
QRegularExpression base_call_re_;
int rx_df_;
} decodes_proxy_model_;
QTableView * decodes_table_view_;
QTableView * beacons_table_view_;
QLineEdit * message_line_edit_;
QLineEdit * grid_line_edit_;
QStackedLayout * decodes_stack_;
QAbstractButton * auto_off_button_;
QAbstractButton * halt_tx_button_;
QLabel * de_label_;
QLabel * mode_label_;
bool fast_mode_;
QLabel * frequency_label_;
QLabel * dx_label_;
QLabel * rx_df_label_;
QLabel * tx_df_label_;
QLabel * report_label_;
bool columns_resized_;
};
#endif
-153
View File
@@ -1,153 +0,0 @@
#include "DecodesModel.hpp"
#include <QStandardItem>
#include <QModelIndex>
#include <QTime>
#include <QString>
#include <QFont>
#include <QList>
namespace
{
char const * const headings[] = {
QT_TRANSLATE_NOOP ("DecodesModel", "Client"),
QT_TRANSLATE_NOOP ("DecodesModel", "Time"),
QT_TRANSLATE_NOOP ("DecodesModel", "Snr"),
QT_TRANSLATE_NOOP ("DecodesModel", "DT"),
QT_TRANSLATE_NOOP ("DecodesModel", "DF"),
QT_TRANSLATE_NOOP ("DecodesModel", "Md"),
QT_TRANSLATE_NOOP ("DecodesModel", "Confidence"),
QT_TRANSLATE_NOOP ("DecodesModel", "Live"),
QT_TRANSLATE_NOOP ("DecodesModel", "Message"),
};
QString confidence_string (bool low_confidence)
{
return low_confidence ? QT_TRANSLATE_NOOP ("DecodesModel", "low") : QT_TRANSLATE_NOOP ("DecodesModel", "high");
}
QString live_string (bool off_air)
{
return off_air ? QT_TRANSLATE_NOOP ("DecodesModel", "no") : QT_TRANSLATE_NOOP ("DecodesModel", "yes");
}
QFont text_font {"Courier", 10};
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence, bool off_air, bool is_fast)
{
auto time_item = new QStandardItem {time.toString (is_fast || "~" == mode ? "hh:mm:ss" : "hh:mm")};
time_item->setData (time);
time_item->setTextAlignment (Qt::AlignRight);
auto snr_item = new QStandardItem {QString::number (snr)};
snr_item->setData (snr);
snr_item->setTextAlignment (Qt::AlignRight);
auto dt = new QStandardItem {QString::number (delta_time)};
dt->setData (delta_time);
dt->setTextAlignment (Qt::AlignRight);
auto df = new QStandardItem {QString::number (delta_frequency)};
df->setData (delta_frequency);
df->setTextAlignment (Qt::AlignRight);
auto md = new QStandardItem {mode};
md->setTextAlignment (Qt::AlignHCenter);
auto confidence = new QStandardItem {confidence_string (low_confidence)};
confidence->setTextAlignment (Qt::AlignHCenter);
auto live = new QStandardItem {live_string (off_air)};
live->setTextAlignment (Qt::AlignHCenter);
QList<QStandardItem *> row {
new QStandardItem {client_id}, time_item, snr_item, dt, df, md, confidence, live, new QStandardItem {message}};
Q_FOREACH (auto& item, row)
{
item->setEditable (false);
item->setFont (text_font);
item->setTextAlignment (item->textAlignment () | Qt::AlignVCenter);
}
return row;
}
}
DecodesModel::DecodesModel (QObject * parent)
: QStandardItemModel {0, sizeof (headings) / sizeof (headings[0]), parent}
{
int column {0};
for (auto const& heading : headings)
{
setHeaderData (column++, Qt::Horizontal, tr (heading));
}
}
void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence, bool off_air, bool is_fast)
{
if (!is_new)
{
int target_row {-1};
for (auto row = 0; row < rowCount (); ++row)
{
if (data (index (row, 0)).toString () == client_id)
{
auto row_time = item (row, 1)->data ().toTime ();
if (row_time == time
&& item (row, 2)->data ().toInt () == snr
&& item (row, 3)->data ().toFloat () == delta_time
&& item (row, 4)->data ().toUInt () == delta_frequency
&& data (index (row, 5)).toString () == mode
&& data (index (row, 7)).toString () == confidence_string (low_confidence)
&& data (index (row, 6)).toString () == live_string (off_air)
&& data (index (row, 8)).toString () == message)
{
return;
}
if (time <= row_time)
{
target_row = row; // last row with same time
}
}
}
if (target_row >= 0)
{
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, delta_frequency, mode
, message, low_confidence, off_air, is_fast));
return;
}
}
appendRow (make_row (client_id, time, snr, delta_time, delta_frequency, mode, message, low_confidence
, off_air, is_fast));
}
void DecodesModel::clear_decodes (QString const& client_id)
{
for (auto row = rowCount () - 1; row >= 0; --row)
{
if (data (index (row, 0)).toString () == client_id)
{
removeRow (row);
}
}
}
void DecodesModel::do_reply (QModelIndex const& source, quint8 modifiers)
{
auto row = source.row ();
Q_EMIT reply (data (index (row, 0)).toString ()
, item (row, 1)->data ().toTime ()
, item (row, 2)->data ().toInt ()
, item (row, 3)->data ().toFloat ()
, item (row, 4)->data ().toInt ()
, data (index (row, 5)).toString ()
, data (index (row, 8)).toString ()
, confidence_string (true) == data (index (row, 7)).toString ()
, modifiers);
}
#include "moc_DecodesModel.cpp"
-44
View File
@@ -1,44 +0,0 @@
#ifndef WSJTX_UDP_DECODES_MODEL_HPP__
#define WSJTX_UDP_DECODES_MODEL_HPP__
#include <QStandardItemModel>
#include "MessageServer.hpp"
using Frequency = MessageServer::Frequency;
class QTime;
class QString;
class QModelIndex;
//
// Decodes Model - simple data model for all decodes
//
// The model is a basic table with uniform row format. Rows consist of
// QStandardItem instances containing the string representation of the
// column data and if the underlying field is not a string then the
// UserRole+1 role contains the underlying data item.
//
// Three slots are provided to add a new decode, remove all decodes
// for a client and, to build a reply to CQ message for a given row
// which is emitted as a signal respectively.
//
class DecodesModel
: public QStandardItemModel
{
Q_OBJECT;
public:
explicit DecodesModel (QObject * parent = nullptr);
Q_SLOT void add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence, bool off_air, bool is_fast);
Q_SLOT void clear_decodes (QString const& client_id);
Q_SLOT void do_reply (QModelIndex const& source, quint8 modifiers);
Q_SIGNAL void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message, bool low_confidence, quint8 modifiers);
};
#endif
-90
View File
@@ -1,90 +0,0 @@
//
// MessageAggregator - an example application that utilizes the WSJT-X
// messaging facility
//
// This application is only provided as a simple GUI application
// example to demonstrate the WSJT-X messaging facility. It allows the
// user to set the server details either as a unicast UDP server or,
// if a multicast group address is provided, as a multicast server.
// The benefit of the multicast server is that multiple servers can be
// active at once each receiving all WSJT-X broadcast messages and
// each able to respond to individual WSJT_X clients. To utilize the
// multicast group features each WSJT-X client must set the same
// multicast group address as the UDP server address for example
// 239.255.0.0 for a site local multicast group.
//
// The UI is a small panel to input the service port number and
// optionally the multicast group address. Below that a table
// representing the log entries where any QSO logged messages
// broadcast from WSJT-X clients are displayed. The bottom of the
// application main window is a dock area where a dock window will
// appear for each WSJT-X client, this window contains a table of the
// current decode messages broadcast from that WSJT-X client and a
// status line showing the status update messages broadcast from the
// WSJT-X client. The dock windows may be arranged in a tab bar, side
// by side, below each other or, completely detached from the dock
// area as floating windows. Double clicking the dock window title bar
// or dragging and dropping with the mouse allows these different
// arrangements.
//
// The application also provides a simple menu bar including a view
// menu that allows each dock window to be hidden or revealed.
//
#include <clocale>
#include <iostream>
#include <exception>
#include <QFile>
#include <QApplication>
#include <QMessageBox>
#include <QObject>
#include "MessageAggregatorMainWindow.hpp"
// deduce the size of an array
template<class T, size_t N>
inline
size_t size (T (&)[N]) {return N;}
int main (int argc, char * argv[])
{
QApplication app {argc, argv};
try
{
setlocale (LC_NUMERIC, "C"); // ensure number forms are in
// consistent format, do this after
// instantiating QApplication so
// that GUI has correct l18n
app.setApplicationName ("WSJT-X Reference UDP Message Aggregator Server");
app.setApplicationVersion ("1.0");
QObject::connect (&app, SIGNAL (lastWindowClosed ()), &app, SLOT (quit ()));
{
QFile file {":/qss/default.qss"};
if (!file.open (QFile::ReadOnly))
{
throw std::runtime_error {
QString {"failed to open \"" + file.fileName () + "\": " + file.errorString ()}
.toLocal8Bit ().constData ()};
}
app.setStyleSheet (file.readAll());
}
MessageAggregatorMainWindow window;
return app.exec ();
}
catch (std::exception const & e)
{
QMessageBox::critical (nullptr, app.applicationName (), e.what ());
std::cerr << "Error: " << e.what () << '\n';
}
catch (...)
{
QMessageBox::critical (nullptr, app.applicationName (), QObject::tr ("Unexpected error"));
std::cerr << "Unexpected error\n";
}
return -1;
}
-284
View File
@@ -1,284 +0,0 @@
#include "MessageAggregatorMainWindow.hpp"
#include <QtWidgets>
#include <QDateTime>
#include "DecodesModel.hpp"
#include "BeaconsModel.hpp"
#include "ClientWidget.hpp"
using port_type = MessageServer::port_type;
namespace
{
char const * const headings[] = {
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Time On"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Time Off"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Callsign"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Grid"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Name"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Frequency"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Mode"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Sent"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Rec'd"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Power"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Operator"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "My Call"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "My Grid"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Comments"),
};
}
MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
: log_ {new QStandardItemModel {0, 14, this}}
, decodes_model_ {new DecodesModel {this}}
, beacons_model_ {new BeaconsModel {this}}
, server_ {new MessageServer {this}}
, multicast_group_line_edit_ {new QLineEdit}
, log_table_view_ {new QTableView}
, add_call_of_interest_action_ {new QAction {tr ("&Add callsign"), this}}
, delete_call_of_interest_action_ {new QAction {tr ("&Delete callsign"), this}}
, last_call_of_interest_action_ {new QAction {tr ("&Highlight last only"), this}}
, call_of_interest_bg_colour_action_ {new QAction {tr ("&Background colour"), this}}
, call_of_interest_fg_colour_action_ {new QAction {tr ("&Foreground colour"), this}}
{
// logbook
int column {0};
for (auto const& heading : headings)
{
log_->setHeaderData (column++, Qt::Horizontal, tr (heading));
}
connect (server_, &MessageServer::qso_logged, this, &MessageAggregatorMainWindow::log_qso);
// menu bar
auto file_menu = menuBar ()->addMenu (tr ("&File"));
auto exit_action = new QAction {tr ("E&xit"), this};
exit_action->setShortcuts (QKeySequence::Quit);
exit_action->setToolTip (tr ("Exit the application"));
file_menu->addAction (exit_action);
connect (exit_action, &QAction::triggered, this, &MessageAggregatorMainWindow::close);
view_menu_ = menuBar ()->addMenu (tr ("&View"));
// central layout
auto central_layout = new QVBoxLayout;
// server details
auto port_spin_box = new QSpinBox;
port_spin_box->setMinimum (1);
port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
auto group_box_layout = new QFormLayout;
group_box_layout->addRow (tr ("Port number:"), port_spin_box);
group_box_layout->addRow (tr ("Multicast Group (blank for unicast server):"), multicast_group_line_edit_);
auto group_box = new QGroupBox {tr ("Server Details")};
group_box->setLayout (group_box_layout);
central_layout->addWidget (group_box);
log_table_view_->setModel (log_);
log_table_view_->verticalHeader ()->hide ();
central_layout->addWidget (log_table_view_);
// central widget
auto central_widget = new QWidget;
central_widget->setLayout (central_layout);
// main window setup
setCentralWidget (central_widget);
setDockOptions (AnimatedDocks | AllowNestedDocks | AllowTabbedDocks);
setTabPosition (Qt::BottomDockWidgetArea, QTabWidget::North);
QDockWidget * calls_dock {new QDockWidget {tr ("Calls of Interest"), this}};
calls_dock->setAllowedAreas (Qt::RightDockWidgetArea);
calls_of_interest_ = new QListWidget {calls_dock};
calls_of_interest_->setContextMenuPolicy (Qt::ActionsContextMenu);
calls_of_interest_->insertAction (nullptr, add_call_of_interest_action_);
connect (add_call_of_interest_action_, &QAction::triggered, [this] () {
auto item = new QListWidgetItem {};
item->setFlags (item->flags () | Qt::ItemIsEditable);
item->setData (Qt::UserRole, QString {});
calls_of_interest_->addItem (item);
calls_of_interest_->editItem (item);
});
calls_of_interest_->insertAction (nullptr, delete_call_of_interest_action_);
connect (delete_call_of_interest_action_, &QAction::triggered, [this] () {
for (auto item : calls_of_interest_->selectedItems ())
{
auto old_call = item->data (Qt::UserRole);
if (old_call.isValid ()) change_highlighting (old_call.toString ());
delete item;
}
});
calls_of_interest_->insertAction (nullptr, last_call_of_interest_action_);
connect (last_call_of_interest_action_, &QAction::triggered, [this] () {
for (auto item : calls_of_interest_->selectedItems ())
{
auto old_call = item->data (Qt::UserRole);
change_highlighting (old_call.toString ());
change_highlighting (old_call.toString ()
, item->background ().color (), item->foreground ().color (), true);
delete item;
}
});
calls_of_interest_->insertAction (nullptr, call_of_interest_bg_colour_action_);
connect (call_of_interest_bg_colour_action_, &QAction::triggered, [this] () {
for (auto item : calls_of_interest_->selectedItems ())
{
auto old_call = item->data (Qt::UserRole);
auto new_colour = QColorDialog::getColor (item->background ().color ()
, this, tr ("Select background color"));
if (new_colour.isValid ())
{
change_highlighting (old_call.toString (), new_colour, item->foreground ().color ());
item->setBackground (new_colour);
}
}
});
calls_of_interest_->insertAction (nullptr, call_of_interest_fg_colour_action_);
connect (call_of_interest_fg_colour_action_, &QAction::triggered, [this] () {
for (auto item : calls_of_interest_->selectedItems ())
{
auto old_call = item->data (Qt::UserRole);
auto new_colour = QColorDialog::getColor (item->foreground ().color ()
, this, tr ("Select foreground color"));
if (new_colour.isValid ())
{
change_highlighting (old_call.toString (), item->background ().color (), new_colour);
item->setForeground (new_colour);
}
}
});
connect (calls_of_interest_, &QListWidget::itemChanged, [this] (QListWidgetItem * item) {
auto old_call = item->data (Qt::UserRole);
auto new_call = item->text ().toUpper ();
if (new_call != old_call)
{
// tell all clients
if (old_call.isValid ())
{
change_highlighting (old_call.toString ());
}
item->setData (Qt::UserRole, new_call);
item->setText (new_call);
auto bg = item->listWidget ()->palette ().text ().color ();
auto fg = item->listWidget ()->palette ().base ().color ();
item->setBackground (bg);
item->setForeground (fg);
change_highlighting (new_call, bg, fg);
}
});
calls_dock->setWidget (calls_of_interest_);
addDockWidget (Qt::RightDockWidgetArea, calls_dock);
view_menu_->addAction (calls_dock->toggleViewAction ());
view_menu_->addSeparator ();
// connect up server
connect (server_, &MessageServer::error, [this] (QString const& message) {
QMessageBox::warning (this, QApplication::applicationName (), tr ("Network Error"), message);
});
connect (server_, &MessageServer::client_opened, this, &MessageAggregatorMainWindow::add_client);
connect (server_, &MessageServer::client_closed, this, &MessageAggregatorMainWindow::remove_client);
connect (server_, &MessageServer::client_closed, decodes_model_, &DecodesModel::clear_decodes);
connect (server_, &MessageServer::client_closed, beacons_model_, &BeaconsModel::clear_decodes);
connect (server_, &MessageServer::decode, [this] (bool is_new, QString const& id, QTime time
, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode
, QString const& message, bool low_confidence
, bool off_air) {
decodes_model_->add_decode (is_new, id, time, snr, delta_time, delta_frequency, mode, message
, low_confidence, off_air, dock_widgets_[id]->fast_mode ());});
connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot);
connect (server_, &MessageServer::clear_decodes, decodes_model_, &DecodesModel::clear_decodes);
connect (server_, &MessageServer::clear_decodes, beacons_model_, &BeaconsModel::clear_decodes);
connect (decodes_model_, &DecodesModel::reply, server_, &MessageServer::reply);
// UI behaviour
connect (port_spin_box, static_cast<void (QSpinBox::*)(int)> (&QSpinBox::valueChanged)
, [this] (port_type port) {server_->start (port);});
connect (multicast_group_line_edit_, &QLineEdit::editingFinished, [this, port_spin_box] () {
server_->start (port_spin_box->value (), QHostAddress {multicast_group_line_edit_->text ()});
});
port_spin_box->setValue (2237); // start up in unicast mode
show ();
}
void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time_off, QString const& dx_call
, QString const& dx_grid, Frequency dial_frequency, QString const& mode
, QString const& report_sent, QString const& report_received
, QString const& tx_power, QString const& comments
, QString const& name, QDateTime time_on, QString const& operator_call
, QString const& my_call, QString const& my_grid)
{
QList<QStandardItem *> row;
row << new QStandardItem {time_on.toString ("dd-MMM-yyyy hh:mm:ss")}
<< new QStandardItem {time_off.toString ("dd-MMM-yyyy hh:mm:ss")}
<< new QStandardItem {dx_call}
<< new QStandardItem {dx_grid}
<< new QStandardItem {name}
<< new QStandardItem {Radio::frequency_MHz_string (dial_frequency)}
<< new QStandardItem {mode}
<< new QStandardItem {report_sent}
<< new QStandardItem {report_received}
<< new QStandardItem {tx_power}
<< new QStandardItem {operator_call}
<< new QStandardItem {my_call}
<< new QStandardItem {my_grid}
<< new QStandardItem {comments};
log_->appendRow (row);
log_table_view_->resizeColumnsToContents ();
log_table_view_->horizontalHeader ()->setStretchLastSection (true);
log_table_view_->scrollToBottom ();
}
void MessageAggregatorMainWindow::add_client (QString const& id, QString const& version, QString const& revision)
{
auto dock = new ClientWidget {decodes_model_, beacons_model_, id, version, revision, calls_of_interest_, this};
dock->setAttribute (Qt::WA_DeleteOnClose);
auto view_action = dock->toggleViewAction ();
view_action->setEnabled (true);
view_menu_->addAction (view_action);
addDockWidget (Qt::BottomDockWidgetArea, dock);
connect (server_, &MessageServer::status_update, dock, &ClientWidget::update_status);
connect (server_, &MessageServer::decode, dock, &ClientWidget::decode_added);
connect (server_, &MessageServer::WSPR_decode, dock, &ClientWidget::beacon_spot_added);
connect (server_, &MessageServer::clear_decodes, dock, &ClientWidget::clear_decodes);
connect (dock, &ClientWidget::do_reply, decodes_model_, &DecodesModel::do_reply);
connect (dock, &ClientWidget::do_halt_tx, server_, &MessageServer::halt_tx);
connect (dock, &ClientWidget::do_free_text, server_, &MessageServer::free_text);
connect (dock, &ClientWidget::location, server_, &MessageServer::location);
connect (view_action, &QAction::toggled, dock, &ClientWidget::setVisible);
connect (dock, &ClientWidget::highlight_callsign, server_, &MessageServer::highlight_callsign);
dock_widgets_[id] = dock;
server_->replay (id); // request decodes and status
}
void MessageAggregatorMainWindow::remove_client (QString const& id)
{
auto iter = dock_widgets_.find (id);
if (iter != std::end (dock_widgets_))
{
(*iter)->close ();
dock_widgets_.erase (iter);
}
}
MessageAggregatorMainWindow::~MessageAggregatorMainWindow ()
{
for (auto client : dock_widgets_)
{
delete client;
}
}
void MessageAggregatorMainWindow::change_highlighting (QString const& call, QColor const& bg, QColor const& fg
, bool last_only)
{
for (auto id : dock_widgets_.keys ())
{
server_->highlight_callsign (id, call, bg, fg, last_only);
}
}
#include "moc_MessageAggregatorMainWindow.cpp"
@@ -1,62 +0,0 @@
#ifndef WSJTX_MESSAGE_AGGREGATOR_MAIN_WINDOW_MODEL_HPP__
#define WSJTX_MESSAGE_AGGREGATOR_MAIN_WINDOW_MODEL_HPP__
#include <QMainWindow>
#include <QHash>
#include <QString>
#include "MessageServer.hpp"
class QDateTime;
class QStandardItemModel;
class QMenu;
class DecodesModel;
class BeaconsModel;
class QLineEdit;
class QTableView;
class ClientWidget;
class QListWidget;
using Frequency = MessageServer::Frequency;
class MessageAggregatorMainWindow
: public QMainWindow
{
Q_OBJECT;
public:
MessageAggregatorMainWindow ();
~MessageAggregatorMainWindow ();
Q_SLOT void log_qso (QString const& /*id*/, QDateTime time_off, QString const& dx_call, QString const& dx_grid
, Frequency dial_frequency, QString const& mode, QString const& report_sent
, QString const& report_received, QString const& tx_power, QString const& comments
, QString const& name, QDateTime time_on, QString const& operator_call
, QString const& my_call, QString const& my_grid);
private:
void add_client (QString const& id, QString const& version, QString const& revision);
void remove_client (QString const& id);
void change_highlighting (QString const& call, QColor const& bg = QColor {}, QColor const& fg = QColor {},
bool last_only = false);
// maps client id to widgets
using ClientsDictionary = QHash<QString, ClientWidget *>;
ClientsDictionary dock_widgets_;
QStandardItemModel * log_;
QMenu * view_menu_;
DecodesModel * decodes_model_;
BeaconsModel * beacons_model_;
MessageServer * server_;
QLineEdit * multicast_group_line_edit_;
QTableView * log_table_view_;
QListWidget * calls_of_interest_;
QAction * add_call_of_interest_action_;
QAction * delete_call_of_interest_action_;
QAction * last_call_of_interest_action_;
QAction * call_of_interest_bg_colour_action_;
QAction * call_of_interest_fg_colour_action_;
};
#endif
-245
View File
@@ -1,245 +0,0 @@
//
// UDPDaemon - an example console application that utilizes the WSJT-X
// messaging facility
//
// This application is only provided as a simple console application
// example to demonstrate the WSJT-X messaging facility. It allows
// the user to set the server details either as a unicast UDP server
// or, if a multicast group address is provided, as a multicast
// server. The benefit of the multicast server is that multiple
// servers can be active at once each receiving all WSJT-X broadcast
// messages and each able to respond to individual WSJT_X clients. To
// utilize the multicast group features each WSJT-X client must set
// the same multicast group address as the UDP server address for
// example 239.255.0.0 for a site local multicast group.
//
//
#include <iostream>
#include <exception>
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDateTime>
#include <QTime>
#include <QHash>
#include <QDebug>
#include "MessageServer.hpp"
#include "Radio.hpp"
#include "qt_helpers.hpp"
using port_type = MessageServer::port_type;
using Frequency = MessageServer::Frequency;
class Client
: public QObject
{
Q_OBJECT
public:
explicit Client (QString const& id, QObject * parent = nullptr)
: QObject {parent}
, id_ {id}
, dial_frequency_ {0u}
{
}
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& /*dx_call*/
, QString const& /*report*/, QString const& /*tx_mode*/, bool /*tx_enabled*/
, bool /*transmitting*/, bool /*decoding*/, qint32 /*rx_df*/, qint32 /*tx_df*/
, QString const& /*de_call*/, QString const& /*de_grid*/, QString const& /*dx_grid*/
, bool /* watchdog_timeout */, QString const& sub_mode, bool /*fast_mode*/)
{
if (id == id_)
{
if (f != dial_frequency_)
{
std::cout << tr ("%1: Dial frequency changed to %2").arg (id_).arg (f).toStdString () << std::endl;
dial_frequency_ = f;
}
if (mode + sub_mode != mode_)
{
std::cout << tr ("%1: Mode changed to %2").arg (id_).arg (mode + sub_mode).toStdString () << std::endl;
mode_ = mode + sub_mode;
}
}
}
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime time, qint32 snr
, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message, bool low_confidence, bool off_air)
{
if (client_id == id_)
{
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
<< "Dt:" << delta_time << "Df:" << delta_frequency
<< "mode:" << mode << "Confidence:" << (low_confidence ? "low" : "high")
<< "On air:" << !off_air;
std::cout << tr ("%1: Decoded %2").arg (id_).arg (message).toStdString () << std::endl;
}
}
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime time, qint32 snr
, float delta_time, Frequency delta_frequency, qint32 drift, QString const& callsign
, QString const& grid, qint32 power, bool off_air)
{
if (client_id == id_)
{
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
<< "Dt:" << delta_time << "Df:" << delta_frequency
<< "drift:" << drift;
std::cout << tr ("%1: WSPR decode %2 grid %3 power: %4").arg (id_).arg (callsign).arg (grid).arg (power).toStdString ()
<< "On air:" << !off_air << std::endl;
}
}
Q_SLOT void qso_logged (QString const&client_id, QDateTime time_off, QString const& dx_call, QString const& dx_grid
, Frequency dial_frequency, QString const& mode, QString const& report_sent
, QString const& report_received, QString const& tx_power
, QString const& comments, QString const& name, QDateTime time_on
, QString const& operator_call, QString const& my_call, QString const& my_grid)
{
if (client_id == id_)
{
qDebug () << "time_on:" << time_on << "time_off:" << time_off << "dx_call:" << dx_call << "grid:" << dx_grid
<< "freq:" << dial_frequency << "mode:" << mode << "rpt_sent:" << report_sent
<< "rpt_rcvd:" << report_received << "Tx_pwr:" << tx_power << "comments:" << comments
<< "name:" << name << "operator_call:" << operator_call << "my_call:" << my_call
<< "my_grid:" << my_grid;
std::cout << QByteArray {80, '-'}.data () << '\n';
std::cout << tr ("%1: Logged %2 grid: %3 power: %4 sent: %5 recd: %6 freq: %7 time_off: %8 op: %9 my_call: %10 my_grid: %11")
.arg (id_).arg (dx_call).arg (dx_grid).arg (tx_power).arg (report_sent).arg (report_received)
.arg (dial_frequency).arg (time_off.toString("yyyy-MM-dd hh:mm:ss.z")).arg (operator_call)
.arg (my_call).arg (my_grid).toStdString ()
<< std::endl;
}
}
Q_SLOT void logged_ADIF (QString const&client_id, QByteArray const& ADIF)
{
if (client_id == id_)
{
qDebug () << "ADIF:" << ADIF;
std::cout << QByteArray {80, '-'}.data () << '\n';
std::cout << ADIF.data () << std::endl;
}
}
private:
QString id_;
Frequency dial_frequency_;
QString mode_;
};
class Server
: public QObject
{
Q_OBJECT
public:
Server (port_type port, QHostAddress const& multicast_group)
: server_ {new MessageServer {this}}
{
// connect up server
connect (server_, &MessageServer::error, [this] (QString const& message) {
std::cerr << tr ("Network Error: %1").arg ( message).toStdString () << std::endl;
});
connect (server_, &MessageServer::client_opened, this, &Server::add_client);
connect (server_, &MessageServer::client_closed, this, &Server::remove_client);
server_->start (port, multicast_group);
}
private:
void add_client (QString const& id, QString const& version, QString const& revision)
{
auto client = new Client {id};
connect (server_, &MessageServer::status_update, client, &Client::update_status);
connect (server_, &MessageServer::decode, client, &Client::decode_added);
connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added);
connect (server_, &MessageServer::qso_logged, client, &Client::qso_logged);
connect (server_, &MessageServer::logged_ADIF, client, &Client::logged_ADIF);
clients_[id] = client;
server_->replay (id);
std::cout << "Discovered WSJT-X instance: " << id.toStdString ();
if (version.size ())
{
std::cout << " v" << version.toStdString ();
}
if (revision.size ())
{
std::cout << " (" << revision.toStdString () << ")";
}
std::cout << std::endl;
}
void remove_client (QString const& id)
{
auto iter = clients_.find (id);
if (iter != std::end (clients_))
{
clients_.erase (iter);
(*iter)->deleteLater ();
}
std::cout << "Removed WSJT-X instance: " << id.toStdString () << std::endl;
}
MessageServer * server_;
// maps client id to clients
QHash<QString, Client *> clients_;
};
#include "UDPDaemon.moc"
int main (int argc, char * argv[])
{
QCoreApplication app {argc, argv};
try
{
setlocale (LC_NUMERIC, "C"); // ensure number forms are in
// consistent format, do this after
// instantiating QApplication so
// that GUI has correct l18n
app.setApplicationName ("WSJT-X UDP Message Server Daemon");
app.setApplicationVersion ("1.0");
QCommandLineParser parser;
parser.setApplicationDescription ("\nWSJT-X UDP Message Server Daemon.");
auto help_option = parser.addHelpOption ();
auto version_option = parser.addVersionOption ();
QCommandLineOption port_option (QStringList {"p", "port"},
app.translate ("UDPDaemon",
"Where <PORT> is the UDP service port number to listen on.\n"
"The default service port is 2237."),
app.translate ("UDPDaemon", "PORT"),
"2237");
parser.addOption (port_option);
QCommandLineOption multicast_addr_option (QStringList {"g", "multicast-group"},
app.translate ("UDPDaemon",
"Where <GROUP> is the multicast group to join.\n"
"The default is a unicast server listening on all interfaces."),
app.translate ("UDPDaemon", "GROUP"));
parser.addOption (multicast_addr_option);
parser.process (app);
Server server {static_cast<port_type> (parser.value (port_option).toUInt ()), QHostAddress {parser.value (multicast_addr_option)}};
return app.exec ();
}
catch (std::exception const & e)
{
std::cerr << "Error: " << e.what () << '\n';
}
catch (...)
{
std::cerr << "Unexpected error\n";
}
return -1;
}
-5
View File
@@ -1,5 +0,0 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>@message_aggregator_RESOURCES@
</qresource>
</RCC>
-1
View File
@@ -1 +0,0 @@
IDI_ICON1 ICON DISCARDABLE "../icons/windows-icons/ft8call.ico"
-13
View File
@@ -1,13 +0,0 @@
/* default stylesheet for the message aggregator application */
[transmitting="true"] {
background-color: yellow
}
[decoding="true"] {
background-color: cyan
}
[watchdog_timeout="true"] {
background-color: red
}
-1
View File
@@ -1 +0,0 @@
IDI_ICON1 ICON DISCARDABLE "../icons/windows-icons/ft8call.ico"
+2 -2
View File
@@ -1,6 +1,6 @@
# Version number components
set (WSJTX_VERSION_MAJOR 0)
set (WSJTX_VERSION_MINOR 6)
set (WSJTX_VERSION_PATCH 5)
set (WSJTX_VERSION_MINOR 8)
set (WSJTX_VERSION_PATCH 1)
set (WSJTX_RC 0) # release candidate number, comment out or zero for development versions
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build
+3 -1
View File
@@ -14,6 +14,8 @@
#include "Bands.hpp"
#include "FrequencyList.hpp"
#include "WsprTxScheduler.h"
#include "DriftingDateTime.h"
#include "pimpl_impl.hpp"
#include "moc_WSPRBandHopping.cpp"
@@ -333,7 +335,7 @@ void WSPRBandHopping::set_tx_percent (int new_value)
// determine the parameters of the hop, if any
auto WSPRBandHopping::next_hop (bool tx_enabled) -> Hop
{
auto const& now = QDateTime::currentDateTimeUtc ();
auto const& now = DriftingDateTime::currentDateTimeUtc ();
auto const& date = now.date ();
auto year = date.year ();
auto month = date.month ();
+8 -7
View File
@@ -13,27 +13,28 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
{
ui->setupUi(this);
ui->labelTxt->setText ("<h2>" + QString {"FT8Call v"
ui->labelTxt->setText ("<h2>" + QString {"JS8Call v"
+ QCoreApplication::applicationVersion ()
+ " " + revision ()}.simplified () + "</h2><br />"
"FT8Call is a derivative of the WSJT-X application, "
"JS8Call is a derivative of the WSJT-X application, "
"restructured and redesigned for message passing. <br/>"
"It is not supported by nor endorsed by the WSJT-X "
"development group. <br/>FT8Call is "
"development group. <br/>JS8Call is "
"licensed under and in accordance with the terms "
"of the <a href=\"https://www.gnu.org/licenses/gpl-3.0.txt\">GPLv3 license</a>.<br/>"
"The source code modifications are public and can be found in <a href=\"https://bitbucket.org/widefido/wsjtx/\">this repository</a>.<br/><br/>"
"FT8Call is heavily inspired by WSJT-X, Fldigi, "
"JS8Call is heavily inspired by WSJT-X, Fldigi, "
"and FSQCall <br/>and would not exist without the hard work and "
"dedication of the many <br/>developers in the amateur radio "
"community.<br /><br />"
"FT8Call stands on the shoulder of giants...the takeoff angle "
"JS8Call stands on the shoulder of giants...the takeoff angle "
"is better up there.<br /><br />"
"A special thanks goes out to the FT8Call development team:<br/><br/><strong>"
"A special thanks goes out to the JS8Call development team:<br/><br/><strong>"
"KC9QNE, "
"KI6SSI, "
"K0OG, "
"LB9YH, "
"M0IAX, "
"N0JDS, "
@@ -41,7 +42,7 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"VA3OSO, "
"VK1MIC, "
"W0FW,</strong><br/><br/>and the many other amateur radio operators who have given "
"FT8Call a chance.");
"JS8Call a chance.");
}
CAboutDlg::~CAboutDlg()
+1 -1
View File
@@ -14,7 +14,7 @@
</rect>
</property>
<property name="windowTitle">
<string>About FT8Call</string>
<string>About JS8Call</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
-70
View File
@@ -1,70 +0,0 @@
import socket
KKEY = 0x73e2
def do_hash(callsign):
rootCall = callsign.split("-")[0].upper() + '\0'
hash = KKEY
i = 0
length = len(rootCall)
while (i+1 < length):
hash ^= ord(rootCall[i])<<8
hash ^= ord(rootCall[i+1])
i += 2
return int(hash & 0x7fff)
HOST = 'rotate.aprs2.net'
#HOST = 'rotate.aprs.net'
PORT = 14580
print "Connecting..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
print "Connected..."
data = s.recv(1024)
print data
call = 'KN4CRD'
pw = do_hash(call)
ver = "FT8Call"
login = "user {} pass {} ver {}\n".format(call, pw, ver)
s.send(login)
print "Login sent...", login
data = s.recv(1024)
print data
if 0:
message = "KN4CRD>OH8STN,APRS,TCPIP*::EMAIL-2 :KN4CRD@GMAIL.COM TESTING!{04}\n"
s.send(message)
if 0:
message = "{}>APRS,TCPIP*::EMAIL-2 :kn4crd@gmail.com testing456{{01}}\n".format(call)
message = "KN4CRD>APRS,TCPIP*::EMAIL-2 :KN4CRD@GMAIL.COM TESTING!{02}\n"
s.send(message)
if 0:
payload = ":This is a test message"
message = "{}>APRS,TCPIP*::{} {}\n".format(call, call, payload)
s.send(message)
if 1:
position = "=3352.45N/08422.71Wn"
status = "FT8CALL VIA XX9XXX/XXXX 14.082500MHz -20dB"
payload = "".join((position, status))
message = "{}>OH8STN,APRS,TCPIP*:{}\n".format(call, payload)
s.send(message)
print "Spot sent...", message
data = s.recv(1024)
print data
s.close()

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 115 KiB

+16 -16
View File
@@ -25,9 +25,9 @@ convert '/tmp/image-%d.png[0-1]' -background transparent \
\( -clone 1 -resize 128 -compress none \) \
\( -clone 1 -resize 256 -compress Zip \) \
-delete 1 -delete 0 \
-alpha remove ../icons/windows-icons/ft8call.ico
-alpha remove ../icons/windows-icons/js8call.ico
rm /tmp/image-0.png /tmp/image-1.png
identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/windows-icons/ft8call.ico
identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/windows-icons/js8call.ico
#
#inkscape -z -e /dev/stdout -w 150 -h 57 -b white installer_logo.svg | tail -n +4 | \
# convert png:- -resize 150x57 +matte BMP3:../icons/windows-icons/installer_logo.bmp
@@ -37,18 +37,18 @@ identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/windows-icons/instal
#
# Mac
#
mkdir -p ../icons/Darwin/FT8Call.iconset
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_16x16.png -w 16 -h 16 icon_128.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_16x16@2x.png -w 32 -h 32 icon_128.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_32x32.png -w 32 -h 32 icon_128.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_32x32@2x.png -w 64 -h 64 icon_128.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_128x128.png -w 128 -h 128 icon_1024.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_128x128@2x.png -w 256 -h 256 icon_1024.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_256x256.png -w 256 -h 256 icon_1024.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_256x256@2x.png -w 512 -h 512 icon_1024.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_512x512.png -w 512 -h 512 icon_1024.svg
inkscape -z -e ../icons/Darwin/FT8Call.iconset/icon_512x512@2x.png -w 1024 -h 1024 icon_1024.svg
identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/Darwin/FT8Call.iconset/*
mkdir -p ../icons/Darwin/JS8Call.iconset
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_16x16.png -w 16 -h 16 icon_128.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_16x16@2x.png -w 32 -h 32 icon_128.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_32x32.png -w 32 -h 32 icon_128.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_32x32@2x.png -w 64 -h 64 icon_128.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_128x128.png -w 128 -h 128 icon_1024.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_128x128@2x.png -w 256 -h 256 icon_1024.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_256x256.png -w 256 -h 256 icon_1024.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_256x256@2x.png -w 512 -h 512 icon_1024.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_512x512.png -w 512 -h 512 icon_1024.svg
inkscape -z -e ../icons/Darwin/JS8Call.iconset/icon_512x512@2x.png -w 1024 -h 1024 icon_1024.svg
identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/Darwin/JS8Call.iconset/*
# generic globe iconset for utilities
mkdir -p ../icons/Darwin/wsjt.iconset
inkscape -z -e ../icons/Darwin/wsjt.iconset/icon_16x16.png -w 16 -h 16 icon_128.svg
@@ -69,5 +69,5 @@ identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' "../icons/Darwin/DragNDrop Ba
#
# KDE & Gnome
#
inkscape -z -e ../icons/Unix/ft8call_icon.png -w 128 -h 128 icon_1024.svg
identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/Unix/ft8call_icon.png
inkscape -z -e ../icons/Unix/js8call_icon.png -w 128 -h 128 icon_1024.svg
identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/Unix/js8call_icon.png
+26 -16
View File
@@ -22,8 +22,9 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
, is_standard_ {false}
, frameType_(Varicode::FrameUnknown)
, isBeacon_(false)
, isHeartbeat_(false)
, isAlt_(false)
, bits_{0}
{
if(message_.length() >= 1) {
message_ = message_.left (21).remove (QRegularExpression {"[<>]"});
@@ -51,21 +52,24 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
grid_c_string += QByteArray {6 - grid_c_string.size (), ' '};
is_standard_ = stdmsg_ (message_c_string.constData (), contest_mode_, grid_c_string.constData (), 22, 6);
// We're only going to unpack standard messages for CQs && beacons...
// We're only going to unpack standard messages for CQs && pings...
// TODO: jsherer - this is a hack for now...
if(is_standard_){
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
}
}
bits_ = bits();
tryUnpack();
}
DecodedText::DecodedText (QString const& ft8callmessage):
DecodedText::DecodedText (QString const& js8callmessage, int bits):
frameType_(Varicode::FrameUnknown),
message_(ft8callmessage),
isBeacon_(false),
isAlt_(false)
message_(js8callmessage),
isHeartbeat_(false),
isAlt_(false),
bits_(bits)
{
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
@@ -80,7 +84,11 @@ bool DecodedText::tryUnpack(){
bool unpacked = false;
if(!unpacked){
unpacked = tryUnpackBeacon();
unpacked = tryUnpackData();
}
if(!unpacked){
unpacked = tryUnpackHeartbeat();
}
if(!unpacked){
@@ -91,14 +99,10 @@ bool DecodedText::tryUnpack(){
unpacked = tryUnpackDirected();
}
if(!unpacked){
unpacked = tryUnpackData();
}
return unpacked;
}
bool DecodedText::tryUnpackBeacon(){
bool DecodedText::tryUnpackHeartbeat(){
QString m = message().trimmed();
// directed calls will always be 12+ chars and contain no spaces.
@@ -109,17 +113,17 @@ bool DecodedText::tryUnpackBeacon(){
bool isAlt = false;
quint8 type = Varicode::FrameUnknown;
quint8 bits3 = 0;
QStringList parts = Varicode::unpackBeaconMessage(m, &type, &isAlt, &bits3);
QStringList parts = Varicode::unpackHeartbeatMessage(m, &type, &isAlt, &bits3);
if(parts.isEmpty() || parts.length() < 2){
return false;
}
// Beacon Alt Type
// Heartbeat Alt Type
// ---------------
// 1 0 BCN
// 1 1 CQ
isBeacon_ = true;
isHeartbeat_ = true;
isAlt_ = isAlt;
extra_ = parts.length() < 3 ? "" : parts.at(2);
@@ -131,7 +135,7 @@ bool DecodedText::tryUnpackBeacon(){
cmp.append(parts.at(1));
}
compound_ = cmp.join("/");
message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? Varicode::cqString(bits3) : "BEACON").arg(extra_);
message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? Varicode::cqString(bits3) : "HEARTBEAT").arg(extra_);
frameType_ = type;
return true;
}
@@ -197,6 +201,8 @@ bool DecodedText::tryUnpackDirected(){
message_ = QString(parts.join(""));
}
message_ = message_.replace("APRS: ", "APRS:");
directed_ = parts;
frameType_ = type;
return true;
@@ -210,6 +216,10 @@ bool DecodedText::tryUnpackData(){
return false;
}
if((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData){
return false;
}
quint8 type = Varicode::FrameUnknown;
QString data = Varicode::unpackDataMessage(m, &type);
+5 -4
View File
@@ -31,10 +31,10 @@ class DecodedText
{
public:
explicit DecodedText (QString const& message, bool, QString const& my_grid);
explicit DecodedText (QString const& ft8callmessage);
explicit DecodedText (QString const& js8callmessage, int bits);
bool tryUnpack();
bool tryUnpackBeacon();
bool tryUnpackHeartbeat();
bool tryUnpackCompound();
bool tryUnpackDirected();
bool tryUnpackData();
@@ -45,7 +45,7 @@ public:
QString compoundCall() const { return compound_; }
bool isCompound() const { return !compound_.isEmpty(); }
bool isBeacon() const { return isBeacon_; }
bool isHeartbeat() const { return isHeartbeat_; }
bool isAlt() const { return isAlt_; }
QStringList directedMessage() const { return directed_; }
@@ -99,7 +99,7 @@ private:
column_qsoText = 22 };
quint8 frameType_;
bool isBeacon_;
bool isHeartbeat_;
bool isAlt_;
QString compound_;
QString extra_;
@@ -109,6 +109,7 @@ private:
bool contest_mode_;
QString message_;
bool is_standard_;
int bits_;
};
#endif // DECODEDTEXT_H
+6 -4
View File
@@ -8,6 +8,8 @@
#include <QMenu>
#include <QAction>
#include "DriftingDateTime.h"
#include "qt_helpers.hpp"
#include "moc_displaytext.cpp"
@@ -288,13 +290,13 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
t2.sprintf("%4d",txFreq);
QString t;
if(bFastMode or modeTx=="FT8") {
t = QDateTime::currentDateTimeUtc().toString("hhmmss") + \
t = DriftingDateTime::currentDateTimeUtc().toString("hhmmss") + \
" Tx " + t2 + t1 + text;
} else if(modeTx.mid(0,6)=="FT8fox") {
t = QDateTime::currentDateTimeUtc().toString("hhmmss") + \
t = DriftingDateTime::currentDateTimeUtc().toString("hhmmss") + \
" Tx" + modeTx.mid(7) + " " + text;
} else {
t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
t = DriftingDateTime::currentDateTimeUtc().toString("hhmm") + \
" Tx " + t2 + t1 + text;
}
appendText (t, color_ReceivedMsg);
@@ -302,7 +304,7 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
void DisplayText::displayQSY(QString text)
{
QString t = QDateTime::currentDateTimeUtc().toString("hhmmss") + " " + text;
QString t = DriftingDateTime::currentDateTimeUtc().toString("hhmmss") + " " + text;
appendText (t, "hotpink");
}
-243
View File
@@ -1,243 +0,0 @@
set (LANGUAGES
en
)
set (common_SRCS
common/communication.adoc
common/license.adoc
common/links.adoc
)
set (UG_SRCS
docinfo.html
docinfo.xml
acknowledgements.adoc
astro_data.adoc
config-details.adoc
controls-functions-center.adoc
controls-functions-left.adoc
controls-functions-main-window.adoc
controls-functions-menus.adoc
controls-functions-messages.adoc
controls-functions-status-bar.adoc
controls-functions-wide-graph.adoc
cooperating-programs.adoc
decoder_notes.adoc
faq.adoc
font-sizes.adoc
install-from-source.adoc
install-linux.adoc
install-mac.adoc
install-windows.adoc
introduction.adoc
measurement_tools.adoc
protocols.adoc
logging.adoc
make-qso.adoc
measurement_tools.adoc
new_features.adoc
platform-dependencies.adoc
protocols.adoc
settings-advanced.adoc
settings-audio.adoc
settings-colors.adoc
settings-frequencies.adoc
settings-general.adoc
settings-radio.adoc
settings-reporting.adoc
settings-txmacros.adoc
support.adoc
system-requirements.adoc
transceiver-setup.adoc
tutorial-example1.adoc
tutorial-example2.adoc
tutorial-example3.adoc
tutorial-main-window.adoc
tutorial-wide-graph-settings.adoc
utilities.adoc
vhf-features.adoc
wsjtx-main.adoc
wspr.adoc
)
set (UG_IMGS
images/130610_2343-wav-80.png
images/170709_135615.wav.png
images/AstroData_2.png
images/Astronomical_data.png
images/auto-seq.png
images/band-settings.png
images/colors.png
images/config-menu.png
images/decode-menu.png
images/decodes.png
images/download_samples.png
images/echo_144.png
images/file-menu.png
images/FreqCal.png
images/FreqCal_Graph.png
images/FreqCal_Results.png
images/freemsg.png
images/ft8_decodes.png
images/help-menu.png
images/JT4F.png
images/JT65B.png
images/keyboard-shortcuts.png
images/MSK144.png
images/QRA64.png
images/WSPR_WideGraphControls.png
images/WSPR_1a.png
images/WSPR_2.png
images/jtalert.png
images/keyboard-shortcuts.png
images/log-qso.png
images/MacAppMenu.png
images/main-ui.png
images/main-ui-controls.png
images/misc-controls-center.png
images/misc-main-ui.png
images/mode-menu.png
images/new-msg-box.png
images/psk-reporter.png
images/r3666-config-screen-80.png
images/r3666-main-ui-80.png
images/r4148-txmac-ui.png
images/RadioTab.png
images/reporting.png
images/save-menu.png
images/settings-advanced.png
images/settings-audio.png
images/settings-frequencies.png
images/settings-general.png
images/setup-menu.png
images/special-mouse-commands.png
images/status-bar-a.png
images/tools-menu.png
images/traditional-msg-box.png
images/tx-macros.png
images/VHF_controls.png
images/view-menu.png
images/wide-graph-controls.png
)
find_program (ASCIIDOCTOR_EXECUTABLE NAMES asciidoctor)
if (NOT ASCIIDOCTOR_EXECUTABLE)
message (FATAL_ERROR "asciidoctor is required to build the documentation
Building the documenation may optionally be turned off by setting the CMake
option WSJT_GENERATE_DOCS to OFF.")
endif (NOT ASCIIDOCTOR_EXECUTABLE)
find_program (FOPUB_EXECUTABLE NAMES fopub)
include (CMakeParseArguments)
# generate a document from asciidoc text files(s)
#
# HTML - generate an HTML document
# PDF - generate a PDF document
# SOURCE - top level asciidoc file
# ASCIIDOCTOR_OPTIONS - asciidoctor command options
# DEPENDS - dependent files
function (document)
cmake_parse_arguments (_args "HTML" "SOURCE;LANG;OUTPUT" "ASCIIDOCTOR_OPTIONS;PDF;DEPENDS" ${ARGN})
get_filename_component (_source_path ${_args_SOURCE} PATH)
get_filename_component (_source_name ${_args_SOURCE} NAME)
get_filename_component (_output_name_we ${_args_SOURCE} NAME_WE)
# HTML
if (${_args_HTML})
set (_html_file ${CMAKE_CURRENT_BINARY_DIR}/${_output_name_we}_${lang}.html)
add_custom_command (
OUTPUT ${_html_file}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_source_path}/${lang}
COMMAND ${ASCIIDOCTOR_EXECUTABLE} ${_args_ASCIIDOCTOR_OPTIONS}
-b html5
-a VERSION_MAJOR=${WSJTX_VERSION_MAJOR}
-a VERSION_MINOR=${WSJTX_VERSION_MINOR}
-a VERSION_PATCH=${WSJTX_VERSION_PATCH}
-a VERSION=${wsjtx_VERSION}
--out-file=${_html_file} ${_source_name}
DEPENDS ${_args_DEPENDS}
COMMENT "Generating ${_html_file}"
)
list (APPEND _output_files ${_html_file})
endif (${_args_HTML})
# PDF
if (_args_PDF AND EXISTS ${FOPUB_EXECUTABLE})
set (_docbook_file ${CMAKE_CURRENT_BINARY_DIR}/${_output_name_we}_${lang}.xml)
set (_pdf_file_we ${CMAKE_CURRENT_BINARY_DIR}/${_output_name_we}_${lang})
if (${lang} MATCHES "^(en|es|fr)$") # en-us, fr-ca and es-{mx,co} use US-Letter or equivalent
set (_usl_commands
COMMAND ${FOPUB_EXECUTABLE} ARGS ${_docbook_file} ${_args_PDF} -param paper.type USLetter
COMMAND ${CMAKE_COMMAND} ARGS -E rename ${_pdf_file_we}.pdf '${_pdf_file_we} \(USLetter\).pdf'
)
list (APPEND _output_files "${_pdf_file_we} (USLetter).pdf")
endif ()
list (APPEND _output_files "${_pdf_file_we}.pdf")
add_custom_command (
OUTPUT ${_docbook_file} ${_output_files}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_source_path}/${lang}
COMMAND ${ASCIIDOCTOR_EXECUTABLE} ARGS ${_args_ASCIIDOCTOR_OPTIONS}
-b docbook
-a data-uri!
-a VERSION_MAJOR=${WSJTX_VERSION_MAJOR}
-a VERSION_MINOR=${WSJTX_VERSION_MINOR}
-a VERSION_PATCH=${WSJTX_VERSION_PATCH}
-a VERSION=${wsjtx_VERSION}
-D ${CMAKE_CURRENT_BINARY_DIR}
-o ${_docbook_file} ${_source_name}
${_usl_commands}
COMMAND ${FOPUB_EXECUTABLE} ARGS ${_docbook_file} ${_args_PDF} -param paper.type A4
COMMAND ${CMAKE_COMMAND} ARGS -E rename ${_pdf_file_we}.pdf '${_pdf_file_we}.pdf'
DEPENDS ${_args_DEPENDS}
COMMENT "Generating ${_output_files}"
)
endif (_args_PDF AND EXISTS ${FOPUB_EXECUTABLE})
set (${_args_OUTPUT} ${_output_files} PARENT_SCOPE)
endfunction (document)
set (htmls)
set (pdfs)
foreach (lang ${LANGUAGES})
set (_sources)
foreach (_src ${UG_SRCS} ${UG_IMGS})
list (APPEND _sources "user_guide/${lang}/${_src}")
endforeach ()
document(
HTML
SOURCE user_guide/wsjtx-main.adoc
LANG "${lang}"
OUTPUT html
ASCIIDOCTOR_OPTIONS -d book -a data-uri -a toc=left -a max-width=1024px
DEPENDS ${common_SRCS} ${_sources}
)
document(
PDF -param body.font.master 11 -param body.font.family "'Noto Sans, Helvetica, sans-serif'" -param title.font.family "'Noto Serif, Times New Roman, serif'" -param page.margin.inner 1cm -param page.margin.outer 1cm -param page.margin.top 0.75cm -param page.margin.bottom 0.5cm -param generate.toc 0
SOURCE user_guide/wsjtx-main.adoc
LANG "${lang}"
OUTPUT pdf
ASCIIDOCTOR_OPTIONS -d book
DEPENDS ${common_SRCS} ${_sources}
)
list (APPEND htmls "${html}")
list (APPEND pdfs "${pdf}")
endforeach ()
add_custom_target (docs ALL DEPENDS ${htmls} ${pdfs})
foreach (_html ${htmls})
get_filename_component (_path ${_html} PATH)
get_filename_component (_nwe ${_html} NAME_WE)
get_filename_component (_ext ${_html} EXT)
string (REGEX REPLACE "_en$" "" _nwe ${_nwe})
install (FILES
${_html}
DESTINATION ${CMAKE_INSTALL_DOCDIR}
RENAME ${_nwe}-${wsjtx_VERSION}${_ext}
#COMPONENT runtime
)
endforeach ()
-40
View File
@@ -1,40 +0,0 @@
This folder contains the sources of WSJT-X documentation. To build
these you will need the asciidoctor tool installed.
If you do not wish to build the documentation, it is possible to skip
this directory in the WSJT-X build by setting the CMake option
WSJT_GENERATE_DOCS to OFF in your build tree.
On Linux
========
You will probably have these installed already if you are building the
WSJT-X manpages, if you are not you will just need to install
asciidoc:
sudo apt-get install asciidoctor
or
sudo yum install asciidoctor
or whatever your distribution and package management requires.
On Mac OS X
===========
I recommend MacPorts:
sudo port install rb-rubygems
sudo gem install asciidoctor
On Windows
==========
The asciidoctor tool is a Ruby script so you will need to install a
version of Ruby. The gem tool is a good way to install asciidoctor:
gem install asciidoctor
-17
View File
@@ -1,17 +0,0 @@
The following are established communication channels for the WSJT Group.
For updates and other information on the continuing development of _WSJT_,
_MAP65_, _WSPR_, _WSPR-X_, and _WSJT-X_ you are invited to subscribe to the
{dev_mail_list}.
.General Information
* Main Site: {homepage}
* Development Site: {projsummary}
.Development Related
* Project Manager, email: {joe_taylor}
* Development Email: {devmail1}
* Development Mailing List (join): {dev_mail_list}
* Repository Updates, (join): {dev_mail_svn}
.Community Related
* Discussion Board: {wsjt_yahoo_group}
-29
View File
@@ -1,29 +0,0 @@
include::./links.adoc[]
_{prog}_ is free software: you may redistribute 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.
_{prog}_ 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 documentation. If not, see {gnu_gpl}.
Except where otherwise noted, all algorithms, protocol designs, source
code, and supporting files contained in the _{prog}_ package are the
intellectual property of the program's authors. The authors assert
*Copyright ownership* of this material, whether or not such copyright
notice appears in each individual file. Others who make fair use of
our work under terms of the GNU General Public License must display
the following copyright notice prominently:
*The algorithms, source code, look-and-feel of _{prog}_ and related
programs, and protocol specifications for the modes FSK441, FT8, JT4,
JT6M, JT9, JT65, JTMS, QRA64, ISCAT, and MSK144 are Copyright (C)
2001-2018 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.*
-128
View File
@@ -1,128 +0,0 @@
////
Link file to hold all links
File Location: ./doc/common/links.adoc
Usage example: include::../common/links.adoc[]
Syntax: [link-id] [link] [displayed text]
Example:
:pskreporter: http://pskreporter.info/pskmap.html[PSK Reporter]
[link-id] = :pskreporter:
[link] http://pskreporter.info/pskmap.html
[displayed text] PSK Reporter
Perform searches from the doc root directory: doc
Search: grep -rl --exclude-dir="*\.svn" {pskreporter} .
grep -rl --exclude-dir="*\.svn" PSK Reporter .
grep -rl --exclude-dir="*\.svn" {devsvn} .
grep -rl --exclude-dir="*\.svn" {kvasd} .
grep -rl --exclude-dir="*\.svn" {ntpsetup} .
Include links.adoc: grep -rl --exclude-dir="*\.svn" pskreporter .
Exclude links.adoc: grep -rl --exclude-dir="*\.svn" {pskreporter} .
Note(s):
a). Don't forget a space then "." at the end.
b). To include links.adoc file itself, remove the brackets {} from
the pattern search:
c). Look at each of the files listed to ensure the [displayed text]
still makes sense in the caption. If not, just add another link. Be
aware of the translators requirements by trying to keep the displayed
text language agnostic or neutral e.g. use a proper noun like a
persons name or a document title in the language of the linked
document. Do not use plain English generic words for link text link
"here".
d). Edit lines as needed. Keeping them in alphabetic order help see dupes.
////
// General URL's
//:launchpadac6sl: https://launchpad.net/~jnogatch/+archive/wsjtx[WSJT-X Linux Packages]
:alarmejt: http://f5jmh.free.fr/index.php?page=english[AlarmeJT]
:asciidoc_cheatsheet: http://powerman.name/doc/asciidoc[AsciiDoc Cheatsheet]
:asciidoc_help: http://www.methods.co.nz/asciidoc/userguide.html[AsciiDoc User Guide]
:asciidoc_questions: http://www.methods.co.nz/asciidoc/faq.html[AsciiDoc FAQ]
:asciidoc_syntax: http://xpt.sourceforge.net/techdocs/nix/tool/asciidoc-syn/ascs01-AsciiDocMarkupSyntaxQuickSummary/single/[AsciiDoc Syntax]
:asciidoctor_style: http://asciidoctor.org/docs/asciidoc-writers-guide/#delimited-blocks[AsciiDoctor Styles Guide]
:asciidoctor_syntax: http://asciidoctor.org/docs/asciidoc-writers-guide/#delimited-blocks[AsciiDoctor Syntax Guide]
:cc_by_sa: http://creativecommons.org/licenses/by-sa/3.0/[Commons Attribution-ShareAlike 3.0 Unported License]
:debian32: http://physics.princeton.edu/pulsar/K1JT/wsjtx_{VERSION}_i386.deb[wsjtx_{VERSION}_i386.deb]
:debian64: http://physics.princeton.edu/pulsar/K1JT/wsjtx_{VERSION}_amd64.deb[wsjtx_{VERSION}_amd64.deb]
:raspbian: http://physics.princeton.edu/pulsar/K1JT/wsjtx_{VERSION}_armhf.deb[wsjtx_{VERSION}_armhf.deb]
:debian: http://www.debian.org/[Debian]
:dev_guide: http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/wsjt-dev-guide.html[Dev-Guide]
:devsvn1: http://sourceforge.net/p/wsjt/wsjt/HEAD/tree/[Devel-SVN]
:devsvn: http://sourceforge.net/p/wsjt/wsjt/HEAD/tree/[SourceForge]
:dimension4: http://www.thinkman.com/dimension4/[Thinking Man Software]
:download: http://physics.princeton.edu/pulsar/K1JT/wsjtx.html[Download Page]
:dxatlas: http://www.dxatlas.com/[Afreet Software, Inc.]
:dxlcommander: http://www.dxlabsuite.com/commander/[Commander]
:dxlsuite: http://www.dxlabsuite.com/[DX Lab Suite]
:fedora32: http://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-i686.rpm[wsjtx-{VERSION}-i686.rpm]
:fedora64: http://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-x86_64.rpm[wsjtx-{VERSION}-x86_64.rpm]
:fmt_arrl: http://www.arrl.org/frequency-measuring-test[ARRL FMT Info]
:fmt_group: https://groups.yahoo.com/neo/groups/FMT-nuts/info[FMT Group]
:fmt_k5cm: http://www.k5cm.com/[FMT Event Info]
:fmt_wspr: http://www.physics.princeton.edu/pulsar/K1JT/FMT_User.pdf[Accurate Frequency Measurements with your WSPR Setup]
:ft8_tips: http://www.physics.princeton.edu/pulsar/K1JT/FT8_Operating_Tips.pdf[here]
:ft8_DXped: http://physics.princeton.edu/pulsar/k1jt/FT8_DXpedition_Mode.pdf[FT8 DXpedition Mode]
:gnu_gpl: http://www.gnu.org/licenses/gpl-3.0.txt[GNU General Public License]
:homepage: http://physics.princeton.edu/pulsar/K1JT/[WSJT Home Page]
:hrd: http://www.hrdsoftwarellc.com/[Ham Radio Deluxe]
:jt4eme: http://physics.princeton.edu/pulsar/K1JT/WSJT-X_1.6.0_for_JT4_v7.pdf[Using WSJT-X for JT4 EME Operation]
:jt65protocol: http://physics.princeton.edu/pulsar/K1JT/JT65.pdf[QEX]
:jtalert: http://hamapps.com/[JT-Alert]
:launchpadki7mt: https://launchpad.net/~ki7mt[KI7MT PPA's]
:log4om: http://www.log4om.com[Log4OM]
:lunarEchoes: http://physics.princeton.edu/pulsar/K1JT/LunarEchoes_QEX.pdf[QEX]
:msk144: http://physics.princeton.edu/pulsar/k1jt/MSK144_Protocol_QEX.pdf[QEX]
:msys_url: http://sourceforge.net/projects/mingwbuilds/files/external-binary-packages/[MSYS Download]
:ntpsetup: http://www.satsignal.eu/ntp/setup.html[Network Time Protocol Setup]
:osx_instructions: http://physics.princeton.edu/pulsar/K1JT/OSX_Readme[Mac OS X Install Instructions]
:ppa: http://en.wikipedia.org/wiki/Personal_Package_Archive[PPA]
:projsummary: http://sourceforge.net/projects/wsjt/[Project Summary]
:pskreporter: http://pskreporter.info/pskmap.html[PSK Reporter]
:sourceforge: https://sourceforge.net/user/registration[SourceForge]
:sourceforge-jtsdk: https://sourceforge.net/projects/jtsdk[SourceForge JTSDK]
:ubuntu_sdk: https://launchpad.net/~ubuntu-sdk-team/+archive/ppa[Ubuntu SDK Notice]
:wsjt_yahoo_group: https://groups.yahoo.com/neo/groups/wsjtgroup/info[WSJT Group]
:wsjtx: http://physics.princeton.edu/pulsar/K1JT/wsjtx.html[WSJT-X]
:wspr0_guide: http://www.physics.princeton.edu/pulsar/K1JT/WSPR0_Instructions.TXT[WSPR0 Guide]
:wspr: http://physics.princeton.edu/pulsar/K1JT/wspr.html[WSPR Home Page]
:wsprnet: http://wsprnet.org/drupal/[WSPRnet]
:wsprnet_activity: http://wsprnet.org/drupal/wsprnet/activity[WSPRnet Activity page]
// Download Links
:cty_dat: http://www.country-files.com/cty/[Amateur Radio Country Files]
:jtbridge: http://jt-bridge.eller.nu/[JT-Bridge]
:jtsdk_doc: http://physics.princeton.edu/pulsar/K1JT/JTSDK-DOC.exe[Download]
:jtsdk_installer: http://sourceforge.net/projects/jtsdk/files/win32/2.0.0/JTSDK-2.0.0-B2-Win32.exe/download[Download]
:jtsdk_omnirig: http://sourceforge.net/projects/jtsdk/files/win32/2.0.0/base/contrib/OmniRig.zip/download[Download]
:jtsdk_py: http://physics.princeton.edu/pulsar/K1JT/JTSDK-PY.exe[Download]
:jtsdk_qt: http://physics.princeton.edu/pulsar/K1JT/JTSDK-QT.exe[Download]
:jtsdk_vcredist: http://sourceforge.net/projects/jtsdk/files/win32/2.0.0/base/contrib/vcredist_x86.exe/download[Download]
:nh6z: http://www.nh6z.net/Amatuer_Radio_Station_NH6Z/Other_Peoples_Software.html[here]
:omnirig: http://www.dxatlas.com/OmniRig/Files/OmniRig.zip[Omni-Rig]
:osx: http://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-Darwin.dmg[wsjtx-{VERSION}-Darwin.dmg]
:QRA64_EME: http://physics.princeton.edu/pulsar/K1JT/QRA64_EME.pdf[QRA64 for microwave EME]
:svn: http://subversion.apache.org/packages.html#windows[Subversion]
:win32: http://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-win32.exe[wsjtx-{VERSION}-win32.exe]
:wsjt-devel: https://lists.sourceforge.net/lists/listinfo/wsjt-devel[here]
:wsjt_svn: http://sourceforge.net/p/wsjt/wsjt/HEAD/tree/[WSJT Source Repository]
:wspr_code: http://physics.princeton.edu/pulsar/K1JT/WSPRcode.exe[WSPRcode.exe]
:wspr_svn: http://sourceforge.net/p/wsjt/wsjt/HEAD/tree/branches/wspr/[WSPR Source Repository]
// MAIL-TO links
:alex_efros: mailto:powerman@powerman.name[Alex Efros]
:bill_somerville: mailto:g4wjs -at- c l a s s d e s i g n -dot- com [G4WJS]
:dev_mail_list: http://sourceforge.net/mailarchive/forum.php?forum_name=wsjt-devel[WSJT Developers Email List]
:dev_mail_svn: https://sourceforge.net/auth/subscriptions/[WSJT SVN Archives]
:devmail: mailto:wsjt-devel@lists.sourceforge.net[wsjt-devel@lists.sourceforge.net]
:devmail1: mailto:wsjt-devel@lists.sourceforge.net[Post Message]
:wsjtgroup_mail: mailto:wsjtgroup@yahoogroups.com[Post Message]
:greg_beam: mailto:ki7mt@yahoo.com[KI7MT]
:joe_taylor: mailto:joe@princeton.edu[K1JT]
:stuart_rackman: mailto:srackham@gmail.com[Stuart Rackham]
-29
View File
@@ -1,29 +0,0 @@
// Status=review
The _WSJT_ project was started in 2001. Since 2005 it has been an
Open Source project, and it now includes programs _WSJT_, _MAP65_,
_WSPR_, _WSJT-X_, and _WSPR-X_. All code is licensed under the
GNU Public License (GPL). Many users of these programs, too numerous
to mention here individually, have contributed suggestions and advice
that have greatly aided the development of _WSJT_ and its sister
programs.
For _WSJT-X_ in particular, we acknowledge contributions from *AC6SL,
AE4JY, DJ0OT, G3WDG, G4KLA, G4WJS, IV3NWV, IW3RAB, K3WYC, K9AN,
KA6MAL, KA9Q, KB1ZMX, KD6EKQ, KI7MT, KK1D, ND0B, PY2SDR, VE1SKY, VK3ACF,
VK4BDJ, VK7MO, W4TI, W4TV, and W9MDB*. Each of these amateurs has helped to
bring the programs design, code, testing, and/or documentation to
its present state.
Most of the color palettes for the _WSJT-X_ waterfall were copied from
the excellent, well documented, open-source program _fldigi_, by *W1HKJ*
and friends.
We use development tools and libraries from many sources. We
particularly wish to acknowledge importance of the GNU Compiler
Collection from the Free Software Foundation, the "clang" compiler
from LLVM at the University of Illinois, and the Qt Project from Digia
PLC. Other important resources include the FFTW library by Matteo
Frigo and Steven G. Johnson; SLALIB, the Positional Astronomy Library
by P. T. Wallace; and a high-precision planetary ephemeris and
associated software from NASA's Jet Propulsion Laboratory.
-57
View File
@@ -1,57 +0,0 @@
A text box entitled Astronomical Data provides information needed for
tracking the sun or moon, compensating for EME Doppler shift, and
estimating EME Doppler spread and path degradation. Toggle the
*Astronomical data* on the *View* menu to display or hide this window.
image::AstroData_2.png[align="center",alt="Astronomical Data"]
Available information includes the current UTC *Date* and time; *Az*
and *El*, azimuth and elevation of the moon at your own location, in
degrees; *SelfDop*, *Width*, and *Delay*, the Doppler shift, full
limb-to-limb Doppler spread in Hz, and delay of your own EME echoes in
seconds; and *DxAz* and *DxEl*, *DxDop*, and *DxWid*, corresponding
parameters for a station located at the *DX Grid* entered on the main
window. These numbers are followed by *Dec*, the declination of the
moon; *SunAz* and *SunEl*, the azimuth and elevation of the Sun;
*Freq*, your stated operating frequency in MHz; *Tsky*, the estimated
sky background temperature in the direction of the moon, scaled to the
operating frequency; *Dpol*, the spatial polarization offset in
degrees; *MNR*, the maximum non-reciprocity of the EME path in dB,
owing to a combination of Faraday rotation and spatial polarization;
and finally *Dgrd*, an estimate of the signal degradation in dB,
relative to the best possible time with the moon at perigee in a cold
part of the sky.
On the higher microwave bands, where Faraday rotation is minimal and
linear polarization is often used, spatial offset will reduce signal
levels. Some stations have implemented mechanical polarisation
adjustment to overcome this loss, and the amount of rotation needed is
predicted in real time by the value of *Dpol*. Positive Dpol means
that the antenna should be rotated in a clockwise direction looking
from behind the antenna towards the moon. For a dish antenna, the
feed should similarly be rotated clockwise looking into the mouth of
the feed. A negative value for Dpol means anticlockwise rotation.
The state of the art for establishing three-dimensional locations of
the sun, moon, and planets at a specified time is embodied in a
numerical model of the solar system maintained at the Jet Propulsion
Laboratory. The model has been numerically integrated to produce
tabular data that can be interpolated with very high accuracy. For
example, the celestial coordinates of the moon or a planet can be
determined at a specified time to within about 0.0000003 degrees. The
JPL ephemeris tables and interpolation routines have been incorporated
into _WSJT-X_. Further details on accuracy, especially concerning
calculated EME Doppler shifts, are described in {lunarEchoes} for
November-December, 2016.
The sky background temperatures reported by _WSJT-X_ are derived from
the all-sky 408 MHz map of Haslam et al. (Astronomy and Astrophysics
Supplement Series, 47, 1, 1982), scaled by frequency to the -2.6
power. This map has angular resolution of about 1 degree, and of
course most amateur EME antennas have much broader beamwidths than
this. Your antenna will therefore smooth out the hot spots
considerably, and the observed extremes of sky temperature will be
less. Unless you understand your sidelobes and ground reflections
extremely well, it is unlikely that more accurate sky temperatures
would be of much practical use.
-4
View File
@@ -1,4 +0,0 @@
// Status=review
[[CONFIG_DETAILS]]
Are we here?
@@ -1,80 +0,0 @@
// Status=review
At the center of the main window are a number of controls used when
making QSOs. Controls not relevant to a particular mode or submode
may be "grayed out" (disabled) or removed from the display.
//.Misc Controls Center
image::misc-controls-center.png[align="center",alt="Misc Controls Center"]
* Check *Tx even* to transmit in even-numbered UTC minutes or
sequences, starting at 0. Uncheck this box to transmit in the odd
sequences. The correct selection is made automatically when you
double-click on a decoded text line, as described in the
<<TUTORIAL,Basic Operating Tutorial>>.
* The Tx and Rx audio frequencies can be set automatically by
double-clicking on decoded text or a signal in the waterfall. They
can also be adjusted using the spinner controls.
* You can force Tx frequency to the current Rx frequency by clicking
the *Tx<-Rx* button, and vice-versa for *Rx<-Tx*. The on-the-air
frequency of your lowest JT9 or JT65 tone is the sum of dial frequency
and audio Tx frequency.
* Check the box *Lock Tx=Rx* to make the frequencies always track one
another.
IMPORTANT: In general we do not recommend using *Lock Tx=Rx* since it
encourages poor radio etiquette when running a frequency. With this
box checked, your own Tx frequency will move around following your
callers.
* For modes lacking a multi-decode feature, or when *Enable
VHF/UHF/Microwave features* has been checked on the *Settings ->
General* tab, the *F Tol* control sets a frequency toilerance range
over which decoding will be attempted, centered on the Rx frequency.
* The *Report* control lets you change a signal report that has been
inserted automatically. Typical reports for the various modes fall in
the range 30 to +20 dB. Remember that JT65 reports saturate at an
upper limit of -1 dB.
TIP: Consider reducing power if your QSO partner reports your
signal above -5 dB in one of the _WSJT-X_ slow modes. These are
supposed to be weak signal modes!
* In some circumstances, especially on VHF and higher bands, you can
select a supported submode of the active mode by using the *Submode*
control. The *Sync* control sets a minimum threshold for establishing
time and frequency synchronization with a received signal.
* Spinner control *T/R xx s* sets sequence lengths for transmission
and reception in ISCAT, MSK144, and the fast JT9 modes.
* With *Split operation* activated on the *Settings -> Radio* tab, in
MSK144 and the fast JT9 submodes you can activate the spinner control
*Tx CQ nnn* by checking the box to its right. The program will then
generate something like `CQ nnn K1ABC FN42` for your CQ message, where
`nnn` is the kHz portion of your current operating frequency,
in the range 010 to 999. Your CQ
message *Tx6* will then be transmitted at the calling frequency
selected in the *Tx CQ nnn* spinner control. All other messages will
be transmitted at your current operating frequency. On reception,
when you double-click on a message like `CQ nnn K1ABC FN42` your rig
will QSY to the specified frequency so you can call the station at his
specified response frequency.
* Checkboxes at bottom center of the main window control special
features for particular operating modes:
** *Sh* enables shorthand messages in JT4, JT65, QRA64 and MSK144 modes
** *Fast* enables fast JT9 submodes
** *Auto Seq* enables auto-sequencing of Tx messages
** *Call 1st* enables automatic response to the first decoded
responder to your CQ
** *Tx6* toggles between two types of shorthand messages in JT4 mode
@@ -1,45 +0,0 @@
// Status=review
Controls related to frequency selection, received audio level, the
station being called, and date and time are found at lower left of the
main window:
//.Misc Controls Left
image::misc-main-ui.png[align="center",alt="Misc Menu Items"]
* A drop-down list of frequencies and bands at upper left lets you
select the operating band and sets dial frequency to a value taken
from the *Frequencies* tab on the *Settings* window. If CAT control
is active the radio's dial frequency will be set accordingly; if not,
you must tune the radio manually.
* Alternatively, you can enter a frequency (in MHz) or band name in
recognized ADIF format, for example 630m, 20m, or 70cm. The band-name
format works only if a working frequency has been set for that band
and mode, in which case the first such match is selected.
* You can also enter a frequency increment in kHz above the currently
displayed integer MHz. For example, if the displayed frequency is
10,368.100, enter `165k` (don't forget the `k`!) to QSY to 10,368.165.
* A small colored circle appears in green if the CAT control is
activated and functional. The green circle contains the character S
if the rig is detected to be in *Split* mode. The circle becomes red
if you have requested CAT control but communication with the radio has
been lost.
TIP: Many Icom rigs cannot be queried for split status, current VFO or
split transmit frequency. When using _WSJT-X_ with such radios you
should not change the current VFO, split status or dial frequency
using controls on the radio.
* If *DX Grid* contains a valid Maidenhead locator, the corresponding
great-circle azimuth and distance from your location are displayed.
* The program can maintain a database of callsigns and locators for
future reference. Click *Add* to insert the present call and locator
in the database; click *Lookup* to retrieve the locator for a
previously stored call. This feature is mainly useful for situations
in which the number of active stations is modest and reasonably
stable, such as EME (Earth-Moon-Earth) communication. The callsign
file name is `CALL3.TXT`.
@@ -1,69 +0,0 @@
// Status=review
The following controls appear just under the decoded text windows on
the main screen:
//.Main UI
image::main-ui-controls.png[align="center",width=650,alt="Main UI Controls"]
* When *CQ only* is checked, only messages from stations calling CQ will
be displayed in the left text panel.
* *Log QSO* raises a dialog window pre-filled with known information
about a QSO you have nearly completed. You can edit or add to this
information before clicking *OK* to log the QSO. If you check *Prompt
me to log QSO* on the *Settings -> Reporting* tab, the program will
raise the confirmation screen automatically when you send a message
containing +73+. *Start Date* and *Start Time* are set when you click
to send the *Tx 2* or *Tx 3* message, and backed up by one or two
sequence lengths, respectively. (Note that the actual start time may
have been earlier if repeats of early transmissions were required.)
End date and time are set when the *Log QSO* screen is invoked.
//.Log QSO Window
image::log-qso.png[align="center",alt="Log QSO"]
* *Stop* will terminate normal data acquisition in case you want to
freeze the waterfall or open and explore a previously recorded audio
file.
* *Monitor* toggles normal receive operation on or off. This button
is highlighted in green when the _WSJT-X_ is receiving. If you are
using CAT control, toggling *Monitor* OFF relinquishes control of the
rig; if *Monitor returns to last used frequency* is selected on the
*Settings | General* tab, toggling *Monitor* back ON will return to
the original frequency.
* *Erase* clears the right-hand decoded text window.
Double-clicking *Erase* clears both text windows.
TIP: Right-clicking on either text window brings up a context menu
with several options (including *Erase*) which operate on that window
alone.
* *Clear Avg* is present only in modes that support message averaging.
It provides a way to erase the accumulating information, thus
preparing to start a new average.
* *Decode* tells the program to repeat the decoding procedure at the
Rx frequency (green marker on waterfall scale), using the most recently
completed sequence of received data.
* *Enable Tx* toggles automatic T/R sequencing mode on or off and
highlights the button in red when ON. A transmission will start at
the beginning of the selected (odd or even) sequence, or immediately
if appropriate. Toggling the button to OFF during a transmission
allows the current transmission to finish.
* *Halt Tx* terminates a transmission immediately and disables
automatic T/R sequencing.
* *Tune* toggles the program into Tx mode and generates an unmodulated
carrier at the specified Tx frequency (red marker on waterfall scale).
This process is useful for adjusting an antenna tuner or tuning an
amplifier. The button is highlighted in red while *Tune* is active.
Toggle the button a second time or click *Halt Tx* to terminate the
*Tune* process. Note that activating *Tune* interrupts a receive
sequence and will prevent decoding during that sequence.
* Uncheck the box *Menus* to make the top-of-window menus disappear,
leaving more vertical space for decoded messages.
@@ -1,66 +0,0 @@
// Status=review
Menus at top of the main window offer many options for configuration
and operation. Most of the items are self-explanatory; a few
additional details are provided below. Keyboard shortcuts for some
frequently used menu items are listed at the right edge of the menu.
==== _WSJT-X_ menu
image::MacAppMenu.png[align="left",alt="Mac App Menu"]
This menu appears on the Macintosh only. *Settings* appears here,
labeled as *Preferences*, rather than on the *File* menu. *About
WSJT-X* appears here rather than on the *Help* menu.
[[FILE_MENU]]
==== File menu
image::file-menu.png[align="left",alt="File Menu"]
[[CONFIG_MENU]]
==== Configuration Menu
image::config-menu.png[align="left",alt="File Menu"]
Many users prefer to create and use entries on the *Configurations*
menu for switching between modes. Simply *Clone* the *Default* entry,
*Rename* it as desired, and then make all desired settings for that
configuration. These settings will be restored whenever you select
that configuration.
As well as switching between configurations while running _WSJT-X_ you
can also start the application from the command line in any desired
configuration. Use the command-line option
`--config <configuration-name>`, or `-c` for short, as in these
examples for configurations `FT8` and `Echo`:
wsjtx --config FT8
wsjtx -c Echo
[[VIEW_MENU]]
==== View Menu
image::view-menu.png[align="left",alt="View Menu"]
[[MODE_MENU]]
==== Mode Menu
image::mode-menu.png[align="left",alt="Mode Menu"]
[[DECODE_MENU]]
==== Decode Menu
image::decode-menu.png[align="left",alt="Decode Menu"]
[[SAVE_MENU]]
[[SAVE-WAV]]
==== Save Menu
image::save-menu.png[align="left",alt="Save Menu"]
==== Tools Menu
image::tools-menu.png[align="left",alt="Tools Menu"]
[[HELP_MENU]]
==== Help Menu
image::help-menu.png[align="left",alt="Help Menu"]
===== Keyboard Shortcuts (F3)
image::keyboard-shortcuts.png[align="left",alt="Keyboard Shortcuts"]
===== Special Mouse Commands (F5)
image::special-mouse-commands.png[align="left",alt="Special Mouse Commands"]
@@ -1,61 +0,0 @@
// Status=review
Two arrangements of controls are provided for generating and selecting
Tx messages. Controls familiar to users of program _WSJT_
appear on *Tab 1*, providing six fields for message entry.
Pre-formatted messages for the standard minimal QSO are generated when
you click *Generate Std Msgs* or double-click on an appropriate line
in one of the decoded text windows.
//.Traditional Message Menu
image::traditional-msg-box.png[align="center",alt="Traditional Message Menu"]
* Select the next message to be transmitted (at the start of your next
Tx sequence) by clicking on the circle under *Next*.
* To change to a specified Tx message immediately during a
transmission, click on a rectangular button under the *Now* label.
Changing a Tx message in mid-stream will slightly reduce the chance of
a correct decode, but it is usually OK if done in the first 10-20% of
a transmission.
* All six Tx message fields are editable. You can modify an
automatically generated message or enter a desired message, keeping in
mind the limits on message content. See <<PROTOCOLS,Protocol
Specifications>> for details.
* Click on the pull-down arrow for message #5 to select one of the
pre-stored messages entered on the *Settings | Tx Macros* tab.
Pressing *Enter* on a modified message #5 automatically adds that
message to the stored macros.
* In some circumstances it may be desirable to make your QSOs as
shiort as possible. To configure the program to start contacts with
message #2, disable message #1 by double-clicking on its round
radio-button or rectangular *Tx 1* button. Similarly, to send RR73
rather than RRR for message #4, double-click on one of its buttons.
The second arrangement of controls for generating and selecting
Tx messages appears on *Tab 2* of the Message Control Panel:
//.New Message Menu
image::new-msg-box.png[align="center",alt="New Message Menu"]
With this setup you normally follow a top-to-bottom sequence of
transmissions from the left column if you are calling CQ, or the right
column if answering a CQ.
* Clicking a button puts the appropriate message in the *Gen Msg* box.
If you are already transmitting, the Tx message is changed
immediately.
* You can enter and transmit anything (up to 13 characters, including
spaces) in the *Free Msg* box.
* Click on the pull-down arrow in the *Free Msg* box to select a
pre-stored macro. Pressing *Enter* on a modified message here
automatically adds that message to the table of stored macros.
TIP: During a transmission the actual message being sent always
appears in the first box of the status bar (bottom left of the main
screen).
@@ -1,23 +0,0 @@
// Status=review
A *Status Bar* at the bottom edge of the main window provides useful
information about operating conditions.
//.Status Bar
image::status-bar-a.png[align="left",alt="Status Bar"]
Labels on the *Status Bar* display such information as the program's
current operating state, configuration name, operating mode, and the
content of your most recent transmitted message. The first label
(operating state) can be Receiving, Tx (for Transmitting), Tune, or
the name of file opened from the *File* menu; this label is
highlighted in green for Receiving, yellow for Tx, red for Tune, and
light blue for a file name. When transmitting, the Tx message is
displayed exactly as it will be decoded by receiving stations. The
second label (as shown above) will be absent if you are using the
*Default* setting on the *Configurations* menu. A progress bar shows
the elapsed fraction of a Tx or Rx sequence. Finally, if the Watchdog
(WD) timer was enabled on the *settings | General* tab, a label in the
lower right-hand corner displays the number of minutes remaining
before timeout.
@@ -1,100 +0,0 @@
// Status=review
The following controls appear at the bottom of the Wide Graph window.
Decoding occurs only in the displayed frequency range; otherwise, with
the exceptions of *Start NNN Hz* and of *JT65 nnnn JT9* when operating
in JT9+JT65 mode, controls on the Wide Graph window have no effect on
the decoding process.
image::wide-graph-controls.png[align="center",alt="Wide Graph Controls"]
- *Bins/Pixel* controls the displayed frequency resolution. Set this
value to 1 for the highest possible resolution, or to higher numbers
to compress the spectral display. Normal operation with a convenient
window size works well at 2 to 8 bins per pixel.
- *JT65 nnnn JT9* sets the dividing point (blue marker) for wide-band
decoding of JT65 and JT9 signals in *JT9+JT65* mode. The decoder
looks for JT65 signals everywhere, but JT9 signals only above this
frequency. This setting is stored separately for each band.
- *Start nnn Hz* sets the low-frequency starting point of the
waterfall frequency scale.
- *N Avg* is the number of successive spectra to be averaged before
updating the display. Values around 5 are suitable for normal JT9 and
JT65 operation. Adjust *N Avg* to make the waterfall move faster or
slower, as desired.
- A dropdown list below the *Palette* label lets you select from a
wide range of waterfall color palettes.
- Click *Adjust* to activate a window that allows you to create a
user-defined palette.
- Check *Flatten* if you want _WSJT-X_ to compensate for a sloping or
uneven response across the received passband. For this feature to
work properly, you should restrict the range of displayed frequencies
so that only the active part of the spectrum is shown.
- Select *Current* or *Cumulative* for the spectrum displayed in the
bottom one-third of the Wide Graph window. *Current* is the average
spectrum over the most recent *N Avg* FFT calculations. *Cumulative*
is the average spectrum since the start of the present UTC minute.
*Linear Avg* is useful in JT4 mode, especially when short-form
messages are used.
- Four sliders control reference levels and scaling for waterfall
colors and the spectrum plot. Values around midscale are usually
about right, depending on the input signal level, the chosen palette,
and your own preferences. Hover the mouse over a control to display a
tip reminding you of its function.
- *Smoothing* is active only when *Linear Average* has been selected.
Smoothing the displayed spectrum over more than one bin can enhance
your ability to detect weak EME signals with Doppler spread more than
a few Hz.
[[CONTROLS_FAST]]
=== Fast Graph
The waterfall palette used for the Fast Graph is the same as the one
selected on the Wide Graph. Three sliders at the bottom of the Fast
Graph window can be used to optimize gain and zero-offset for the
displayed information. Hover the mouse over a control to display a
tip reminding you of its function. Clicking the *Auto Level* button
will produce reasonable settings as a starting point.
image::fast-graph-controls.png[align="center",alt="Fast Graph Controls"]
[[CONTROLS_ECHO]]
=== Echo Graph
The following controls appear at the bottom of the Echo Graph:
image::echo-graph-controls.png[align="center",alt="EchoGraph Controls"]
- *Bins/Pixel* controls the displayed frequency resolution. Set this
value to 1 for the highest possible resolution, or to higher numbers
to compress the spectral display.
- *Gain* and *Zero* sliders control scaling and offset of plotted
spectra.
- *Smooth* values greater than 0 apply running averages to the plotted
spectra, thereby smoothing the curves over multiple bins.
- Label *N* shows the number of echo pulses averaged.
- Click the *Colors* button to cycle through 6 possible choices of
color and line width for the plots.
[[CONTROLS_MISCELLANEOUS]]
=== Miscellaneous
Most windows can be resized as desired. If you are short of screen
space you can make the Main Window and Wide Graph smaller by hiding
some controls and labels. To enable this feature type *Ctrl+M* with
focus on the appropriate window. (For the Main Window you can select
*Hide menus and labels* on the *View* menu.) Type *Ctrl+M* again
to make the controls visible once more.
@@ -1,39 +0,0 @@
_WSJT-X_ is programmed to cooperate closely with several other useful
programs.
* {dxlsuite}, {omnirig}, and {hrd} were described in the section on
<<RADIO,rig control>>.
* {pskreporter}, by Philip Gladstone, is a web server that gathers
reception reports sent by various other programs, including _WSJT-X_.
The information is made available in near real time on a world map,
and also as statistical summaries of various kinds. A number of
options are available to the user; for example, you can request a map
showing world-wide JT65 activity on all amateur bands over the
past hour. Such a map might look like this, where different colors
represent different bands:
image::psk-reporter.png[align="left",alt="PSK Reporter"]
The following screen shot shows the PSK Reporter map configured to
show MSK144 reports:
image::psk-reporter_2.png[align="left",alt="PSK Reporter"]
* {jtalert}, by VK3AMA, is available only for Windows. It provides
many operating aids including automatic logging to several third-party
logging programs, audio and visual alerts following a number of
optional alert conditions (decoding of a new DXCC, new state, etc.),
and convenient direct access to web services such as callsign lookup.
image::jtalert.png[align="left",alt="JTAlert-X image"]
* {alarmejt}, by F5JMH, is available only for Linux. The program keeps
its own logbook. It fetches contact information from _WSJT-X_ and
provides visual alerts for new DXCC entities and grid squares on the
current band, as well as other options.
* {jtbridge}, by SM0THU, is available for OS X. It works together with
logging applications Aether, MacLoggerDX, RUMlog or RUMlogNG. It
checks QSO and QSL status of the call and DXCC entity, as well as many
other features.
-155
View File
@@ -1,155 +0,0 @@
=== AP Decoding
The _WSJT-X_ decoders for JT65, QRA64, and FT8 include optional
procedures that use naturally accumulating information during a
minimal QSO. This _a priori_ (AP) information increases sensitivity
of the decoder by up to 4 dB, at the cost of a slightly higher rate of
false decodes.
For example: when you decide to answer a CQ, you already know your own
callsign and that of your potential QSO partner. The software
therefore "`knows`" what to expect for 57 of the 72 message bits (28
bits for each of two callsigns, 1 bit for message type) in the next
received message. The decoder's task can thus be reduced to
determining the remaining 15 bits of the message and ensuring that the
resulting solution is reliable.
AP decoding starts by setting AP bits to the hypothesized values, as
if they had been received correctly. We then determine whether the
remaining message and parity bits are consistent with the hypothesized
AP bits, with a specified level of confidence. Successful AP decodes
are labeled with an end-of-line indicator of the form `aP`, where `P`
is one of the single-digit AP decoding types listed in Table 1. For
example, `a2` indicates that the successful decode used MyCall as
hypothetically known information.
[[FT8_AP_INFO_TABLE]]
.FT8 AP information types
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|aP | Message components
|a1 | CQ &#160; &#160; ? &#160; &#160; ?
|a2 | MyCall &#160; &#160; ? &#160; &#160; ?
|a3 | MyCall DxCall &#160; &#160; ?
|a4 | MyCall DxCall RRR
|a5 | MyCall DxCall 73
|a6 | MyCall DxCall RR73
|===============================================
If a codeword is found that is judged to have high (but not
overwhelmingly high) probability of being correct, a `?` character is
appended when the decoded message is displayed. To avoid misleading
spots of occasional false decodes, messages so marked are not
forwarded to {pskreporter}.
Table 2 lists the six possible QSO states that are tracked by the
_WSJT-X_ auto-sequencer, along with the type of AP decoding that would
be attempted in each state.
[[FT8_AP_DECODING_TYPES_TABLE]]
.FT8 AP decoding types for each QSO state
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===========================================
|State |AP type
|CALLING STN | 2, 3
|REPORT | 2, 3
|ROGER_REPORT | 3, 4, 5, 6
|ROGERS | 3, 4, 5, 6
|SIGNOFF | 3, 1, 2
|CALLING CQ | 1, 2
|===========================================
Decoding with _a priori_ information behaves slightly differently
in JT65. Some details are provided in Tables 3 and 4.
[[JT65_AP_INFO_TABLE]]
.JT65 AP information types
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|aP | Message components
|a1 | CQ &#160; &#160; ? &#160; &#160; ?
|a2 | MyCall &#160; &#160; ? &#160; &#160; ?
|a3 | MyCall DxCall &#160; &#160; ?
|a4 | MyCall DxCall RRR
|a5 | MyCall DxCall 73
|a6 | MyCall DxCall DxGrid
|a7 | CQ DxCall DxGrid
|===============================================
[[JT65_AP_DECODING_TYPES_TABLE]]
.JT65 AP decoding types for each QSO state
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===========================================
|State |AP type
|CALLING STN | 2, 3, 6, 7
|REPORT | 2, 3
|ROGER_REPORT | 3, 4, 5
|ROGERS | 3, 4, 5
|SIGNOFF | 2, 3, 4, 5
|CALLING CQ | 1, 2, 6
|===========================================
=== Decoded Lines
Displayed information accompanying decoded messages generally includes UTC,
signal-to-noise ratio in dB, time offset DT in seconds, and
audio frequency in Hz. Some modes include additional information such
as frequency offset from nominal (DF), frequency drift (Drift or F1),
or distance (km or mi).
There may also be some cryptic characters with special meanings
summarized in the following Table:
[[DECODED_LINES_TABLE]]
.Notations used on decoded text lines
[width="50%",cols="h,3*^",frame=topbot,options="header"]
|===========================================
|Mode |Mode character|Sync character|End of line information
|FT8 | ~ | | ? &#160; aP
|JT4 | $ | *, # | f, fN, dNC
|JT9 | @ | |
|JT65 | # | |
|JT65 VHF| # | *, # | f, fN, dNC
|QRA64 | : | * | R
|ISCAT | | * | M N C T
|MSK144 | & | | N H E
|===========================================
Sync character::
`*` - Normal sync +
`#` - Alternate sync
End of line information::
`?` - Decoded with lower confidence +
`a` - Decoded with aid of some a priori (AP) information +
`C` - Confidence indicator [ISCAT and Deep Search; (0-9,*)] +
`d` - Deep Search algorithm +
`E` - Size of MSK eye diagram opening - if negative, the eye is closed +
`f` - Franke-Taylor or Fano algorithm +
`H` - Number of bit errors corrected +
`M` - Message length (characters) +
`N` - Number of Rx intervals or frames averaged +
`P` - Number indicating type of AP information (Table 1, above) +
`R` - Return code from QRA64 decoder +
`T` - Length of analyzed region (s)
Table 6 below shows the meaning of the return codes R in QRA64 mode.
[[QRA64_AP_INFO_TABLE]]
.QRA64 AP return codes
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|rc | Message components
|0 | ? &#160; &#160; ? &#160; &#160; ?
|1 | CQ &#160; &#160; ? &#160; &#160; ?
|2 | CQ &#160; &#160; ?
|3 | MyCall &#160; &#160; ? &#160; &#160; ?
|4 | MyCall &#160; &#160; ?
|5 | MyCall DxCall &#160; &#160; ?
|6 | ? &#160; &#160; DxCall &#160; &#160; ?
|7 | ? &#160; &#160; DxCall
|8 | MyCall DxCall DxGrid
|9 | CQ DxCall &#160; &#160; ?
|10 | CQ DxCall
|11 | CQ DxCall DxGrid
|===============================================
-17
View File
@@ -1,17 +0,0 @@
<style>
html, body {
font-size: 90%;
}
body {
font-family: Arial, Helvetica, sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: Georgia, "Times New Roman", Times, serif;
}
a:visited {
color: purple;
}
</style>
View File
-77
View File
@@ -1,77 +0,0 @@
////
Questions:
Should be short one liners (in the .adoc file) ending with ?::
If your question is too long for one line, consider multiple questions or rephrase
Answers:
Can be bullet or paragraphs. Bullets make for easier reading.
Bullet Usage:
* = a circle bullet single intent
** = circle bullet double indent
. = should be avoided as the questions are numbered
.. = bullet a, b, c, and so on, double indent
Alternatives: Use a * Bullet, followed by .. for example, then have
a multi-section answer using the * as the section header
* Section Header 1
.. Possible Answer a
.. Possible Answer b
* Section Header 2
.. Possible Answer a
.. Possible Answer b
Link Usage:
Use the common/links.adoc for href links to maintain consistency. Try to avoid
apostrophes ` or ' as it breaks AsciiDoc syntax without special escaping
and they do not translate into other languages well.
////
[qanda]
My displayed spectrum is flatter when I do not check the *Flatten* box. What's wrong?::
_WSJT-X_ does not expect a steep filter edge within the displayed
passband. Use a wider IF filter or reduce the displayed passband by
decreasing *Bins/Pixel*, increasing *Start*, or reducing the width of
the *Wide Graph*. You might also choose to re-center the filter
passband, if such control is available.
How should I configure _WSJT-X_ to run multiple instances?::
Start _WSJT-X_ from a command-prompt window, assigning each instance a
unique identifier as in the following two-instance example. This
procedure will isolate the *Settings* file and the writable file
location for each instance of _WSJT-X_.
wsjtx --rig-name=TS2000
wsjtx --rig-name=FT847
Rig control through _OmniRig_ seems to fail when I click *Test CAT*. What can I do about it?::
_Omni-Rig_ apparently has a bug that appears when you click *Test
CAT*. Forget using *Test CAT* and just click *OK*. _Omni-Rig_ then
behaves normally.
I am using _WSJT-X_ with _Ham Radio Deluxe_. All seems well until I start HRD Logbook or DM780 running in parallel; then CAT control becomes unreliable.::
You may see delays up to 20 seconds or so in frequency changes or
other radio commands, due to a bug in HRD. HRD folks are aware of the
problem, and are working to resolve it.
I am running _WSJT-X_ under Ubuntu. The program starts, but menu bar is missing from the top of the main window and the hot-keys don't work.::
Ubuntu's new "`Unity`" desktop puts the menu for the currently active
window at the top of the primary display screen. You can restore menu
bars to their traditional locations by typing the following in a
command-prompt window:
sudo apt remove appmenu-qt5
+
Alternatively, you can disable the common menu bar for just _WSJT-X_
by starting the application with the environment variable
QT_QPA_PLATFORMTHEME set to empty (the space after the '=' character
is necessary):
QT_QPA_PLATFORMTHEME= wsjtx
-15
View File
@@ -1,15 +0,0 @@
// Status=review
- You can control the program's font sizes by using a text editor
(e.g., Windows Notepad or similar) to create a one-line file named
+fonts.txt+ in the _WSJT-X_ installation directory. Enter a single
line of text with four numbers separated by spaces. The first two
numbers control the font size (in points) and weight (on a 0 100
scale) of most labels on the user interface. The last two numbers
control size and weight of text in the *Band Activity* and *Rx
Frequency* windows.
- By default the four numbers are "`8 50 10 50`". If you need larger
fonts in the user interface and bold text in the decode windows, try
something like "`10 50 12 100`" (without the quotes).
Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Some files were not shown because too many files have changed in this diff Show More