Compare commits

...

182 Commits

Author SHA1 Message Date
Jordan Sherer 9bb1ae920b Added msg to to the menu 2019-01-23 20:38:44 -05:00
Jordan Sherer 9b29c8c722 Added query msgs to the menu 2019-01-23 20:35:29 -05:00
Jordan Sherer 33227a648d Bump eol 2019-01-23 20:33:13 -05:00
Jordan Sherer faf653d8ba Added message storage and retreival 2019-01-23 20:31:26 -05:00
Jordan Sherer a1f0a15d41 Bump to v0.13.0 2019-01-22 20:19:25 -05:00
Jordan Sherer 0b5972e2ea Added dialog to set audio offset 2019-01-21 22:27:43 -05:00
Jordan Sherer 8738132836 Added a new, more obvious frequency control and a menu item for setting the frequency 2019-01-21 17:45:52 -05:00
Jordan Sherer d3f398e538 Fixed issue with printing messages with the autoreply whitelist non-empty 2019-01-21 09:21:35 -05:00
Jordan Sherer b97e0f3411 Make sure selected text found matches search 2019-01-20 23:27:32 -05:00
Jordan Sherer ef6bde8cb0 Closed #45: A subset of directed commands will be autoreplied when relayed. This includes: SNR, GRID, QTC, QTH, etc 2019-01-20 23:08:57 -05:00
Jordan Sherer f13a6c37e8 Fixed main header 2019-01-20 22:27:27 -05:00
Jordan Sherer 10ecd059d1 Updated CQ spec to include CQ FIELD and CQ CONTEST 2019-01-20 13:15:23 -05:00
Jordan Sherer d722b8206c Fixed issue with tx queue when idle watchdog kicks in 2019-01-20 11:02:10 -05:00
Jordan Sherer 239b02d927 Only have a relay status if AUTO is enabled 2019-01-19 17:28:59 -05:00
Jordan Sherer 55d76dc67f Fixed duplicate acks printing 2019-01-17 09:56:42 -05:00
Jordan Sherer 685c1be141 Fixed a few bugs related to message duplicates 2019-01-17 09:36:06 -05:00
Jordan Sherer bf2bfa28be HB should only move freq if necessary 2019-01-16 00:39:15 -05:00
Jordan Sherer aae1c20f12 Added call detail tooltip into the call activity 2019-01-16 00:08:09 -05:00
Jordan Sherer c75b21b0b5 Fixed bug in flags hb message generation 2019-01-15 02:06:30 -05:00
Jordan Sherer 1648c645a5 Bump to v0.12.1 2019-01-14 10:45:00 -05:00
Jordan Sherer d0d9c4d352 Added whitelist to the configuration for AUTO replies. That way you can restrict who you allow to use your station 2019-01-14 10:43:14 -05:00
Jordan Sherer a46035fa86 Unified STATUS and HB flags for better visibility. 2019-01-14 10:15:45 -05:00
Jordan Sherer de2d1dcf8d Conditionally compile call detail browser into the app 2019-01-14 09:50:47 -05:00
Jordan Sherer 60aadd867a Refactored heard graph logging 2019-01-14 09:48:53 -05:00
Jordan Sherer 4541d58cac Fixed self logging 2019-01-09 18:27:33 -05:00
Jordan Sherer 9d575707f0 Initial commit of detail panel 2019-01-09 17:52:53 -05:00
Jordan Sherer 4c82a5e84a Updated HB and CQ menu labels 2019-01-09 11:36:08 -05:00
Jordan Sherer b81622ccde Fixed #72: added a tooltip of the band activity text 2019-01-09 11:31:15 -05:00
Jordan Sherer cf85b18fa5 Fixed #75: allow messages to group callsigns 2019-01-09 11:25:00 -05:00
Jordan Sherer 1c6b18cb51 Fixed #77: Added an option to hide the statusbar 2019-01-09 11:14:59 -05:00
Jordan Sherer 3d7b523746 Rename variable to be more correct 2019-01-09 11:03:32 -05:00
Jordan Sherer 05f584a58b Removed SQL dump 2019-01-06 22:50:51 -05:00
Jordan Sherer bb24724587 Cut down on a few false positives of auto-prepended callsigns with text override for words 3 characters or less. 2019-01-06 22:48:44 -05:00
Jordan Sherer bb3a710b88 Clear activity should clear the heard graph too. 2019-01-03 15:43:07 -05:00
Jordan Sherer 0f61ebe78d Merge branch 'ft8call-develop' of bitbucket.org:widefido/js8call-private into ft8call-develop 2019-01-03 13:33:25 -05:00
Jordan Sherer 0ec5348aee Fixed issue with requests being sent out of the MessageClient when udp is disabled 2019-01-03 13:33:08 -05:00
Jordan Sherer 489d5c7c1c Fixed network messages to include an id so they are both 1) indexable and 2) do not cache in the network buffer 2019-01-03 13:32:37 -05:00
Jordan Sherer 68c15aa83e Added heard activity graph logging 2019-01-03 12:39:48 -05:00
Jordan Sherer 44bb868efb Fixed issue with removing band activity rows 2019-01-02 21:27:04 -05:00
Jordan Sherer e098fe75c2 Remove legacy control menu items 2019-01-02 20:09:36 -05:00
Jordan Sherer 4f226b0c11 Cleanup of build frames and a note for later 2019-01-02 12:36:25 -05:00
Jordan Sherer cc9ecf0f47 Bump eol 2019-01-02 12:28:27 -05:00
Jordan Sherer bdfc1cff8e Squashed commit of the following:
commit e48c78765ca1e2e5a68fd93bac7191eaf6918352
Author: Jordan Sherer <jordan@widefido.com>
Date:   Wed Jan 2 12:23:28 2019 -0500

    Transition to persistent inbox for later retrieval
    Fixed issue with inbox items disappearing due to aging.

commit 1df07595bf6507438c1488839f7a2075a432a1a1
Author: Jordan Sherer <jordan@widefido.com>
Date:   Wed Jan 2 09:23:28 2019 -0500

    Filtered value and count queries for the inbox

commit c93a93a1c43a65fae4a31ddeb40c77c53204bbdb
Author: Jordan Sherer <jordan@widefido.com>
Date:   Tue Jan 1 22:58:07 2019 -0500

    Initial cut of inbox storage
2019-01-02 12:27:16 -05:00
Jordan Sherer 0405dba3fc Added RIG.PTT status message to the API 2019-01-01 10:29:35 -05:00
Jordan Sherer bedc6dd96c Fixed bug with hearing command response. Added status response shortcode. 2019-01-01 10:12:09 -05:00
Jordan Sherer b001356eb0 Added configuration parameter to execute an external command when PTT is toggled 2018-12-31 23:37:19 -05:00
Jordan Sherer 85c0f1fb96 Fixed #60: sort by menu added to right click of the table headers 2018-12-31 20:30:47 -05:00
Jordan Sherer 81a22ab8b8 Renamed QUERY to QUERY CALL. Added generic user QUERY with no auto-reply (for scripting). 2018-12-31 20:03:51 -05:00
Jordan Sherer b7792fe30c Removed most old compat query shortcodes 2018-12-31 19:50:50 -05:00
Jordan Sherer 19ad283119 Added HEARING short message back in to complement HEARING query 2018-12-31 19:49:06 -05:00
Jordan Sherer 7b44b3010a Display 0M idle status in status command 2018-12-31 19:45:31 -05:00
Jordan Sherer b0fff26b77 Added timestamp to alert 2018-12-31 17:07:33 -05:00
Jordan Sherer 0a63433bd7 Restore the alert box for when a message is received via relay 2018-12-31 15:53:09 -05:00
Jordan Sherer a4cc87d7b4 Added a toggle to disable word suggestions 2018-12-31 15:25:04 -05:00
Jordan Sherer 28e542e414 Updated suggestions menu to be inline 2018-12-31 15:14:48 -05:00
Jordan Sherer 22e2700a04 Cleanup 2018-12-30 20:20:06 -05:00
Jordan Sherer 95bbfb8232 Squashed commit of the following:
commit a1f8cef250bcc033d120d87aaeafd0794e0c7252
Author: Jordan Sherer <jordan@widefido.com>
Date:   Sun Dec 30 20:16:47 2018 -0500

    Added word replacement from suggestions menu

commit 51af18c06d3268b34dd5b472f8a94787e47af04c
Author: Jordan Sherer <jordan@widefido.com>
Date:   Sun Dec 30 11:21:24 2018 -0500

    Simplified word checker to use text stats signal for computation

commit aa831492784fec30c8a6d804a4ae7ca718f865fe
Author: Jordan Sherer <jordan@widefido.com>
Date:   Sat Dec 29 22:50:24 2018 -0500

    Initial working implmementation of spell check highlighting
2018-12-30 20:18:35 -05:00
Jordan Sherer 1aed1fde31 Fixed deselect callsign after logging not showing up in configuration 2018-12-28 23:24:38 -05:00
Jordan Sherer 7e9e955d7d Fixed macro expansion of macro QTC, QTH, CQ, REPLY values 2018-12-28 11:44:58 -05:00
Jordan Sherer 45f5854bc0 Merge branch 'ft8call-develop' of bitbucket.org:widefido/js8call-private into ft8call-develop 2018-12-27 22:39:57 -05:00
Jordan Sherer 9e1afaf106 Changed status response to only report things that are 'on' 2018-12-27 22:39:13 -05:00
Jordan Sherer 1a8d02fc89 Performing some minimal code cleanup 2018-12-27 10:04:46 -05:00
Jordan Sherer 4064c70c26 Restore clear all menu item label 2018-12-27 00:13:06 -05:00
Jordan Sherer ce153a4511 Moved callsign count to header instead of in the ALLCALL row since that row can be hidden now 2018-12-26 23:38:24 -05:00
Jordan Sherer ebbdd679e1 Updated menu item label 2018-12-26 23:22:07 -05:00
Jordan Sherer 298500f8fc Added confirmation to clear all activity item 2018-12-26 23:08:02 -05:00
Jordan Sherer 0d63463851 Added new status command output and fixed a bug in macros 2018-12-26 20:33:30 -05:00
Jordan Sherer 2f3ea90263 Bump to v0.12.0 2018-12-26 15:16:51 -05:00
Jordan Sherer c8af5e51a7 Removed save/messages/callsign.txt for every directed calls in preparation for message inbox 2018-12-26 15:16:25 -05:00
Jordan Sherer df602c663b Fixed button background autofill 2018-12-26 15:00:47 -05:00
Jordan Sherer 9f2e87c076 Removed selcall and active flag
In effort to simplify the behavior of automatic responses as well as make the software easier to use, I have removed the SELCALL button and the ACTIVE flag. Now, the response to STATUS is one that contains actual status (AUTO ON/OFF, VERSION NUMBER, etc). HBs used this in their transmissions, but it was never really accurate because it relied on the user to toggle the switch. Hazardous really. So, I approached this by simplifying the behavior. If AUTO is on, you will reply to direct queries. If AUTO is off, you wont. Simple. If HB is on, you will heartbeat. If it is off, you wont. Simple. If both AUTO and HB is on, you will automatically reply to heartbeats with ACKs. If not, you wont. Simple. You can remove yourself from the ALLCALL group. This is the same behavior as the previous SELCALL function and now that we have simplified it I can build an actual SELCALL function (to selectively allow stations to call you) instead of a 1/2 SELCALL that it used to be. Bingo.
2018-12-26 14:05:44 -05:00
Jordan Sherer 6ef891af0f Fixed inactive table highlighting 2018-12-23 22:31:22 -05:00
Jordan Sherer 0f05bfedc3 Fixed bold font in call activity...again 2018-12-23 22:24:45 -05:00
Jordan Sherer fb9c280c67 Fixed Hz and dB labels to the tables 2018-12-23 21:06:54 -05:00
Jordan Sherer e19dc2ea8f Relay messaging label 2018-12-23 09:48:22 -05:00
Jordan Sherer 4ad817c060 Added units to SNR and Offset in the activity tables 2018-12-23 09:37:40 -05:00
Jordan Sherer 88fb605b40 Removed remnants of WSJT-X references 2018-12-23 08:54:31 -05:00
Jordan Sherer 478a909b90 Added idle ellipsis during band fades 2018-12-22 22:47:48 -05:00
Jordan Sherer 03b2b11938 Fixed issue with call activity table font not being set on application start 2018-12-21 22:20:52 -05:00
Jordan Sherer 3b4ea12e5f Band Activity Double Click Switches Frequency Offset 2018-12-21 22:14:14 -05:00
Jordan Sherer caf3cbfc3c Set flat should not be in text tx update 2018-12-21 22:02:15 -05:00
Jordan Sherer 5bc4838496 Send button should be flat to help colorize it 2018-12-21 20:02:04 -05:00
Jordan Sherer 11740384f3 Bumped ALLCALL timeout to 10 minutes 2018-12-20 21:05:24 -05:00
Jordan Sherer 5c9aee4b3f Fixed #51: lighter red for higher contrast 2018-12-20 20:55:55 -05:00
Jordan Sherer db5969fdc4 Fixed #53: group callsign validation errors in configuration and from call activity menu 2018-12-20 20:36:33 -05:00
Jordan Sherer 5ca582a6b4 Fixed #54: heartbeat anywhere should be exposed in the configuration and HB ack should abide by that setting 2018-12-20 20:16:53 -05:00
Jordan Sherer 17416144a8 Added relay message storage and display in the call activity list 2018-12-18 21:28:31 -05:00
Jordan Sherer b8ff10fde9 Updated about messaging 2018-12-17 01:46:57 -05:00
Jordan Sherer 6c741e21b5 Removed hash messages '#' as they are now duplicated by relay '>' 2018-12-17 01:33:22 -05:00
Jordan Sherer 47eec2dc0b Added automatic ACK for relay messages 2018-12-17 01:27:41 -05:00
Jordan Sherer 6504a1f220 Bump eol and versions to 0.11.0 2018-12-17 01:04:43 -05:00
Jordan Sherer 91a2a801f9 Fixed heartbeat sub-channel configuration 2018-12-17 01:03:07 -05:00
Jordan Sherer 8c74499700 Removed unused commands 2018-12-17 00:54:54 -05:00
Jordan Sherer 51c9dd2761 Removed QRZ short message 2018-12-17 00:45:44 -05:00
Jordan Sherer dc70d53f5c Added HEARING query back into the app 2018-12-17 00:38:34 -05:00
Jordan Sherer 3c2a5f98ec Fixed #16: do not symlink js8call in usr if not using the opt install prefix 2018-12-14 21:23:06 -05:00
Jordan Sherer 5c1f890095 Fixed #13: configuration validator should require cq or callsign in cq message 2018-12-14 20:16:33 -05:00
Jordan Sherer 29f759dafe Fixed #23: idle watchdog should prevent all types of automated transmissions 2018-12-14 20:02:46 -05:00
Jordan Sherer 90858f8964 Fixed #43: space prefix should not break directed call 2018-12-13 22:22:10 -05:00
Jordan Sherer e6464e952d Removed comments 2018-12-13 22:21:37 -05:00
Jordan Sherer 186fed04e3 Fixed #41: remember pane sizes when showing/hiding 2018-12-13 09:50:02 -05:00
Jordan Sherer 6716eb771e Changed send button color while sending and label when ready 2018-12-12 22:14:45 -05:00
Jordan Sherer b8b2cf33c3 Fixed defines and % in the send button 2018-12-11 23:52:01 -05:00
Jordan Sherer 4025edfc0f Fixed rebase issues 2018-12-11 22:23:07 -05:00
Jordan Sherer c5930a0aa3 Fixed rebase issues 2018-12-11 22:14:26 -05:00
Jordan Sherer 9079d45587 Rename JS8CallExtended to JS8CallFlag 2018-12-10 23:37:22 -05:00
Jordan Sherer 223a4a2183 Updated comments to be more clear 2018-12-10 23:37:22 -05:00
Jordan Sherer 1584cf0404 Turn off turbo for now...still experimental 2018-12-10 23:37:22 -05:00
Jordan Sherer 5619824bd8 Hide turbo button for now 2018-12-10 23:37:22 -05:00
Jordan Sherer e1e2ae50e8 Simplify conditional 2018-12-10 23:35:58 -05:00
Jordan Sherer cc96daa26f Fixed button alignment 2018-12-10 23:35:58 -05:00
Jordan Sherer 5ba31d6df7 Changed frame packing so we can use one of the ibits as a turbo flag 2018-12-10 23:33:50 -05:00
Jordan Sherer 73346240e5 Fixed frame counting during turbo transmission 2018-12-10 23:30:36 -05:00
Jordan Sherer 886e678531 Fixed send button counts while in turbo 2018-12-10 23:27:21 -05:00
Jordan Sherer 526b72022e Added turbo button to the UI 2018-12-10 23:27:21 -05:00
Jordan Sherer a1864fa3f0 Configurable slots 2018-12-10 23:23:31 -05:00
Jordan Sherer b0c57029e8 Experiment with compression 2018-12-10 23:18:19 -05:00
Jordan Sherer 2d5b41d4b7 Added a waterfall indicator for turbo'd signals 2018-12-10 23:18:19 -05:00
Jordan Sherer 21004a7b28 Two-frame turbo for any message 2018-12-10 23:18:19 -05:00
Jordan Sherer 94f2f510fc Initial proof of concept of turbo button 2018-12-10 23:18:19 -05:00
Jordan Sherer b6745c9e2e Fixed #40: Force uppercase without resetting text 2018-12-10 10:18:45 -05:00
Jordan Sherer 8c81b3b83a Fixed #38: Moved Show Heartbeats menu item to the View menu 2018-12-10 09:44:16 -05:00
Jordan Sherer 9ddfec5e72 Fixed #28: band activity clear should not deselect callsign selected in call activity 2018-12-04 22:20:26 -05:00
Jordan Sherer a5f0937cbb Fixed #23: Log window should not halt transmission 2018-12-04 22:10:52 -05:00
Jordan Sherer 26f21cd70a Fixed issue with repeat messages 2018-12-03 22:42:19 -05:00
Jordan Sherer bb7e2544b5 Updated README with new links and history line items 2018-12-02 23:03:42 -05:00
Jordan Sherer 4df65585a3 Bump to v0.10.1 2018-12-01 17:22:29 -05:00
Jordan Sherer f406553a5f Fixed issues with frame counting 2018-12-01 17:17:12 -05:00
Jordan Sherer ecf14dcb5c Fixed #7: De-select callsign on save log should be visible in the settings 2018-12-01 17:03:05 -05:00
Jordan Sherer 5163a4a630 Fixed #1: automatic repeat of CQ was not transmitting when setting was not checked 2018-12-01 16:59:17 -05:00
Jordan Sherer 4af1a14961 Remove FT8 reference from ALL.txt 2018-12-01 16:51:14 -05:00
Jordan Sherer 842896d867 Restore the 'Deselect callsign after logging' setting 2018-12-01 16:47:57 -05:00
Jordan Sherer 4406e99670 Added MFSK/JS8 for logging modes 2018-11-30 17:02:14 -05:00
Jordan Sherer 79785dbef5 Fixed bug in HB auto-reply when HB was not active 2018-11-30 10:05:47 -05:00
Jordan Sherer 1d1bc254a4 Don't turn off the repeat buttons on stop button clicked, just reset them 2018-11-30 09:09:54 -05:00
Jordan Sherer 4ddccd99a1 Added a compatiblity display for old heartbeat acks 2018-11-29 22:53:56 -05:00
Jordan Sherer dd6f50a5a3 Bump version and EOL 2018-11-29 22:51:19 -05:00
Jordan Sherer 55c365b834 Added heartbeat and CQ to control menu 2018-11-29 22:43:15 -05:00
Jordan Sherer b55f8ba5c5 Added option for displaying/hiding heartbeats and acks 2018-11-29 22:34:39 -05:00
Jordan Sherer fd77e5440f Keep configuration option for heartbeat channelization 2018-11-29 22:19:17 -05:00
Jordan Sherer 19cb0b859d SELCALL checked should disable repeat transmissions 2018-11-29 21:53:03 -05:00
Jordan Sherer 3d3be02830 Countdown for HB and CQ. Escape key stops CQ and resets HB timer 2018-11-28 22:53:18 -05:00
Jordan Sherer 55f04d3cd7 Fixed padding of configuration behavior panel 2018-11-28 16:42:09 -05:00
Jordan Sherer 693eec8b4b Rename do not repeat 2018-11-27 23:25:40 -05:00
Jordan Sherer 9244ac08c6 Hide heartbeat and acks if we have HB turned off 2018-11-27 23:21:16 -05:00
Jordan Sherer 8004c51ed2 Hide configuration for heartbeat. 2018-11-27 23:16:02 -05:00
Jordan Sherer 52b67a5609 HB and CQ repeat logic 2018-11-27 23:04:11 -05:00
Jordan Sherer 3e7c64e994 Proper active/inactive flags for HB 2018-11-26 22:40:34 -05:00
Jordan Sherer d9d3e6fba3 Added active/inactive flag and restructuring heartbeat 2018-11-25 22:12:54 -05:00
Jordan Sherer 09cea086c7 Added fullscreen toggle 2018-11-22 10:37:38 -05:00
Jordan Sherer a013e79eff Reordering varicode commands to make it easier to spot which numbers are available 2018-11-20 10:09:07 -05:00
Jordan Sherer a3e004375e Added deselect callsign after logging as an option instead of forced 2018-11-20 09:50:53 -05:00
Jordan Sherer f018a622ce Removed printing of ALLCALL messages that were not freetext in the RX window 2018-11-19 23:02:59 -05:00
Jordan Sherer 565c031b28 Added add/remove group from callsign list and it propagate to the settings 2018-11-19 22:36:28 -05:00
Jordan Sherer d88d8aa440 Removed clear menu item icons 2018-11-19 22:36:10 -05:00
Jordan Sherer 3a59599253 Fix SELCALL and HB menu items toggle vs click 2018-11-16 15:36:02 -05:00
Jordan Sherer 22e4b0891e Bump eol 2018-11-15 22:09:03 -05:00
Jordan Sherer 8c564b6637 Added control menu 2018-11-15 22:06:52 -05:00
Jordan Sherer 97763ed82d Bump to 0.9 2018-11-15 21:57:20 -05:00
Jordan Sherer a7849c5b72 Added push button bold style for colorblindness 2018-11-15 21:57:04 -05:00
Jordan Sherer 04394273dd Added notification for CQ messages 2018-11-15 15:03:05 -05:00
Jordan Sherer 1052dd3f9f Added macro expansion in typed message text 2018-11-14 22:48:31 -05:00
Jordan Sherer 78ed799a8b Updated configuration panel to be more flexible (scroll areas) 2018-11-14 22:03:45 -05:00
Jordan Sherer c0d08f87b6 Added keyboard shortcuts to the basic Show actions. Added show action to disable tooltips 2018-11-13 12:35:39 -05:00
Jordan Sherer f92b3db5ea Added ability to add an arbitrary station to the heard list manually 2018-11-12 16:51:51 -05:00
Jordan Sherer cebed44ccd User Interface Tweaks:
* Changed Window Menu to View Menu
* Added Show Clock to View Menu
* Changed minimum sizing for better fit on smaller screens
* Reordered Clock and Date for Clock Priority
2018-11-12 16:34:31 -05:00
Jordan Sherer d47d88681b Updated dependencies list 2018-11-11 15:06:45 -05:00
Jordan Sherer 1be0ee4f4f Added a reference to dependency installation 2018-11-11 14:58:23 -05:00
Jordan Sherer 43d8986e0a Tweaking window sizes 2018-11-08 17:11:25 -05:00
Jordan Sherer fd69dce0ae Fixed word wrapping of non-breaking space words by only replacing double spaces 2018-11-06 23:06:05 -05:00
Jordan Sherer b2fb3f31ac Added azimuth to the distance column 2018-11-06 17:28:21 -05:00
Jordan Sherer db704858e2 Merge branch 'ft8call-develop' of bitbucket.org:widefido/js8call into ft8call-develop 2018-11-05 21:36:13 -05:00
Jordan Sherer 1d11f0f8ba Fixed word wrapping with no break spaces 2018-11-05 21:13:16 -05:00
Jordan Sherer b6bc50a8e1 Fixed QAction for older Qt versions 2018-11-05 17:00:59 -05:00
Jordan Sherer 5addf8f61f Fixed bug with space collapsing in displayTextForFreq 2018-11-05 16:51:24 -05:00
Jordan Sherer 367966f5e6 Bump to v0.8.3 2018-11-05 16:47:09 -05:00
Jordan Sherer caaaa957b6 Fixed OSX issue with menuBar menus that have sub-menues that aren't populated at construction, but when the menu is aboutToShow 2018-11-05 16:00:12 -05:00
Jordan Sherer c440d4c143 Added TDELTA macro variable 2018-11-05 11:35:37 -05:00
Jordan Sherer 740c0b4c04 Fixed call activity with empty rows 2018-11-04 14:57:44 -05:00
Jordan Sherer f5ce9f0e30 Added TU short command 2018-11-03 22:38:27 -04:00
Jordan Sherer 0a6ec136f9 Fixed macro expansion for auto-reply messages QTC and QTH 2018-11-03 22:20:49 -04:00
Jordan Sherer d5e1f2822d Fixed more issues with compressed data decoding and invalid frames 2018-11-03 22:14:42 -04:00
47 changed files with 256656 additions and 4480 deletions
+16 -5
View File
@@ -178,6 +178,7 @@ set (wsjt_qt_CXXSRCS
HRDTransceiver.cpp
DXLabSuiteCommanderTransceiver.cpp
NetworkMessage.cpp
Message.cpp
MessageClient.cpp
LettersSpinBox.cpp
HintedSpinBox.cpp
@@ -237,10 +238,12 @@ set (wsjtx_CXXSRCS
jsc.cpp
jsc_list.cpp
jsc_map.cpp
jsc_checker.cpp
SelfDestructMessageBox.cpp
messagereplydialog.cpp
keyeater.cpp
APRSISClient.cpp
Inbox.cpp
mainwindow.cpp
Configuration.cpp
main.cpp
@@ -549,6 +552,10 @@ set (qra_CSRCS
lib/qra/qracodes/normrnd.c
)
set (sqlite3_CSRCS
vendor/sqlite3/sqlite3.c
)
set (wsjt_CSRCS
${ka9q_CSRCS}
lib/ftrsd/ftrsdap.c
@@ -620,6 +627,7 @@ set (all_CXXSRCS
)
set (all_C_and_CXXSRCS
${sqlite3_CSRCS}
${wsjt_CSRCS}
${wsprsim_CSRCS}
${wsprd_CSRCS}
@@ -1111,6 +1119,7 @@ endif (${OPENMP_FOUND} OR APPLE)
# build the main application
add_executable (js8call MACOSX_BUNDLE
${sqlite3_CSRCS}
${wsjtx_CXXSRCS}
${wsjtx_GENUISRCS}
wsjtx.rc
@@ -1272,12 +1281,14 @@ if (NOT WIN32 AND NOT APPLE)
#COMPONENT runtime
)
execute_process(COMMAND ln -s /opt/js8call/bin/js8call ljs8call)
IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/opt/js8call")
execute_process(COMMAND ln -s /opt/js8call/bin/js8call ljs8call)
install(FILES
${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call
#COMPONENT runtime
)
install(FILES
${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call
#COMPONENT runtime
)
endif()
endif (NOT WIN32 AND NOT APPLE)
+161 -40
View File
@@ -163,6 +163,7 @@
#include <QSerialPortInfo>
#include <QScopedPointer>
#include <QDateTimeEdit>
#include <QProcess>
#include "pimpl_impl.hpp"
#include "qt_helpers.hpp"
@@ -463,6 +464,9 @@ private:
void delete_selected_macros (QModelIndexList);
Q_SLOT void on_save_path_select_push_button_clicked (bool);
Q_SLOT void on_azel_path_select_push_button_clicked (bool);
Q_SLOT void on_sound_cq_path_select_push_button_clicked();
Q_SLOT void on_sound_cq_path_test_push_button_clicked();
Q_SLOT void on_sound_cq_path_reset_push_button_clicked();
Q_SLOT void on_sound_dm_path_select_push_button_clicked();
Q_SLOT void on_sound_dm_path_test_push_button_clicked();
Q_SLOT void on_sound_dm_path_reset_push_button_clicked();
@@ -517,6 +521,7 @@ private:
QDir default_azel_directory_;
QDir azel_directory_;
QString sound_cq_path_; // cq message sound file
QString sound_dm_path_; // directed message sound file
QString sound_am_path_; // alert message sound file
@@ -586,6 +591,7 @@ private:
QString my_grid_;
QString my_station_;
QStringList my_groups_;
QStringList auto_whitelist_;
QString my_qth_;
QString cq_;
QString reply_;
@@ -638,8 +644,10 @@ private:
bool insert_blank_;
bool DXCC_;
bool ppfx_;
bool clear_DX_;
bool clear_callsign_;
bool miles_;
bool avoid_allcall_;
bool spellcheck_;
bool quick_call_;
bool disable_TX_on_73_;
int heartbeat_;
@@ -655,7 +663,7 @@ private:
bool x4ToneSpacing_;
bool use_dynamic_info_;
QString opCall_;
QString ptt_command_;
QString aprs_server_name_;
QString aprs_passcode_;
port_type aprs_server_port_;
@@ -769,8 +777,10 @@ bool Configuration::prompt_to_log () const {return m_->prompt_to_log_;}
bool Configuration::insert_blank () const {return m_->insert_blank_;}
bool Configuration::DXCC () const {return m_->DXCC_;}
bool Configuration::ppfx() const {return m_->ppfx_;}
bool Configuration::clear_DX () const {return m_->clear_DX_;}
bool Configuration::clear_callsign () const {return m_->clear_callsign_;}
bool Configuration::miles () const {return m_->miles_;}
bool Configuration::avoid_allcall () const {return m_->avoid_allcall_;}
bool Configuration::spellcheck () const {return m_->spellcheck_;}
bool Configuration::quick_call () const {return m_->quick_call_;}
bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;}
int Configuration::heartbeat () const {return m_->heartbeat_;}
@@ -786,6 +796,7 @@ bool Configuration::x2ToneSpacing() const {return m_->x2ToneSpacing_;}
bool Configuration::x4ToneSpacing() const {return m_->x4ToneSpacing_;}
bool Configuration::split_mode () const {return m_->split_mode ();}
QString Configuration::opCall() const {return m_->opCall_;}
QString Configuration::ptt_command() const { return m_->ptt_command_.trimmed();}
QString Configuration::aprs_server_name () const {return m_->aprs_server_name_;}
auto Configuration::aprs_server_port () const -> port_type {return m_->aprs_server_port_;}
QString Configuration::aprs_passcode() const { return m_->aprs_passcode_; }
@@ -810,6 +821,7 @@ QStringListModel * Configuration::macros () {return &m_->macros_;}
QStringListModel const * Configuration::macros () const {return &m_->macros_;}
QDir Configuration::save_directory () const {return m_->save_directory_;}
QDir Configuration::azel_directory () const {return m_->azel_directory_;}
QString Configuration::sound_cq_path() const {return m_->sound_cq_path_;}
QString Configuration::sound_dm_path() const {return m_->sound_dm_path_;}
QString Configuration::sound_am_path() const {return m_->sound_am_path_;}
QString Configuration::rig_name () const {return m_->rig_params_.rig_name;}
@@ -894,6 +906,18 @@ void Configuration::transceiver_ptt (bool on)
#endif
m_->transceiver_ptt (on);
auto cmd = ptt_command();
if(!cmd.isEmpty()){
auto p = new QProcess(this);
if(cmd.contains("%1")){
cmd = cmd.arg(on ? "\"on\"" : "\"off\"");
} else {
cmd.append(" ");
cmd.append(on ? "\"on\"" : "\"off\"");
}
p->startDetached(cmd);
}
}
void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_split)
@@ -940,6 +964,24 @@ QSet<QString> Configuration::my_groups() const {
return QSet<QString>::fromList(m_->my_groups_);
}
void Configuration::addGroup(QString const &group){
QSet<QString> groups = my_groups();
groups.insert(group.trimmed());
m_->my_groups_ = groups.toList();
m_->write_settings();
}
void Configuration::removeGroup(QString const &group){
QSet<QString> groups = my_groups();
groups.remove(group.trimmed());
m_->my_groups_ = groups.toList();
m_->write_settings();
}
QSet<QString> Configuration::auto_whitelist() const {
return QSet<QString>::fromList(m_->auto_whitelist_);
}
QString Configuration::my_qth() const
{
return m_->my_qth_.trimmed();
@@ -1009,6 +1051,12 @@ namespace
}
}
template <typename T> void setUppercase(T* t){
auto f = t->font();
f.setCapitalization(QFont::AllUppercase);
t->setFont(f);
}
Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
QSettings * settings, QWidget * parent)
: QDialog {parent}
@@ -1042,6 +1090,7 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
, default_audio_output_device_selected_ {false}
{
ui_->setupUi (this);
// ui_->groupBox_6->setVisible(false); //### Temporary ??? ###
{
@@ -1117,6 +1166,17 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
ui_->qth_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->reply_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->cq_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->groups_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
setUppercase(ui_->callsign_line_edit);
setUppercase(ui_->grid_line_edit);
setUppercase(ui_->add_macro_line_edit);
setUppercase(ui_->station_message_line_edit);
setUppercase(ui_->qth_message_line_edit);
setUppercase(ui_->reply_message_line_edit);
setUppercase(ui_->cq_message_line_edit);
setUppercase(ui_->groups_line_edit);
setUppercase(ui_->auto_whitelist_line_edit);
ui_->udp_server_port_spin_box->setMinimum (1);
ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
@@ -1307,6 +1367,7 @@ void Configuration::impl::initialize_models ()
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_->auto_whitelist_line_edit->setText(auto_whitelist_.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());
@@ -1331,6 +1392,7 @@ void Configuration::impl::initialize_models ()
ui_->PTT_method_button_group->button (rig_params_.ptt_type)->setChecked (true);
ui_->save_path_display_label->setText (save_directory_.absolutePath ());
ui_->azel_path_display_label->setText (azel_directory_.absolutePath ());
ui_->sound_cq_path_display_label->setText(sound_cq_path_);
ui_->sound_dm_path_display_label->setText(sound_dm_path_);
ui_->sound_am_path_display_label->setText(sound_am_path_);
ui_->CW_id_after_73_check_box->setChecked (id_after_73_);
@@ -1346,8 +1408,10 @@ 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_->clear_DX_check_box->setChecked (clear_DX_);
ui_->clear_callsign_check_box->setChecked (clear_callsign_);
ui_->miles_check_box->setChecked (miles_);
ui_->avoid_allcall_checkbox->setChecked(avoid_allcall_);
ui_->spellcheck_check_box->setChecked(spellcheck_);
ui_->quick_call_check_box->setChecked (quick_call_);
ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_);
ui_->heartbeat_spin_box->setValue (heartbeat_);
@@ -1389,6 +1453,7 @@ void Configuration::impl::initialize_models ()
ui_->TX_audio_source_button_group->button (rig_params_.audio_source)->setChecked (true);
ui_->CAT_poll_interval_spin_box->setValue (rig_params_.poll_interval);
ui_->opCallEntry->setText (opCall_);
ui_->ptt_command_line_edit->setText(ptt_command_);
ui_->aprs_server_line_edit->setText (aprs_server_name_);
ui_->aprs_server_port_spin_box->setValue (aprs_server_port_);
ui_->aprs_passcode_line_edit->setText(aprs_passcode_);
@@ -1430,7 +1495,7 @@ void Configuration::impl::done (int r)
{
// do this here since window is still on screen at this point
SettingsGroup g {settings_, "Configuration"};
settings_->setValue ("window/geometry", saveGeometry ());
settings_->setValue ("WindowGeometry", saveGeometry ());
QDialog::done (r);
}
@@ -1438,13 +1503,16 @@ void Configuration::impl::done (int r)
void Configuration::impl::read_settings ()
{
SettingsGroup g {settings_, "Configuration"};
restoreGeometry (settings_->value ("window/geometry").toByteArray ());
setMinimumSize(800, 400);
restoreGeometry (settings_->value ("WindowGeometry").toByteArray ());
setMinimumSize(800, 400);
auto_switch_bands_ = settings_->value("AutoSwitchBands", false).toBool();
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();
auto_whitelist_ = settings_->value("AutoWhitelist", QStringList{}).toStringList();
callsign_aging_ = settings_->value ("CallsignAging", 0).toInt ();
activity_aging_ = settings_->value ("ActivityAging", 2).toInt ();
my_qth_ = settings_->value("MyQTH", QString {}).toString();
@@ -1533,6 +1601,7 @@ void Configuration::impl::read_settings ()
RxBandwidth_ = settings_->value ("RxBandwidth", 2500).toInt ();
save_directory_ = settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString ();
azel_directory_ = settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ();
sound_cq_path_ = settings_->value ("SoundCQPath", "").toString ();
sound_dm_path_ = settings_->value ("SoundDMPath", "").toString ();
sound_am_path_ = settings_->value ("SoundAMPath", "").toString ();
@@ -1653,8 +1722,10 @@ void Configuration::impl::read_settings ()
insert_blank_ = settings_->value ("InsertBlank", false).toBool ();
DXCC_ = settings_->value ("DXCCEntity", false).toBool ();
ppfx_ = settings_->value ("PrincipalPrefix", false).toBool ();
clear_DX_ = settings_->value ("ClearCallGrid", false).toBool ();
clear_callsign_ = settings_->value ("ClearCallGrid", false).toBool ();
miles_ = settings_->value ("Miles", false).toBool ();
avoid_allcall_ = settings_->value ("AvoidAllcall", false).toBool ();
spellcheck_ = settings_->value ("Spellcheck", true).toBool();
quick_call_ = settings_->value ("QuickCall", false).toBool ();
disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool ();
heartbeat_ = settings_->value ("TxBeacon", 30).toInt ();
@@ -1674,6 +1745,7 @@ void Configuration::impl::read_settings ()
rig_params_.poll_interval = settings_->value ("Polling", 0).toInt ();
rig_params_.split_mode = settings_->value ("SplitMode", QVariant::fromValue (TransceiverFactory::split_mode_none)).value<TransceiverFactory::SplitMode> ();
opCall_ = settings_->value ("OpCall", "").toString ();
ptt_command_ = settings_->value("PTTCommand", "").toString();
aprs_server_name_ = settings_->value ("aprsServer", "rotate.aprs2.net").toString ();
aprs_server_port_ = settings_->value ("aprsServerPort", 14580).toUInt ();
aprs_passcode_ = settings_->value ("aprsPasscode", "").toString();
@@ -1701,6 +1773,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("MyGrid", my_grid_);
settings_->setValue ("MyStation", my_station_);
settings_->setValue ("MyGroups", my_groups_);
settings_->setValue ("AutoWhitelist", auto_whitelist_);
settings_->setValue ("MyQTH", my_qth_);
settings_->setValue ("CQMessage", cq_);
settings_->setValue ("Reply", reply_);
@@ -1736,6 +1809,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("PTTport", rig_params_.ptt_port);
settings_->setValue ("SaveDir", save_directory_.absolutePath ());
settings_->setValue ("AzElDir", azel_directory_.absolutePath ());
settings_->setValue ("SoundCQPath", sound_cq_path_);
settings_->setValue ("SoundDMPath", sound_dm_path_);
settings_->setValue ("SoundAMPath", sound_am_path_);
@@ -1787,8 +1861,10 @@ void Configuration::impl::write_settings ()
settings_->setValue ("InsertBlank", insert_blank_);
settings_->setValue ("DXCCEntity", DXCC_);
settings_->setValue ("PrincipalPrefix", ppfx_);
settings_->setValue ("ClearCallGrid", clear_DX_);
settings_->setValue ("ClearCallGrid", clear_callsign_);
settings_->setValue ("Miles", miles_);
settings_->setValue ("AvoidAllcall", avoid_allcall_);
settings_->setValue ("Spellcheck", spellcheck_);
settings_->setValue ("QuickCall", quick_call_);
settings_->setValue ("73TxDisable", disable_TX_on_73_);
settings_->setValue ("TxBeacon", heartbeat_);
@@ -1810,6 +1886,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("x2ToneSpacing", x2ToneSpacing_);
settings_->setValue ("x4ToneSpacing", x4ToneSpacing_);
settings_->setValue ("OpCall", opCall_);
settings_->setValue ("PTTCommand", ptt_command_);
settings_->setValue ("aprsServer", aprs_server_name_);
settings_->setValue ("aprsServerPort", aprs_server_port_);
settings_->setValue ("aprsPasscode", aprs_passcode_);
@@ -1880,7 +1957,8 @@ void Configuration::impl::set_rig_invariants ()
// makes no sense with rig as "None"
ui_->monitor_last_used_check_box->setEnabled (false);
ui_->CAT_control_group_box->setEnabled (false);
ui_->catTab->setEnabled(false);
//ui_->CAT_control_group_box->setEnabled (false);
ui_->test_CAT_push_button->setEnabled (false);
ui_->test_PTT_push_button->setEnabled (TransceiverFactory::PTT_method_DTR == ptt_method
|| TransceiverFactory::PTT_method_RTS == ptt_method);
@@ -1889,7 +1967,8 @@ void Configuration::impl::set_rig_invariants ()
else
{
ui_->monitor_last_used_check_box->setEnabled (true);
ui_->CAT_control_group_box->setEnabled (true);
ui_->catTab->setEnabled(true);
//ui_->CAT_control_group_box->setEnabled (true);
ui_->test_CAT_push_button->setEnabled (true);
ui_->test_PTT_push_button->setEnabled (false);
ui_->TX_audio_source_group_box->setEnabled (transceiver_factory_.has_CAT_PTT_mic_data (rig) && TransceiverFactory::PTT_method_CAT == ptt_method);
@@ -1940,7 +2019,9 @@ void Configuration::impl::set_rig_invariants ()
break;
}
}
ui_->CAT_serial_port_parameters_group_box->setEnabled (is_serial_CAT);
ui_->force_DTR_combo_box->setEnabled (is_serial_CAT
&& (cat_port != ptt_port
|| !ui_->PTT_DTR_radio_button->isEnabled ()
@@ -1969,27 +2050,54 @@ QStringList splitGroups(QString groupsString, bool filter){
if(filter && !g.startsWith("@")){
continue;
}
groups.append(group.trimmed());
groups.append(group.trimmed().toUpper());
}
return groups;
}
QStringList splitCalls(QString callsString){
QStringList calls;
if(callsString.isEmpty()){
return calls;
}
foreach(QString call, callsString.split(",")){
auto g = call.trimmed();
calls.append(call.trimmed().toUpper());
}
return calls;
}
bool Configuration::impl::validate ()
{
auto callsign = ui_->callsign_line_edit->text().trimmed();
auto callsign = ui_->callsign_line_edit->text().toUpper().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)){
foreach(auto group, splitGroups(ui_->groups_line_edit->text().toUpper().trimmed(), false)){
if(!Varicode::isCompoundCallsign(group)){
MessageBox::critical_message (this, QString("%1 is not a valid group").arg(group));
return false;
}
}
foreach(auto call, splitCalls(ui_->auto_whitelist_line_edit->text().toUpper().trimmed())){
if(!Varicode::isValidCallsign(call, nullptr)){
MessageBox::critical_message (this, QString("%1 is not a valid callsign to whitelist").arg(call));
return false;
}
}
auto cq = ui_->cq_message_line_edit->text().toUpper().trimmed();
if(!cq.isEmpty() && !(cq.startsWith("CQ") || cq.contains(callsign))){
MessageBox::critical_message (this, QString("The CQ message format is invalid. It must either start with \"CQ\" or contain your callsign."));
return false;
}
if (ui_->sound_input_combo_box->currentIndex () < 0
&& !QAudioDeviceInfo::availableDevices (QAudio::AudioInput).empty ())
{
@@ -2238,12 +2346,11 @@ void Configuration::impl::accept ()
Q_ASSERT (audio_output_channel_ <= AudioDevice::Both);
auto_switch_bands_ = ui_->auto_switch_bands_check_box->isChecked();
my_callsign_ = ui_->callsign_line_edit->text ();
my_grid_ = ui_->grid_line_edit->text ();
my_callsign_ = ui_->callsign_line_edit->text ().toUpper();
my_grid_ = ui_->grid_line_edit->text ().toUpper();
my_station_ = ui_->station_message_line_edit->text().toUpper();
my_groups_ = splitGroups(ui_->groups_line_edit->text().toUpper().trimmed(), true);
auto_whitelist_ = splitCalls(ui_->auto_whitelist_line_edit->text().toUpper().trimmed());
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();
@@ -2268,8 +2375,10 @@ 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 ();
clear_DX_ = ui_->clear_DX_check_box->isChecked ();
clear_callsign_ = ui_->clear_callsign_check_box->isChecked ();
miles_ = ui_->miles_check_box->isChecked ();
avoid_allcall_ = ui_->avoid_allcall_checkbox->isChecked();
spellcheck_ = ui_->spellcheck_check_box->isChecked();
quick_call_ = ui_->quick_call_check_box->isChecked ();
disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked ();
heartbeat_ = ui_->heartbeat_spin_box->value ();
@@ -2277,6 +2386,7 @@ void Configuration::impl::accept ()
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 ();
sound_cq_path_ = ui_->sound_cq_path_display_label->text();
sound_dm_path_ = ui_->sound_dm_path_display_label->text();
sound_am_path_ = ui_->sound_am_path_display_label->text();
enable_VHF_features_ = ui_->enable_VHF_features_check_box->isChecked ();
@@ -2292,7 +2402,7 @@ void Configuration::impl::accept ()
pwrBandTxMemory_ = ui_->checkBoxPwrBandTxMemory->isChecked ();
pwrBandTuneMemory_ = ui_->checkBoxPwrBandTuneMemory->isChecked ();
opCall_=ui_->opCallEntry->text();
ptt_command_ = ui_->ptt_command_line_edit->text();
aprs_server_name_ = ui_->aprs_server_line_edit->text();
aprs_server_port_ = ui_->aprs_server_port_spin_box->value();
aprs_passcode_ = ui_->aprs_passcode_line_edit->text();
@@ -2668,43 +2778,23 @@ void Configuration::impl::on_sound_output_combo_box_currentTextChanged (QString
void Configuration::impl::on_station_message_line_edit_textChanged(QString const &text)
{
QString upper = text.toUpper();
if(text != upper){
ui_->station_message_line_edit->setText (upper);
}
}
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();
if(text != upper){
ui_->qth_message_line_edit->setText (upper);
}
}
void Configuration::impl::on_cq_message_line_edit_textChanged(QString const &text)
{
QString upper = text.toUpper();
if(text != upper){
ui_->cq_message_line_edit->setText (upper);
}
}
void Configuration::impl::on_reply_message_line_edit_textChanged(QString const &text)
{
QString upper = text.toUpper();
if(text != upper){
ui_->reply_message_line_edit->setText (upper);
}
}
void Configuration::impl::on_add_macro_line_edit_editingFinished ()
@@ -2763,7 +2853,7 @@ void Configuration::impl::on_add_macro_push_button_clicked (bool /* checked */)
{
auto index = next_macros_.index (next_macros_.rowCount () - 1);
ui_->macros_list_view->setCurrentIndex (index);
next_macros_.setData (index, ui_->add_macro_line_edit->text ());
next_macros_.setData (index, ui_->add_macro_line_edit->text ().toUpper());
ui_->add_macro_line_edit->clear ();
}
}
@@ -2945,6 +3035,37 @@ void Configuration::impl::on_azel_path_select_push_button_clicked (bool /* check
}
}
void Configuration::impl::on_sound_cq_path_select_push_button_clicked(){
QStringList filters;
filters << "Audio files (*.wav)"
<< "Any files (*)";
QFileDialog fd {this, tr ("Sound File"), ui_->sound_cq_path_display_label->text ()};
fd.setNameFilters(filters);
if (fd.exec ()) {
if (fd.selectedFiles ().size ()) {
if(rig_params_.ptt_type == TransceiverFactory::PTT_method_VOX){
QMessageBox::warning(this, "Notifications Sounds Warning", "You have enabled notification sounds while using VOX. To avoid transmitting these notification sounds, please make sure your rig is using a different sound card than your system.");
}
ui_->sound_cq_path_display_label->setText(fd.selectedFiles().at(0));
}
}
}
void Configuration::impl::on_sound_cq_path_test_push_button_clicked(){
auto path = ui_->sound_cq_path_display_label->text();
if(path.isEmpty()){
return;
}
QSound::play(path);
}
void Configuration::impl::on_sound_cq_path_reset_push_button_clicked(){
ui_->sound_cq_path_display_label->clear();
}
void Configuration::impl::on_sound_dm_path_select_push_button_clicked(){
QStringList filters;
filters << "Audio files (*.wav)"
+10 -3
View File
@@ -26,7 +26,7 @@ class QHostAddress;
// Class Configuration
//
// Encapsulates the control, access and, persistence of user defined
// settings for the wsjtx GUI. Setting values are accessed through a
// settings for the GUI. Setting values are accessed through a
// QDialog window containing concept orientated tab windows.
//
// Responsibilities
@@ -37,7 +37,7 @@ class QHostAddress;
// farmed out to a separate thread since many of the rig control
// functions are blocking.
//
// All user settings required by the wsjtx GUI are exposed through
// All user settings required by the GUI are exposed through
// query methods. Settings only become visible once they have been
// accepted by the user which is done by clicking the "OK" button on
// the settings dialog.
@@ -99,6 +99,9 @@ public:
QString my_grid () const;
QString my_station () const;
QSet<QString> my_groups() const;
void addGroup(QString const &group);
void removeGroup(QString const &group);
QSet<QString> auto_whitelist() const;
int activity_aging() const;
int callsign_aging() const;
QString my_qth () const;
@@ -131,8 +134,10 @@ public:
bool insert_blank () const;
bool DXCC () const;
bool ppfx() const;
bool clear_DX () const;
bool clear_callsign () const;
bool miles () const;
bool avoid_allcall () const;
bool spellcheck() const;
bool quick_call () const;
bool disable_TX_on_73 () const;
int heartbeat () const;
@@ -155,6 +160,7 @@ public:
bool EMEonly() const;
bool post_decodes () const;
QString opCall() const;
QString ptt_command() const;
QString aprs_server_name () const;
port_type aprs_server_port () const;
QString aprs_passcode () const;
@@ -180,6 +186,7 @@ public:
QStringListModel const * macros () const;
QDir save_directory () const;
QDir azel_directory () const;
QString sound_cq_path() const;
QString sound_dm_path() const;
QString sound_am_path() const;
QString rig_name () const;
+3298 -2852
View File
File diff suppressed because it is too large Load Diff
+8 -1
View File
@@ -50,6 +50,13 @@ 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.
On Debian based systems, install requirements like:
sudo apt install git cmake clang gfortran \
libfftw3-dev git libgfortran3 libusb-1.0-dev autoconf libtool \
texinfo qt5-default qtmultimedia5-dev libqt5multimedia5-plugins libqt5serialport5-dev \
libudev-dev pkg-config
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
@@ -413,4 +420,4 @@ $ cmake --build . --target install
73
Bill
G4WJS.
G4WJS.
+311
View File
@@ -0,0 +1,311 @@
/**
* This file is part of JS8Call.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
*
**/
#include "Inbox.h"
#include <QDebug>
const char* SCHEMA = "CREATE TABLE IF NOT EXISTS inbox_v1 ("
" id INTEGER PRIMARY KEY AUTOINCREMENT, "
" blob TEXT"
");"
"CREATE INDEX IF NOT EXISTS idx_inbox_v1__type ON"
" inbox_v1(json_extract(blob, '$.type'));"
"CREATE INDEX IF NOT EXISTS idx_inbox_v1__params_from ON"
" inbox_v1(json_extract(blob, '$.params.FROM'));"
"CREATE INDEX IF NOT EXISTS idx_inbox_v1__params_to ON"
" inbox_v1(json_extract(blob, '$.params.TO'))";
Inbox::Inbox(QString path) :
path_{ path },
db_{ nullptr }
{
}
Inbox::~Inbox(){
close();
}
/**
* Low-Level Interface
**/
bool Inbox::isOpen(){
return db_ != nullptr;
}
bool Inbox::open(){
int rc = sqlite3_open(path_.toLocal8Bit().data(), &db_);
if(rc != SQLITE_OK){
close();
return false;
}
rc = sqlite3_exec(db_, SCHEMA, nullptr, nullptr, nullptr);
if(rc != SQLITE_OK){
return false;
}
return true;
}
void Inbox::close(){
if(db_){
sqlite3_close(db_);
db_ = nullptr;
}
}
QString Inbox::error(){
if(db_){
return QString::fromLocal8Bit(sqlite3_errmsg(db_));
}
return "";
}
int Inbox::count(QString type, QString query, QString match){
if(!isOpen()){
return -1;
}
const char* sql = "SELECT COUNT(*) FROM inbox_v1 "
"WHERE json_extract(blob, '$.type') = ? "
"AND json_extract(blob, ?) LIKE ?;";
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
if(rc != SQLITE_OK){
return -1;
}
auto t8 = type.toLocal8Bit();
auto q8 = query.toLocal8Bit();
auto m8 = match.toLocal8Bit();
rc = sqlite3_bind_text(stmt, 1, t8.data(), -1, nullptr);
rc = sqlite3_bind_text(stmt, 2, q8.data(), -1, nullptr);
rc = sqlite3_bind_text(stmt, 3, m8.data(), -1, nullptr);
int count = 0;
rc = sqlite3_step(stmt);
if(rc == SQLITE_ROW) {
count = sqlite3_column_int(stmt, 0);
}
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
return -1;
}
return count;
}
QList<QPair<int, Message> > Inbox::values(QString type, QString query, QString match, int offset, int limit){
if(!isOpen()){
return {};
}
const char* sql = "SELECT id, blob FROM inbox_v1 "
"WHERE json_extract(blob, '$.type') = ? "
"AND json_extract(blob, ?) LIKE ? "
"ORDER BY id ASC "
"LIMIT ? OFFSET ?;";
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
if(rc != SQLITE_OK){
return {};
}
auto t8 = type.toLocal8Bit();
auto q8 = query.toLocal8Bit();
auto m8 = match.toLocal8Bit();
rc = sqlite3_bind_text(stmt, 1, t8.data(), -1, nullptr);
rc = sqlite3_bind_text(stmt, 2, q8.data(), -1, nullptr);
rc = sqlite3_bind_text(stmt, 3, m8.data(), -1, nullptr);
rc = sqlite3_bind_int(stmt, 4, limit);
rc = sqlite3_bind_int(stmt, 5, offset);
//qDebug() << "exec" << sqlite3_expanded_sql(stmt);
QList<QPair<int, Message>> v;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
Message m;
int i = sqlite3_column_int(stmt, 0);
auto msg = QByteArray((const char*)sqlite3_column_text(stmt, 1), sqlite3_column_bytes(stmt, 1));
QJsonParseError e;
QJsonDocument d = QJsonDocument::fromJson(msg, &e);
if(e.error != QJsonParseError::NoError){
continue;
}
if(!d.isObject()){
continue;
}
m.read(d.object());
v.append({ i, m });
}
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
return {};
}
return v;
}
Message Inbox::value(int key){
if(!isOpen()){
return {};
}
const char* sql = "SELECT blob FROM inbox_v1 WHERE id = ? LIMIT 1;";
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
if(rc != SQLITE_OK){
return {};
}
rc = sqlite3_bind_int(stmt, 1, key);
Message m;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
auto msg = QByteArray((const char*)sqlite3_column_text(stmt, 0), sqlite3_column_bytes(stmt, 0));
QJsonParseError e;
QJsonDocument d = QJsonDocument::fromJson(msg, &e);
if(e.error != QJsonParseError::NoError){
return {};
}
if(!d.isObject()){
return {};
}
m.read(d.object());
}
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
return {};
}
return m;
}
int Inbox::append(Message value){
if(!isOpen()){
return -1;
}
const char* sql = "INSERT INTO inbox_v1 (blob) VALUES (?);";
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
if(rc != SQLITE_OK){
return -2;
}
auto j8 = value.toJson();
rc = sqlite3_bind_text(stmt, 1, j8.data(), -1, nullptr);
rc = sqlite3_step(stmt);
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
return -1;
}
return sqlite3_last_insert_rowid(db_);
}
bool Inbox::set(int key, Message value){
if(!isOpen()){
return false;
}
const char* sql = "UPDATE inbox_v1 SET blob = ? WHERE id = ?;";
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
if(rc != SQLITE_OK){
return false;
}
auto j8 = value.toJson();
rc = sqlite3_bind_text(stmt, 1, j8.data(), -1, nullptr);
rc = sqlite3_bind_int(stmt, 2, key);
rc = sqlite3_step(stmt);
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
return false;
}
return true;
}
bool Inbox::del(int key){
if(!isOpen()){
return false;
}
const char* sql = "DELETE FROM inbox_v1 WHERE id = ?;";
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
if(rc != SQLITE_OK){
return false;
}
rc = sqlite3_bind_int(stmt, 1, key);
rc = sqlite3_step(stmt);
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
return false;
}
return true;
}
/**
* High-Level Interface
**/
int Inbox::countUnreadFrom(QString from){
return count("UNREAD", "$.params.FROM", from);
}
QPair<int, Message> Inbox::firstUnreadFrom(QString from){
auto v = values("UNREAD", "$.params.FROM", from, 0, 1);
if(v.isEmpty()){
return {};
}
return v.first();
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef INBOX_H
#define INBOX_H
/**
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
**/
#include <QObject>
#include <QString>
#include <QPair>
#include <QVariant>
#include "vendor/sqlite3/sqlite3.h"
#include "Message.h"
class Inbox
{
public:
explicit Inbox(QString path);
~Inbox();
// Low-Level Interface
bool isOpen();
bool open();
void close();
QString error();
int count(QString type, QString query, QString match);
QList<QPair<int, Message>> values(QString type, QString query, QString match, int offset, int limit);
Message value(int key);
int append(Message value);
bool set(int key, Message value);
bool del(int key);
// High-Level Interface
int countUnreadFrom(QString from);
QPair<int, Message> firstUnreadFrom(QString from);
signals:
public slots:
private:
QString path_;
sqlite3 * db_;
};
#endif // INBOX_H
+90
View File
@@ -0,0 +1,90 @@
/**
* This file is part of JS8Call.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
*
**/
#include "Message.h"
#include "DriftingDateTime.h"
const quint32 EPOCH = 1499299200000; // July 6, 2017
#if USE_SNOWFLAKE
quint64 snowflake(quint64 epoch, quint16 machine, quint16 sequence){
quint64 value = (DriftingDateTime::currentMSecsSinceEpoch() - epoch) << 22;
value |= machine & 0x3FF << 12;
value |= sequence & 0xFFF;
return value;
}
#endif
Message::Message()
{
}
Message::Message(QString const &type, QString const &value):
type_{ type },
value_{ value }
{
params_["_ID"] = QString::number(DriftingDateTime::currentMSecsSinceEpoch()-EPOCH);
}
Message::Message(QString const &type, QString const &value, QMap<QString, QVariant> const &params):
type_{ type },
value_{ value },
params_{ params }
{
params_["_ID"] = QString::number(DriftingDateTime::currentMSecsSinceEpoch()-EPOCH);
}
void Message::read(const QJsonObject &json){
if(json.contains("type") && json["type"].isString()){
type_ = json["type"].toString();
}
if(json.contains("value") && json["value"].isString()){
value_ = json["value"].toString();
}
if(json.contains("params") && json["params"].isObject()){
params_.clear();
QJsonObject params = json["params"].toObject();
foreach(auto key, params.keys()){
params_[key] = params[key].toVariant();
}
}
}
void Message::write(QJsonObject &json) const{
json["type"] = type_;
json["value"] = value_;
QJsonObject params;
foreach(auto key, params_.keys()){
params.insert(key, QJsonValue::fromVariant(params_[key]));
}
json["params"] = params;
}
QByteArray Message::toJson() const {
QJsonObject o;
write(o);
QJsonDocument d(o);
return d.toJson(QJsonDocument::Compact);
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef MESSAGE_H
#define MESSAGE_H
/**
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
**/
#include <QMap>
#include <QByteArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QString>
#include <QVariant>
class Message {
public:
Message();
Message(QString const &type, QString const &value="");
Message(QString const &type, QString const &value, QMap<QString, QVariant> const &params);
void read(const QJsonObject &json);
void write(QJsonObject &json) const;
QByteArray toJson() const;
QString type() const { return type_; }
void setType(QString type){ type_ = type; }
QString value() const { return value_; }
void setValue(QString value){ value_ = value; }
QMap<QString, QVariant> params() const { return params_; }
private:
QString type_;
QString value_;
QMap<QString, QVariant> params_;
};
#endif // MESSAGE_H
-55
View File
@@ -19,61 +19,6 @@
#include "moc_MessageClient.cpp"
Message::Message()
{
}
Message::Message(QString const &type, QString const &value):
type_{ type },
value_{ value }
{
}
Message::Message(QString const &type, QString const &value, QMap<QString, QVariant> const &params):
type_{ type },
value_{ value },
params_{ params }
{
}
void Message::read(const QJsonObject &json){
if(json.contains("type") && json["type"].isString()){
type_ = json["type"].toString();
}
if(json.contains("value") && json["value"].isString()){
value_ = json["value"].toString();
}
if(json.contains("params") && json["params"].isObject()){
params_.clear();
QJsonObject params = json["params"].toObject();
foreach(auto key, params.keys()){
params_[key] = params[key].toVariant();
}
}
}
void Message::write(QJsonObject &json) const{
json["type"] = type_;
json["value"] = value_;
QJsonObject params;
foreach(auto key, params_.keys()){
params.insert(key, QJsonValue::fromVariant(params_[key]));
}
json["params"] = params;
}
QByteArray Message::toJson() const {
QJsonObject o;
write(o);
QJsonDocument d(o);
return d.toJson();
}
class MessageClient::impl
: public QUdpSocket
+1 -25
View File
@@ -6,9 +6,8 @@
#include <QDataStream>
#include <QDateTime>
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
#include "Message.h"
#include "Radio.hpp"
#include "pimpl_h.hpp"
@@ -16,29 +15,6 @@ class QByteArray;
class QHostAddress;
class QColor;
class Message {
public:
Message();
Message(QString const &type, QString const &value="");
Message(QString const &type, QString const &value, QMap<QString, QVariant> const &params);
void read(const QJsonObject &json);
void write(QJsonObject &json) const;
QByteArray toJson() const;
QString type() const { return type_; }
QString value() const { return value_; }
QMap<QString, QVariant> params() const { return params_; }
private:
QString type_;
QString value_;
QMap<QString, QVariant> params_;
};
//
// MessageClient - Manage messages sent and replies received from a
// matching server (MessageServer) at the other end of
+7 -1
View File
@@ -10,10 +10,12 @@ JS8Call is an experiment to test the feasibility of a digital mode with the robu
* For release announcements and discussion, join the JS8Call mailing list here: https://groups.io/g/js8call
* Documentation is available here: https://docs.google.com/document/d/159S4wqMUVdMA7qBgaSWmU-iDI4C9wd4CuWnetN68O9U/edit?pli=1#heading=h.kfnyge37yfr
# Notice
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/
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/js8call/
# History
@@ -33,3 +35,7 @@ JS8Call is a derivative of the WSJT-X application, restructured and redesigned f
* 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
* October 8, 2018 - Version 0.7 released - 6000 testers, name changed to JS8 & JS8Call
* October 31, 2018 - Version 0.8 released - ~7000 testers
* November 15, 2018 - Version 0.9 released - ~7500 testers
* November 30, 2018 - Version 0.10 released - ~7800 testers
+1 -2
View File
@@ -11,8 +11,7 @@ class QString;
//
// Abstract Transceiver Interface
//
// This is the minimal generic interface to a rig as required by
// wsjtx.
// This is the minimal generic interface to a rig.
//
// Responsibilities
//
+2 -2
View File
@@ -1,6 +1,6 @@
# Version number components
set (WSJTX_VERSION_MAJOR 0)
set (WSJTX_VERSION_MINOR 8)
set (WSJTX_VERSION_PATCH 2)
set (WSJTX_VERSION_MINOR 13)
set (WSJTX_VERSION_PATCH 0)
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 -3
View File
@@ -31,7 +31,7 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"community.<br /><br />"
"JS8Call stands on the shoulder of giants...the takeoff angle "
"is better up there.<br /><br />"
"A special thanks goes out to the JS8Call development team:<br/><br/><strong>"
"A special thanks goes out to:<br/><br/><strong>"
"KC9QNE, "
"KI6SSI, "
"K0OG, "
@@ -41,8 +41,8 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"OH8STN, "
"VA3OSO, "
"VK1MIC, "
"W0FW,</strong><br/><br/>and the many other amateur radio operators who have given "
"JS8Call a chance.");
"W0FW,</strong><br/><br/>and the many other amateur radio operators who have helped<br/>"
"bring JS8Call into the world.");
}
CAboutDlg::~CAboutDlg()
+4 -9
View File
@@ -126,7 +126,7 @@ bool DecodedText::tryUnpackHeartbeat(){
// Heartbeat Alt Type
// ---------------
// 1 0 BCN
// 1 0 HB
// 1 1 CQ
isHeartbeat_ = true;
isAlt_ = isAlt;
@@ -140,7 +140,7 @@ bool DecodedText::tryUnpackHeartbeat(){
cmp.append(parts.at(1));
}
compound_ = cmp.join("/");
message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? Varicode::cqString(bits3) : "HEARTBEAT").arg(extra_);
message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? Varicode::cqString(bits3) : Varicode::hbString(bits3)).arg(extra_);
frameType_ = type;
return true;
}
@@ -221,19 +221,14 @@ bool DecodedText::tryUnpackData(){
return false;
}
if((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData){
return false;
}
quint8 type = Varicode::FrameUnknown;
QString data = Varicode::unpackDataMessage(m, &type);
QString data = Varicode::unpackDataMessage(m);
if(data.isEmpty()){
return false;
}
message_ = data;
frameType_ = type;
frameType_ = Varicode::FrameData;
return true;
}
+13
View File
@@ -137,8 +137,14 @@ QString JSC::decompress(Codeword const& bitvec){
k++;
}
if(start + k >= bytes.length()){
break;
}
j = j*s + bytes[start + k] + base[k];
if(j >= (int)JSC::size){
break;
}
auto word = QString(JSC::map[j].str);
out.append(word);
@@ -153,6 +159,13 @@ QString JSC::decompress(Codeword const& bitvec){
return out.join("");
}
bool JSC::exists(QString w, quint32 *pIndex){
bool found = false;
quint32 index = lookup(w, &found);
if(pIndex) *pIndex = index;
return found && JSC::map[index].size == w.length();
}
quint32 JSC::lookup(QString w, bool * ok){
if(LOOKUP_CACHE.contains(w)){
if(ok) *ok = true;
+1
View File
@@ -32,6 +32,7 @@ public:
static QList<CodewordPair> compress(QString text);
static QString decompress(Codeword const& bits);
static bool exists(QString w, quint32 *pIndex);
static quint32 lookup(QString w, bool *ok);
static quint32 lookup(char const* b, bool *ok);
+238
View File
@@ -0,0 +1,238 @@
/**
* This file is part of JS8Call.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
*
**/
#include "jsc_checker.h"
#include <QTextEdit>
#include <QTextBlock>
#include <QTextCursor>
#include <QTextDocument>
#include <QTextLayout>
#include <QDebug>
#include "jsc.h"
#include "varicode.h"
const int CORRECT = QTextFormat::UserProperty + 10;
const QString ALPHABET = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" };
JSCChecker::JSCChecker(QObject *parent) :
QObject(parent)
{
}
bool cursorHasProperty(const QTextCursor &cursor, int property){
if(property < QTextFormat::UserProperty) {
return false;
}
if(cursor.charFormat().intProperty(property) == 1) {
return true;
}
const QList<QTextLayout::FormatRange>& formats = cursor.block().layout()->additionalFormats();
int pos = cursor.positionInBlock();
foreach(const QTextLayout::FormatRange& range, formats) {
if(pos > range.start && pos <= range.start + range.length && range.format.intProperty(property) == 1) {
return true;
}
}
return false;
}
QString nextChar(QTextCursor c){
QTextCursor cur(c);
cur.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
return cur.selectedText();
}
bool isNumeric(QString s){
return s.indexOf(QRegExp("^\\d+$")) == 0;
}
bool isWordChar(QString ch){
return ch.contains(QRegExp("^\\w$"));
}
void JSCChecker::checkRange(QTextEdit* edit, int start, int end)
{
if(end == -1){
QTextCursor tmpCursor(edit->textCursor());
tmpCursor.movePosition(QTextCursor::End);
end = tmpCursor.position();
}
// stop contentsChange signals from being emitted due to changed charFormats
edit->document()->blockSignals(true);
qDebug() << "checking range " << start << " - " << end;
QTextCharFormat errorFmt;
errorFmt.setFontUnderline(true);
errorFmt.setUnderlineColor(Qt::red);
errorFmt.setUnderlineStyle(QTextCharFormat::WaveUnderline);
QTextCharFormat defaultFormat = QTextCharFormat();
auto cursor = edit->textCursor();
cursor.beginEditBlock();
{
cursor.setPosition(start);
while(cursor.position() < end) {
bool correct = false;
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
if(cursor.selectedText() == "@"){
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
}
if(cursorHasProperty(cursor, CORRECT)){
correct = true;
} else {
QString word = cursor.selectedText();
// three or less is always "correct"
if(word.length() < 4 || isNumeric(word)){
correct = true;
} else {
bool found = false;
quint32 index = JSC::lookup(word, &found);
if(found){
correct = JSC::map[index].size == word.length();
}
if(!correct){
correct = Varicode::isValidCallsign(word, nullptr);
}
}
}
if(correct){
QTextCharFormat fmt = cursor.charFormat();
fmt.setFontUnderline(defaultFormat.fontUnderline());
fmt.setUnderlineColor(defaultFormat.underlineColor());
fmt.setUnderlineStyle(defaultFormat.underlineStyle());
cursor.setCharFormat(fmt);
} else {
cursor.mergeCharFormat(errorFmt);
}
// Go to next word start
//while(cursor.position() < end && !isWordChar(nextChar(cursor))){
// cursor.movePosition(QTextCursor::NextCharacter);
//}
cursor.movePosition(QTextCursor::NextCharacter);
}
}
cursor.endEditBlock();
edit->document()->blockSignals(false);
}
QSet<QString> oneEdit(QString word, bool includeAdditions, bool includeDeletions){
QSet<QString> all;
// 1-edit distance words (i.e., prefixed/suffixed/edited characters)
for(int i = 0; i < 26; i++){
if(includeAdditions){
auto prefixed = ALPHABET.mid(i, 1) + word;
all.insert(prefixed);
auto suffixed = word + ALPHABET.mid(i, 1);
all.insert(suffixed);
}
for(int j = 0; j < word.length(); j++){
auto edited = word.mid(0, j) + ALPHABET.mid(i, 1) + word.mid(j + 1, word.length() - j);
all.insert(edited);
}
}
// 1-edit distance words (i.e., removed characters)
if(includeDeletions){
for(int j = 0; j < word.length(); j++){
auto deleted = word.mid(0, j) + word.mid(j + 1, word.length() - j);
all.insert(deleted);
}
}
return all;
}
QMap<quint32, QString> candidates(QString word, bool includeTwoEdits){
// one edit
QSet<QString> one = oneEdit(word, true, true);
// two edits
QSet<QString> two;
if(includeTwoEdits){
foreach(auto w, one){
two |= oneEdit(w, false, false);
}
}
// existence check
QMap<quint32, QString> m;
quint32 index;
foreach(auto w, one | two){
if(JSC::exists(w, &index)){
m[index] = w;
}
}
return m;
}
QStringList JSCChecker::suggestions(QString word, int n, bool *pFound){
QStringList s;
qDebug() << "computing suggestions for word" << word;
QMap<quint32, QString> m;
bool prefixFound = false;
// lookup actual word prefix that is not a single character
quint32 index = JSC::lookup(word, &prefixFound);
if(prefixFound){
auto t = JSC::map[index];
if(t.size > 1){
m[index] = QString::fromLatin1(t.str, t.size);
}
}
// compute suggestion candidates
m.unite(candidates(word, false));
// return in order of probability (i.e., index rank)
int i = 0;
foreach(auto key, m.uniqueKeys()){
if(i >= n){
break;
}
qDebug() << "suggest" << m[key] << key;
s.append(m[key]);
i++;
}
if(pFound) *pFound = prefixFound;
return s;
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef JSC_CHECKER_H
#define JSC_CHECKER_H
/**
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
**/
#include <QObject>
class QTextEdit;
class JSCChecker : public QObject
{
Q_OBJECT
public:
explicit JSCChecker(QObject *parent = nullptr);
static void checkRange(QTextEdit * edit, int start, int end);
static QStringList suggestions(QString word, int n, bool *pFound);
signals:
public slots:
private:
};
#endif // JSC_CHECKER_H
+15
View File
@@ -27,3 +27,18 @@ bool EnterKeyPressEater::eventFilter(QObject *obj, QEvent *event){
// standard event processing
return QObject::eventFilter(obj, event);
}
bool MousePressEater::eventFilter(QObject *obj, QEvent *event){
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
bool processed = false;
emit this->mousePressed(obj, mouseEvent, &processed);
if(processed){
return true;
}
}
// standard event processing
return QObject::eventFilter(obj, event);
}
+18
View File
@@ -3,6 +3,7 @@
#include <QObject>
#include <QKeyEvent>
#include <QMouseEvent>
class EscapeKeyPressEater : public QObject
{
@@ -29,5 +30,22 @@ public:
Q_SIGNAL void enterKeyPressed(QObject *obj, QKeyEvent *evt, bool *pProcessed);
};
class MousePressEater : public QObject
{
Q_OBJECT
public:
MousePressEater(){}
virtual ~MousePressEater(){}
protected:
bool eventFilter(QObject *obj, QEvent *event);
public:
Q_SIGNAL void mousePressed(QObject *obj, QMouseEvent *evt, bool *pProcessed);
};
#endif // KEYEATER_H
+49 -49
View File
@@ -48,50 +48,50 @@ subroutine foxgen()
do n=1,nslots
i3b=i3bit(n)
if(i3b.eq.0) then
msg=cmsg(n)(1:22) !Standard FT8 message
else
i1=index(cmsg(n),' ') !Special Fox message
i2=index(cmsg(n),';')
i3=index(cmsg(n),'<')
i4=index(cmsg(n),'>')
msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' '
read(cmsg(n)(i4+2:i4+4),*) irpt
endif
call genft8(msg,mygrid,bcontest,0,msgsent,msgbits,itone)
!if(i3b.eq.0) then
msg=cmsg(n)(1:12) !Standard FT8 message
!else
! i1=index(cmsg(n),' ') !Special Fox message
! i2=index(cmsg(n),';')
! i3=index(cmsg(n),'<')
! i4=index(cmsg(n),'>')
! msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' '
! read(cmsg(n)(i4+2:i4+4),*) irpt
!endif
call genft8(msg,mygrid,bcontest,i3b,msgsent,msgbits,itone)
! print*,'Foxgen:',n,cmsg(n),msgsent
if(i3b.eq.1) then
icrc10=crc10(c_loc(mycall),12)
nrpt=irpt+30
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0
1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12)
read(cbits,1002) msgbits
1002 format(87i1)
cb88=cbits//'0'
read(cb88,1003) i1Msg8BitBytes(1:11)
1003 format(11b8)
icrc12=crc12(c_loc(i1Msg8BitBytes),11)
! icrc12=xor(icrc12, 41) ! TODO: jsherer - could change the crc here
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12
read(cbits,1002) msgbits
call encode174(msgbits,codeword) !Encode the test message
! Message structure: S7 D29 S7 D29 S7
itone(1:7)=icos7
itone(36+1:36+7)=icos7
itone(NN-6:NN)=icos7
k=7
do j=1,ND
i=3*j -2
k=k+1
if(j.eq.30) k=k+7
itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2)
enddo
endif
!! if(i3b.eq.1) then
!! icrc10=crc10(c_loc(mycall),12)
!! nrpt=irpt+30
!! write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0
!! 1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12)
!! read(cbits,1002) msgbits
!! 1002 format(87i1)
!!
!! cb88=cbits//'0'
!! read(cb88,1003) i1Msg8BitBytes(1:11)
!! 1003 format(11b8)
!! icrc12=crc12(c_loc(i1Msg8BitBytes),11)
!! ! icrc12=xor(icrc12, 41) ! TODO: jsherer - could change the crc here
!!
!! write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12
!! read(cbits,1002) msgbits
!!
!! call encode174(msgbits,codeword) !Encode the test message
!!
!! ! Message structure: S7 D29 S7 D29 S7
!! itone(1:7)=icos7
!! itone(36+1:36+7)=icos7
!! itone(NN-6:NN)=icos7
!! k=7
!! do j=1,ND
!! i=3*j -2
!! k=k+1
!! if(j.eq.30) k=k+7
!! itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2)
!! enddo
!! endif
! Make copies of itone() and msgbits() for ft8sim
itone2=itone
@@ -117,13 +117,13 @@ subroutine foxgen()
! call plotspec(1,wave) !Plot the spectrum
! Apply compression
! rms=sqrt(dot_product(wave,wave)/kz)
! wave=wave/rms
! do i=1,NWAVE
! wave(i)=h1(wave(i))
! enddo
! peak2=maxval(abs(wave))
! wave=wave/peak2
rms=sqrt(dot_product(wave,wave)/kz)
wave=wave/rms
do i=1,NWAVE
wave(i)=h1(wave(i))
enddo
peak2=maxval(abs(wave))
wave=wave/peak2
! call plotspec(2,wave) !Plot the spectrum
+10 -21
View File
@@ -100,6 +100,7 @@ void ADIF::load()
add (extractField (record, "CALL")
, extractField (record, "BAND")
, extractField (record, "MODE")
, extractField (record, "SUBMODE")
, extractField (record, "QSO_DATE"));
}
inputFile.close ();
@@ -107,12 +108,13 @@ void ADIF::load()
}
void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& date)
void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& submode, QString const& date)
{
QSO q;
q.call = call;
q.band = band;
q.mode = mode;
q.submode = submode;
q.date = date;
if (q.call.size ())
{
@@ -121,8 +123,8 @@ void ADIF::add(QString const& call, QString const& band, QString const& mode, QS
}
}
// return true if in the log same band and mode (where JT65 == JT9)
bool ADIF::match(QString const& call, QString const& band, QString const& mode) const
// return true if in the log same band
bool ADIF::match(QString const& call, QString const& band) const
{
QList<QSO> qsos = _data.values(call);
if (qsos.size()>0)
@@ -134,22 +136,6 @@ bool ADIF::match(QString const& call, QString const& band, QString const& mode)
|| (band=="")
|| (q.band==""))
{
if (
(
((mode.compare("JT65",Qt::CaseInsensitive)==0) ||
(mode.compare("JT9",Qt::CaseInsensitive)==0) ||
(mode.compare("JS8",Qt::CaseInsensitive)==0) ||
(mode.compare("FT8",Qt::CaseInsensitive)==0))
&&
((q.mode.compare("JT65",Qt::CaseInsensitive)==0) ||
(q.mode.compare("JT9",Qt::CaseInsensitive)==0) ||
(q.mode.compare("JS8",Qt::CaseInsensitive)==0) ||
(q.mode.compare("FT8",Qt::CaseInsensitive)==0))
)
|| (mode.compare(q.mode,Qt::CaseInsensitive)==0)
|| (mode=="")
|| (q.mode=="")
)
return true;
}
}
@@ -176,7 +162,7 @@ int ADIF::getCount() const
return _data.size();
}
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& submode
, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn
, QDateTime const& dateTimeOff, QString const& band, QString const& comments
, QString const& name, QString const& strDialFreq, QString const& m_myCall
@@ -186,6 +172,9 @@ QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QStri
t = "<call:" + QString::number(hisCall.length()) + ">" + hisCall;
t += " <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid;
t += " <mode:" + QString::number(mode.length()) + ">" + mode;
if(!submode.isEmpty()){
t += " <submode:" + QString::number(submode.length()) + ">" + submode;
}
t += " <rst_sent:" + QString::number(rptSent.length()) + ">" + rptSent;
t += " <rst_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd;
t += " <qso_date:8>" + dateTimeOn.date().toString("yyyyMMdd");
@@ -224,7 +213,7 @@ bool ADIF::addQSOToFile(QByteArray const& ADIF_record)
{
QTextStream out(&f2);
if (f2.size()==0)
out << "WSJT-X ADIF Export<eoh>" << endl; // new file
out << "JS8Call ADIF Export<eoh>" << endl; // new file
out << ADIF_record << " <eor>" << endl;
f2.close();
+4 -4
View File
@@ -23,15 +23,15 @@ class ADIF
public:
void init(QString const& filename);
void load();
void add(QString const& call, QString const& band, QString const& mode, QString const& date);
bool match(QString const& call, QString const& band, QString const& mode) const;
void add(QString const& call, QString const& band, QString const& mode, const QString &submode, QString const& date);
bool match(QString const& call, QString const& band) const;
QList<QString> getCallList() const;
int getCount() const;
// open ADIF file and append the QSO details. Return true on success
bool addQSOToFile(QByteArray const& ADIF_record);
QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent
QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& submode, QString const& rptSent
, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff
, QString const& band, QString const& comments, QString const& name
, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid
@@ -41,7 +41,7 @@ class ADIF
private:
struct QSO
{
QString call,band,mode,date;
QString call,band,mode,submode,date;
};
QMultiHash<QString, QSO> _data;
+5 -6
View File
@@ -50,8 +50,8 @@ void LogBook::_setAlreadyWorkedFromLog()
}
}
bool LogBook::hasWorkedBefore(const QString &call, const QString &band, const QString &mode){
return _log.match(call, band, mode);
bool LogBook::hasWorkedBefore(const QString &call, const QString &band){
return _log.match(call, band);
}
void LogBook::match(/*in*/const QString call,
@@ -61,9 +61,8 @@ void LogBook::match(/*in*/const QString call,
{
if (call.length() > 0)
{
QString currentMode = ""; // match any mode
QString currentBand = ""; // match any band
callWorkedBefore = _log.match(call,currentBand,currentMode);
callWorkedBefore = _log.match(call,currentBand);
countryName = _countries.find(call);
if (countryName.length() > 0) // country was found
@@ -76,9 +75,9 @@ void LogBook::match(/*in*/const QString call,
}
}
void LogBook::addAsWorked(const QString call, const QString band, const QString mode, const QString date)
void LogBook::addAsWorked(const QString call, const QString band, const QString mode, const QString submode, const QString date)
{
_log.add(call,band,mode,date);
_log.add(call,band,mode,submode,date);
QString countryName = _countries.find(call);
if (countryName.length() > 0)
_worked.setAsWorked(countryName);
+2 -2
View File
@@ -20,12 +20,12 @@ class LogBook
{
public:
void init();
bool hasWorkedBefore(const QString &call, const QString &band, const QString &mode);
bool hasWorkedBefore(const QString &call, const QString &band);
void match(/*in*/ const QString call,
/*out*/ QString &countryName,
bool &callWorkedBefore,
bool &countryWorkedBefore) const;
void addAsWorked(const QString call, const QString band, const QString mode, const QString date);
void addAsWorked(const QString call, const QString band, const QString mode, const QString submode, const QString date);
private:
CountryDat _countries;
+10 -6
View File
@@ -95,12 +95,16 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
void LogQSO::accept()
{
QString hisCall,hisGrid,mode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band,operator_call;
QString hisCall,hisGrid,mode,submode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band,operator_call;
QString comments,name;
hisCall=ui->call->text().toUpper();
hisGrid=ui->grid->text().toUpper();
mode=ui->mode->text().toUpper();
mode = ui->mode->text().toUpper();
if(mode == "JS8"){
mode="MFSK";
submode="JS8";
}
rptSent=ui->sent->text();
rptRcvd=ui->rcvd->text();
m_dateTimeOn = ui->start_date_time->dateTime ();
@@ -115,10 +119,10 @@ void LogQSO::accept()
//Log this QSO to ADIF file "js8call_log.adi"
QString filename = "js8call_log.adi"; // TODO allow user to set
ADIF adifile;
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("js8call_log.adi");
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (filename);
adifile.init(adifilePath);
QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band
QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, submode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band
, comments, name, strDialFreq, m_myCall, m_myGrid, m_txPower, operator_call)};
if (!adifile.addQSOToFile (ADIF))
{
@@ -148,7 +152,7 @@ void LogQSO::accept()
m_dateTimeOn.time().toString("hh:mm:ss,") +
m_dateTimeOff.date().toString("yyyy-MM-dd,") +
m_dateTimeOff.time().toString("hh:mm:ss,") + hisCall + "," +
hisGrid + "," + strDialFreq + "," + mode +
hisGrid + "," + strDialFreq + "," + (mode == "MFSK" ? "JS8" : mode) +
"," + rptSent + "," + rptRcvd + "," + m_txPower +
"," + comments + "," + name;
QTextStream out(&f);
@@ -157,7 +161,7 @@ void LogQSO::accept()
}
//Clean up and finish logging
Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, rptSent, rptRcvd, m_txPower, comments, name,m_dateTimeOn, operator_call, m_myCall, m_myGrid, ADIF);
Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, submode, rptSent, rptRcvd, m_txPower, comments, name,m_dateTimeOn, operator_call, m_myCall, m_myGrid, ADIF);
QDialog::accept();
}
+1 -1
View File
@@ -40,7 +40,7 @@ public slots:
signals:
void acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid
, Radio::Frequency dial_freq, QString const& mode
, Radio::Frequency dial_freq, QString const& mode, QString const& submode
, QString const& rpt_sent, QString const& rpt_received
, QString const& tx_power, QString const& comments
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
+3
View File
@@ -152,6 +152,9 @@
<height>16777215</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
-1
View File
@@ -107,7 +107,6 @@ int main(int argc, char *argv[])
// that GUI has correct l18n
// Override programs executable basename as application name.
//a.setApplicationName ("WSJT-X");
a.setApplicationName("JS8Call");
a.setApplicationVersion (version ());
+1749 -432
View File
File diff suppressed because it is too large Load Diff
+68 -17
View File
@@ -90,6 +90,7 @@ class Detector;
class MultiSettings;
class EqualizationToolsDialog;
class DecodedText;
class JSCChecker;
using namespace std;
typedef std::function<void()> Callback;
@@ -100,6 +101,7 @@ class MainWindow : public QMainWindow
Q_OBJECT;
struct CallDetail;
struct CommandDetail;
public:
using Frequency = Radio::Frequency;
using FrequencyDelta = Radio::FrequencyDelta;
@@ -130,8 +132,11 @@ public slots:
void msgAvgDecode2();
void fastPick(int x0, int x1, int y);
void playSoundNotification(const QString &path);
bool hasExistingMessageBufferToMe(int *pOffset);
bool hasExistingMessageBuffer(int offset, bool drift, int *pPrevOffset);
void logCallActivity(CallDetail d, bool spot=true);
void logHeardGraph(QString from, QString to);
QString lookupCallInCompoundCache(QString const &call);
void cacheActivity(QString key);
void restoreActivity(QString key);
@@ -144,14 +149,13 @@ public slots:
void prependMessageText(QString text);
void addMessageText(QString text, bool clear=false, bool selectFirstPlaceholder=false);
void enqueueMessage(int priority, QString message, int freq, Callback c);
void enqueueHeartbeat(QString message);
void resetMessage();
void resetMessageUI();
void restoreMessage();
void initializeDummyData();
bool ensureCallsignSet(bool alert=true);
bool ensureSelcalCallsignSelected(bool alert=true);
bool ensureKeyNotStuck(QString const& text);
bool ensureNotIdle();
void createMessage(QString const& text);
void createMessageTransmitQueue(QString const& text);
void resetMessageTransmitQueue();
@@ -170,8 +174,16 @@ private slots:
void on_tx4_editingFinished();
void on_tx5_currentTextChanged (QString const&);
void on_tx6_editingFinished();
void on_menuControl_aboutToShow();
void on_actionEnable_Spotting_toggled(bool checked);
void on_actionEnable_Auto_Reply_toggled(bool checked);
void on_menuWindow_aboutToShow();
void on_actionSetOffset_triggered();
void on_actionShow_Fullscreen_triggered(bool checked);
void on_actionShow_Statusbar_triggered(bool checked);
void on_actionShow_Frequency_Clock_triggered(bool checked);
void on_actionShow_Band_Activity_triggered(bool checked);
void on_actionShow_Band_Heartbeats_and_ACKs_triggered(bool checked);
void on_actionShow_Call_Activity_triggered(bool checked);
void on_actionShow_Waterfall_triggered(bool checked);
void on_actionShow_Waterfall_Controls_triggered(bool checked);
@@ -185,6 +197,7 @@ private slots:
void on_actionAbout_triggered();
void on_autoButton_clicked (bool);
void on_labDialFreq_clicked();
void resetPushButtonToggleText(QPushButton *btn);
void on_monitorTxButton_clicked();
void on_stopTxButton_clicked();
void on_stopButton_clicked();
@@ -265,6 +278,16 @@ private slots:
void on_rbGenMsg_clicked(bool checked);
void on_rbFreeText_clicked(bool checked);
void on_clearAction_triggered(QObject * sender);
void buildFrequencyMenu(QMenu *menu);
void buildHeartbeatMenu(QMenu *menu);
void buildCQMenu(QMenu *menu);
void buildRepeatMenu(QMenu *menu, QPushButton * button, int * interval);
void sendHeartbeat();
void sendHeartbeatAck(QString to, int snr);
void on_hbMacroButton_toggled(bool checked);
void on_hbMacroButton_clicked();
void sendCQ(bool repeat=false);
void on_cqMacroButton_toggled(bool checked);
void on_cqMacroButton_clicked();
void on_replyMacroButton_clicked();
void on_snrMacroButton_clicked();
@@ -281,6 +304,7 @@ private slots:
void buildQueryMenu(QMenu *, QString callsign);
QMap<QString, QString> buildMacroValues();
QString replaceMacros(QString const &text, QMap<QString, QString> values, bool prune);
void buildSuggestionsMenu(QMenu *menu, QTextEdit *edit, const QPoint &point);
void buildSavedMessagesMenu(QMenu *menu);
void buildRelayMenu(QMenu *menu);
QAction* buildRelayAction(QString call);
@@ -291,6 +315,7 @@ private slots:
void on_tableWidgetRXAll_cellClicked(int row, int col);
void on_tableWidgetRXAll_cellDoubleClicked(int row, int col);
void on_tableWidgetRXAll_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
QString generateCallDetail(QString selectedCall);
void on_tableWidgetCalls_cellClicked(int row, int col);
void on_tableWidgetCalls_cellDoubleClicked(int row, int col);
void on_tableWidgetCalls_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
@@ -302,12 +327,8 @@ private slots:
bool prepareNextMessageFrame();
bool isFreqOffsetFree(int f, int bw);
int findFreeFreqOffset(int fmin, int fmax, int bw);
void scheduleHeartbeat(bool first=false);
void pauseHeartbeat();
void unpauseHeartbeat();
void checkHeartbeat();
void prepareHeartbeat();
QString calculateDistance(QString const& grid, int *pDistance=nullptr);
void checkRepeat();
QString calculateDistance(QString const& grid, int *pDistance=nullptr, int *pAzimuth=nullptr);
void on_driftSpinBox_valueChanged(int n);
void on_driftSyncButton_clicked();
void on_driftSyncEndButton_clicked();
@@ -318,10 +339,9 @@ private slots:
void on_tuneButton_clicked (bool);
void on_pbR2T_clicked();
void on_pbT2R_clicked();
void on_heartbeatButton_clicked();
void on_selcalButton_clicked();
void on_turboButton_clicked();
void acceptQSO (QDateTime const&, QString const& call, QString const& grid
, Frequency dial_freq, QString const& mode
, Frequency dial_freq, QString const& mode, QString const& submode
, QString const& rpt_sent, QString const& rpt_received
, QString const& tx_power, QString const& comments
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
@@ -342,6 +362,12 @@ private slots:
void stop_tuning ();
void stopTuneATU();
void auto_tx_mode(bool);
void on_autoReplyButton_toggled(bool checked);
void on_monitorButton_toggled(bool checked);
void on_monitorTxButton_toggled(bool checked);
void on_tuneButton_toggled(bool checked);
void on_spotButton_toggled(bool checked);
void on_actionMessage_averaging_triggered();
void on_actionFox_Log_triggered();
void on_actionInclude_averaging_toggled (bool);
@@ -356,6 +382,7 @@ private slots:
void on_cbCQonly_toggled(bool b);
void on_cbFirst_toggled(bool b);
void on_cbAutoSeq_toggled(bool b);
void emitPTT(bool on);
void networkMessage(Message const &message);
void sendNetworkMessage(QString const &type, QString const &message);
void sendNetworkMessage(QString const &type, QString const &message, const QMap<QString, QVariant> &params);
@@ -648,7 +675,7 @@ private:
QTimer minuteTimer;
QTimer splashTimer;
QTimer p1Timer;
QTimer heartbeatTimer;
QTimer repeatTimer;
QString m_path;
QString m_baseCall;
@@ -707,6 +734,7 @@ private:
QString text;
QString extra;
float tdrift;
QString relayPath;
};
struct ActivityDetail
@@ -731,6 +759,10 @@ private:
QList<ActivityDetail> msgs;
};
int m_bandActivityWidth;
int m_callActivityWidth;
int m_textActivityWidth;
int m_waterfallHeight;
bool m_bandActivityWasVisible;
bool m_rxDirty;
bool m_rxDisplayDirty;
@@ -787,13 +819,19 @@ private:
QMap<int, QList<ActivityDetail>> m_bandActivity; // freq -> [(text, last timestamp), ...]
QMap<int, MessageBuffer> m_messageBuffer; // freq -> (cmd, [frames, ...])
QMap<QString, CallDetail> m_callActivity; // call -> (last freq, last timestamp)
QQueue<QString> m_txHeartbeatQueue; // ping frames to be sent
QMap<QString, QDateTime> m_aprsCallCache;
QMap<QString, QSet<QString>> m_heardGraphOutgoing; // callsign -> [stations who've this callsign has heard]
QMap<QString, QSet<QString>> m_heardGraphIncoming; // callsign -> [stations who've heard this callsign]
QMap<QString, int> m_rxInboxCountCache; // call -> count
QMap<QString, QMap<QString, CallDetail>> m_callActivityCache; // band -> call activity
QMap<QString, QMap<int, QList<ActivityDetail>>> m_bandActivityCache; // band -> band activity
QMap<QString, QString> m_rxTextCache; // band -> rx text
JSCChecker * m_checker;
QSet<QString> m_callSeenHeartbeat; // call
int m_previousFreq;
bool m_shouldRestoreFreq;
@@ -818,9 +856,11 @@ private:
QQueue<QString> m_foxQSOinProgress; //QSOs in progress: Fox has sent a report
QQueue<qint64> m_foxRateQueue;
bool m_nextHeartbeatQueued = false;
bool m_nextHeartPaused = false;
bool m_hbHidden;
int m_hbInterval;
int m_cqInterval;
QDateTime m_nextHeartbeat;
QDateTime m_nextCQ;
QDateTime m_dateTimeQSOOn;
QDateTime m_dateTimeLastTX;
@@ -847,7 +887,6 @@ private:
double m_toneSpacing;
int m_firstDecode;
QProgressDialog m_optimizingProgress;
QTimer m_heartbeat;
MessageClient * m_messageClient;
PSK_Reporter *psk_Reporter;
APRSISClient * m_aprsClient;
@@ -886,8 +925,10 @@ private:
void postDecode (bool is_new, QString const& message);
void displayTransmit();
void updateButtonDisplay();
void updateRepeatButtonDisplay();
void updateTextDisplay();
void updateFrameCountEstimate(int count);
void updateTextWordCheckerDisplay();
void updateTextStatsDisplay(QString text, int count);
void updateTxButtonDisplay();
bool isMyCallIncluded(QString const &text);
@@ -903,10 +944,16 @@ private:
void observeTimeDeltaForAverage(float delta);
void resetTimeDeltaAverage();
void processRxActivity();
void processIdleActivity();
void processCompoundActivity();
void processBufferedActivity();
QString generateStatus();
QStringList generateStatusFlags();
void processCommandActivity();
void writeDirectedCommandToFile(CommandDetail d);
QString inboxPath();
void refreshInboxCounts();
void addCommandToMyInbox(CommandDetail d);
void addCommandToInboxStorage(QString type, CommandDetail d);
void processAlertReplyForCommand(CommandDetail d, QString from, QString cmd);
void processSpots();
void processTxQueue();
@@ -934,6 +981,10 @@ private:
, QString const& his_call
, QString const& his_grid) const;
void read_wav_file (QString const& fname);
QDateTime nextTransmitCycle();
void resetAutomaticIntervalTransmissions(bool stopCQ, bool stopHB);
void resetCQTimer(bool stop);
void resetHeartbeatTimer(bool stop);
void decodeDone ();
void subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
void subProcessError (QProcess *, QProcess::ProcessError);
+870 -838
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -27,6 +27,7 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
m_plot2dGain {0},
m_plot2dZero {0},
m_nSubMode {0},
m_turbo {false},
m_Running {false},
m_paintEventBusy {false},
m_fftBinWidth {1500.0/2048.0},
@@ -587,6 +588,9 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_mode=="FT8"){
int fwidth=XfromFreq(m_rxFreq+bw)-XfromFreq(m_rxFreq);
#if TEST_FOX_WAVE_GEN
int offset=XfromFreq(m_rxFreq+bw+10)-XfromFreq(m_rxFreq+bw);
#endif
QPainter overPainter(&m_DialOverlayPixmap);
overPainter.initFrom(this);
overPainter.setCompositionMode(QPainter::CompositionMode_Source);
@@ -595,10 +599,22 @@ void CPlotter::DrawOverlay() //DrawOverlay()
overPainter.setPen(thinRed);
overPainter.drawLine(0, 30, 0, m_h);
overPainter.drawLine(fwidth+1, 30, fwidth+1, m_h);
#if TEST_FOX_WAVE_GEN
if(m_turbo){
overPainter.drawLine(offset+fwidth+1, 30, offset+fwidth+1, m_h);
overPainter.drawLine(offset+2*fwidth+1, 30, offset+2*fwidth+1, m_h);
}
#endif
overPainter.setPen(penRed);
overPainter.drawLine(0, 26, fwidth, 26);
overPainter.drawLine(0, 28, fwidth, 28);
#if TEST_FOX_WAVE_GEN
if(m_turbo){
overPainter.drawLine(offset+fwidth, 26, offset+2*fwidth, 26);
overPainter.drawLine(offset+fwidth, 28, offset+2*fwidth, 28);
}
#endif
QPainter hoverPainter(&m_HoverOverlayPixmap);
hoverPainter.initFrom(this);
@@ -607,6 +623,12 @@ void CPlotter::DrawOverlay() //DrawOverlay()
hoverPainter.setPen(QPen(Qt::white));
hoverPainter.drawLine(0, 30, 0, m_h);
hoverPainter.drawLine(fwidth+1, 30, fwidth+1, m_h);
#if TEST_FOX_WAVE_GEN
if(m_turbo){
hoverPainter.drawLine(offset+fwidth+1, 30, offset+fwidth+1, m_h);
hoverPainter.drawLine(offset+2*fwidth+1, 30, offset+2*fwidth+1, m_h);
}
#endif
#if DRAW_FREQ_OVERLAY
int f = FreqfromX(m_lastMouseX);
@@ -865,6 +887,15 @@ void CPlotter::setDialFreq(double d)
void CPlotter::setRxBand(QString band)
{
m_rxBand=band;
DrawOverlay();
update();
}
void CPlotter::setTurbo(bool turbo)
{
m_turbo=turbo;
DrawOverlay();
update();
}
void CPlotter::setFlatten(bool b1, bool b2)
+2
View File
@@ -81,6 +81,7 @@ public:
void setFlatten(bool b1, bool b2);
void setTol(int n);
void setRxBand(QString band);
void setTurbo(bool turbo);
void setReference(bool b) {m_bReference = b;}
bool Reference() const {return m_bReference;}
void drawRed(int ia, int ib, float swide[]);
@@ -147,6 +148,7 @@ private:
QString m_rxBand;
QString m_redFile;
bool m_turbo;
bool m_Running;
bool m_paintEventBusy;
bool m_dataFromDisk;
+1 -1
View File
@@ -127,7 +127,7 @@ void PSK_Reporter::dnsLookupResult(QHostInfo info)
// qDebug() << "PSK Reporter IP: " << m_pskReporterAddress;
// deal with miss-configured settings that attempt to set a
// Pskreporter Internet address for the WSJT-X UDP protocol
// Pskreporter Internet address for the UDP protocol
// server address
m_messageClient->add_blocked_destination (m_pskReporterAddress);
}
+138 -83
View File
@@ -27,6 +27,7 @@
#include "varicode.h"
#include "jsc.h"
#include "decodedtext.h"
#include <cmath>
@@ -49,30 +50,32 @@ QMap<QString, int> directed_cmds = {
{"?", 0 }, // compat
{" QTH?", 1 }, // query qth
{"@", 1 }, // compat
{" QTC?", 2 }, // query station message
{"&", 2 }, // compat
{" HEARING?", 3 }, // query station calls heard
{" GRID?", 4 }, // query grid
{"^", 4 }, // compat
{">", 5 }, // relay message
{" STATUS?", 6 }, // query idle message
{"*", 6 }, // compat
{">", 5 }, // relay message
{"#", 8 }, // all or nothing message
{" STATUS", 7 }, // this is my status
//{"!", 7 }, // alert message
//{"$", 3 }, // query station(s) heard
//{"=", 9 }, // unused
{" HEARING", 8 }, // these are the stations i'm hearing
{" ACTIVE", 10 }, // i have been active in the past 10 minutes
{" IDLE", 11 }, // i have not been active in the past 10 minutes
{" TU", 9 }, // thank you
{" HEARTBEAT", -1 }, // this is my ping (unused except for faux processing of pings as directed commands)
{" HEARTBEAT ACK", 12 }, // i acknowledge your ping at this SNR
{" HEARTBEAT REQ", 13 }, // can you transmit a ping to callsign?
{" HB", -1 }, // this is my heartbeat (unused except for faux processing of HBs as directed commands)
{" MSG TO:", 10 }, // store message at a station
{" QUERY", 11 }, // generic query
{" QUERY MSGS", 12 }, // do you have any stored messages?
{" QUERY CALL", 13 }, // can you transmit a ping to callsign?
{" APRS:", 14 }, // send an aprs packet
@@ -86,42 +89,52 @@ QMap<QString, int> directed_cmds = {
{" RR", 21 }, // roger roger
{" QSL?", 22 }, // do you copy?
{" QSL", 23 }, // i copy
{" QRZ?", 24 }, // who is calling me
// {" ", 24 }, // unused
{" SNR", 25 }, // seen a station at the provided snr
{" NO", 26 }, // negative confirm
{" YES", 27 }, // confirm
{" 73", 28 }, // best regards, end of contact
{" ACK", 29 }, // acknowledge
{" AGN?", 30 }, // repeat message
{" ", 31 }, // send freetext
{" ", 31 }, // send freetext (weird artifact)
{" ", 31 }, // send freetext
};
QSet<int> allowed_cmds = {-1, 0, 1, 2, 3, 4, 5, 6, /*7,*/ 8, /*9,*/ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
// commands allowed to be processed
QSet<int> allowed_cmds = {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, /*24,*/ 25, 26, 27, 28, 29, 30, 31};
QSet<int> buffered_cmds = {3, 5, /*6,*/ /*7,*/ 8, 13, 14, 15};
// commands that result in an autoreply
QSet<int> autoreply_cmds = {0, 1, 2, 3, 4, 6, 10, 12, 13, 30};
QSet<int> snr_cmds = {12, 25};
// commands that should be buffered
QSet<int> buffered_cmds = {3, 5, /*6,*/ /*7,*/ 10, 11, 12, 13, 14, 15};
// commands that may include an SNR value
QSet<int> snr_cmds = {25, 29};
// commands that are checksummed and their crc size
QMap<int, int> checksum_cmds = {
{ 5, 16 },
{ 8, 16 },
{ 10, 16 },
{ 11, 16 },
{ 12, 16 },
{ 13, 16 },
{ 14, 16 },
{ 15, 0 }
};
QString callsign_pattern = QString("(?<callsign>[@]?[A-Z0-9/]+)");
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:HEARTBEAT (ACK|REQ)|AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|QRZ[?]|SNR[?]|QTC[?]|QTH[?]|GRID[?]|STATUS[?]|(?:(?:ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|QTC|GRID|ACTIVE|IDLE)(?=[ ]|$))|[?*^&@#> ]))?");
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|MSG TO[:]|SNR[?]|QTC[?]|QTH[?]|GRID[?]|STATUS[?]|HEARING[?]|(?:(?:STATUS|HEARING|QUERY CALL|QUERY MSGS|QUERY|ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|QTC|GRID|TU)(?=[ ]|$))|[?> ]))?");
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
QString optional_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?");
QString optional_num_pattern = QString("(?<num>(?<=SNR|HEARTBEAT ACK)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
QString optional_num_pattern = QString("(?<num>(?<=SNR|ACK)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
QRegularExpression directed_re("^" +
callsign_pattern +
optional_cmd_pattern +
optional_num_pattern);
QRegularExpression heartbeat_re(R"(^\s*(?<type>CQCQCQ|CQ QRPP?|CQ DX|CQ TEST|CQ( CQ){0,2}|HEARTBEAT)(?:\s(?<grid>[A-R]{2}[0-9]{2}))?\b)");
QRegularExpression heartbeat_re(R"(^\s*(?<type>CQCQCQ|CQ QRP|CQ FIELD|CQ DX|CQ CONTEST|CQ( CQ){0,2}|HB( AUTO)?( RELAY)?( SPOT)?)(?:\s(?<grid>[A-R]{2}[0-9]{2}))?\b)");
QRegularExpression compound_re("^\\s*[`]" +
callsign_pattern +
@@ -190,19 +203,31 @@ quint16 nmaxgrid = (1<<15)-1;
QMap<QString, quint32> basecalls = {
{ "<....>", nbasecall + 1 }, // incomplete callsign
{ "@ALLCALL", nbasecall + 2 }, // ALLCALL group
{ "@JS8NET", nbasecall + 3 }, // JS8NET group
};
QMap<quint32, QString> cqs = {
{ 0, "CQCQCQ" },
{ 1, "CQ DX" },
{ 2, "CQ QRP" },
{ 3, "CQ TEST" },
{ 4, "CQ QRPP" },
{ 3, "CQ CONTEST" },
{ 4, "CQ FIELD" },
{ 5, "CQ"},
{ 6, "CQ CQ"},
{ 7, "CQ CQ CQ"},
};
QMap<quint32, QString> hbs = {
{ 0, "HB" }, // HB
{ 1, "HB AUTO" }, // HB AUTO
{ 2, "HB AUTO RELAY" }, // HB AUTO RELAY
{ 3, "HB AUTO RELAY SPOT" }, // HB AUTO RELAY SPOT
{ 4, "HB RELAY" }, // HB RELAY
{ 5, "HB RELAY SPOT" }, // HB RELAY SPOT
{ 6, "HB SPOT" }, // HB SPOT
};
QMap<int, int> dbm2mw = {
{0 , 1}, // 1mW
{3 , 2}, // 2mW
@@ -289,6 +314,13 @@ QString Varicode::cqString(int number){
return cqs[number];
}
QString Varicode::hbString(int number){
if(!hbs.contains(number)){
return QString{};
}
return hbs[number];
}
bool Varicode::startsWithCQ(QString text){
foreach(auto cq, cqs.values()){
if(text.startsWith(cq)){
@@ -298,6 +330,15 @@ bool Varicode::startsWithCQ(QString text){
return false;
}
bool Varicode::startsWithHB(QString text){
foreach(auto hb, hbs.values()){
if(text.startsWith(hb)){
return true;
}
}
return false;
}
QString Varicode::formatSNR(int snr){
if(snr < -60 || snr > 60){
return QString();
@@ -991,7 +1032,7 @@ quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
// [1][X][6]
// X = 0 == SNR
// X = 1 == ACK
value = ((1 << 1) | (int)(cmdStr == " HEARTBEAT ACK")) << 6;
value = ((1 << 1) | (int)(cmdStr == " ACK")) << 6;
value = value + (num & ((1<<6)-1));
if(pPackedNum) *pPackedNum = true;
} else {
@@ -1009,7 +1050,7 @@ quint8 Varicode::unpackCmd(quint8 value, quint8 *pNum){
auto cmd = directed_cmds[" SNR"];
if(value & (1<<6)){
cmd = directed_cmds[" HEARTBEAT ACK"];
cmd = directed_cmds[" ACK"];
}
return cmd;
} else {
@@ -1038,6 +1079,10 @@ int Varicode::isCommandChecksumed(const QString &cmd){
return checksum_cmds[directed_cmds[cmd]];
}
bool Varicode::isCommandAutoreply(const QString &cmd){
return directed_cmds.contains(cmd) && (autoreply_cmds.contains(directed_cmds[cmd]));
}
bool isValidCompoundCallsign(QStringRef callsign){
// compound calls cannot be > 9 characters after removing the /
if(callsign.toString().replace("/", "").length() > 9){
@@ -1118,7 +1163,7 @@ bool Varicode::isCompoundCallsign(const QString &callsign){
// CQCQCQ EM73
// CQ DX EM73
// CQ QRP EM73
// HEARTBEAT EM73
// HB EM73
QString Varicode::packHeartbeatMessage(QString const &text, const QString &callsign, int *n){
QString frame;
@@ -1132,8 +1177,8 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
// Heartbeat Alt Type
// ---------------
// 1 0 HEARTBEAT
// 1 1 CQCQCQ
// 1 0 HB
// 1 1 CQ
auto type = parsedText.captured("type");
auto isAlt = type.startsWith("CQ");
@@ -1148,13 +1193,14 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
packed_extra = Varicode::packGrid(extra);
}
quint8 cqNumber = hbs.key(type, 0);
if(isAlt){
packed_extra |= (1<<15);
cqNumber = cqs.key(type, 0);
}
quint8 cqNumber = cqs.key(type, 0);
frame = packCompoundFrame(callsign, FrameHeartbeat, packed_extra, cqNumber);
frame = packCompoundFrame(callsign, Varicode::FrameHeartbeat, packed_extra, cqNumber);
if(frame.isEmpty()){
if(n) *n = 0;
return frame;
@@ -1165,12 +1211,12 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
}
QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType, bool * isAlt, quint8 * pBits3){
quint8 type = FrameHeartbeat;
quint8 type = Varicode::FrameHeartbeat;
quint16 num = nmaxgrid;
quint8 bits3 = 0;
QStringList unpacked = unpackCompoundFrame(text, &type, &num, &bits3);
if(unpacked.isEmpty() || type != FrameHeartbeat){
if(unpacked.isEmpty() || type != Varicode::FrameHeartbeat){
return QStringList{};
}
@@ -1183,7 +1229,6 @@ QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType,
return unpacked;
}
// KN4CRD/XXXX EM73
// XXXX/KN4CRD EM73
// KN4CRD/P
@@ -1210,7 +1255,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
return frame;
}
quint8 type = FrameCompound;
quint8 type = Varicode::FrameCompound;
quint16 extra = nmaxgrid;
qDebug() << "try pack cmd" << cmd << directed_cmds.contains(cmd) << Varicode::isCommandAllowed(cmd);
@@ -1220,7 +1265,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
qint8 inum = Varicode::packNum(num, nullptr);
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum, &packedNum);
type = FrameCompoundDirected;
type = Varicode::FrameCompoundDirected;
} else if(!grid.isEmpty()){
extra = Varicode::packGrid(grid);
}
@@ -1232,12 +1277,12 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
}
QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType, quint8 *pBits3){
quint8 type = FrameCompound;
quint8 type = Varicode::FrameCompound;
quint16 extra = nmaxgrid;
quint8 bits3 = 0;
QStringList unpacked = unpackCompoundFrame(text, &type, &extra, &bits3);
if(unpacked.isEmpty() || (type != FrameCompound && type != FrameCompoundDirected)){
if(unpacked.isEmpty() || (type != Varicode::FrameCompound && type != Varicode::FrameCompoundDirected)){
return QStringList {};
}
@@ -1265,7 +1310,7 @@ QString Varicode::packCompoundFrame(const QString &callsign, quint8 type, quint1
QString frame;
// needs to be a compound type...
if(type == FrameDataCompressed || type == FrameDataUncompressed || type == FrameDirected){
if(type == Varicode::FrameData || type == Varicode::FrameDirected){
return frame;
}
@@ -1309,7 +1354,7 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, quint8 *pType, qu
quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3));
// needs to be a ping type...
if(packed_flag == FrameDataCompressed || packed_flag == FrameDataUncompressed || packed_flag == FrameDirected){
if(packed_flag == Varicode::FrameData || packed_flag == Varicode::FrameDirected){
return unpacked;
}
@@ -1410,7 +1455,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &mycall
cmdOut = cmd.trimmed();
packed_cmd = directed_cmds[cmdOut];
}
quint8 packed_flag = FrameDirected;
quint8 packed_flag = Varicode::FrameDirected;
quint8 packed_extra = inum;
// [3][28][28][5],[2][6] = 72
@@ -1438,7 +1483,7 @@ QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){
auto bits = Varicode::intToBits(Varicode::unpack72bits(text, &extra), 64);
quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3));
if(packed_flag != FrameDirected){
if(packed_flag != Varicode::FrameDirected){
return unpacked;
}
@@ -1471,8 +1516,12 @@ QString packHuffMessage(const QString &input, int *n){
QString frame;
// [1][71] = 72
QVector<bool> frameBits = {false};
// [1][1][70] = 72
// The first bit is a flag that indicates this is a data frame, technically encoded as [100]
// but, since none of the other frame types start with a 0, we can drop the two zeros and use
// them for encoding the first two bits of the actuall data sent. boom!
// The second bit is a flag that indicates this is not compressed frame (huffman coding)
QVector<bool> frameBits = {true, false};
int i = 0;
@@ -1525,8 +1574,12 @@ QString packCompressedMessage(const QString &input, int *n){
QString frame;
// [1][71] = 72
QVector<bool> frameBits = {true};
// [1][1][70] = 72
// The first bit is a flag that indicates this is a data frame, technically encoded as [100]
// but, since none of the other frame types start with a 1, we can drop the two zeros and use
// them for encoding the first two bits of the actuall data sent. boom!
// The second bit is a flag that indicates this is a compressed frame (dense coding)
QVector<bool> frameBits = {true, true};
int i = 0;
foreach(auto pair, JSC::compress(input)){
@@ -1564,24 +1617,25 @@ QString packCompressedMessage(const QString &input, int *n){
}
QString Varicode::packDataMessage(const QString &input, int *n){
QString huffFrame;
int huffChars = 0;
huffFrame = packHuffMessage(input, &huffChars);
QString huffFrame;
int huffChars = 0;
huffFrame = packHuffMessage(input, &huffChars);
QString compressedFrame;
int compressedChars = 0;
compressedFrame = packCompressedMessage(input, &compressedChars);
QString compressedFrame;
int compressedChars = 0;
compressedFrame = packCompressedMessage(input, &compressedChars);
if(huffChars > compressedChars){
if(n) *n = huffChars;
return huffFrame;
} else {
if(n) *n = compressedChars;
return compressedFrame;
}
if(huffChars > compressedChars){
if(n) *n = huffChars;
return huffFrame;
} else {
if(n) *n = compressedChars;
return compressedFrame;
}
}
QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
QString Varicode::unpackDataMessage(const QString &text){
QString unpacked;
if(text.length() < 12 || text.contains(" ")){
@@ -1592,18 +1646,24 @@ QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
quint64 value = Varicode::unpack72bits(text, &rem);
auto bits = Varicode::intToBits(value, 64) + Varicode::intToBits(rem, 8);
bool isData = bits.at(0);
if(!isData){
return unpacked;
}
bits = bits.mid(1);
bool compressed = bits.at(0);
int n = bits.lastIndexOf(0);
bits = bits.mid(1, n-1);
if(compressed){
// partial word (s,c)-dense coding with code tables
unpacked = JSC::decompress(bits);
if(pType) *pType = Varicode::FrameDataCompressed;
} else {
// huff decode the bits (without escapes)
unpacked = Varicode::huffDecode(Varicode::defaultHuffTable(), bits);
if(pType) *pType = Varicode::FrameDataUncompressed;
}
return unpacked;
@@ -1612,9 +1672,7 @@ QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
// TODO: remove the dependence on providing all this data?
QList<QPair<QString, int>> Varicode::buildMessageFrames(
QString const& mycall,
//QString const& basecall,
QString const& mygrid,
//bool compound,
QString const& selectedCall,
QString const& text
){
@@ -1654,14 +1712,14 @@ QList<QPair<QString, int>> Varicode::buildMessageFrames(
// and if this isn't a raw message (starting with "`")... then...
if(!selectedCall.isEmpty() && !line.startsWith(selectedCall) && !line.startsWith("`")){
bool lineStartsWithBaseCall = (
line.startsWith("@ALLCALL") ||
line.contains("HEARTBEAT") ||
Varicode::startsWithCQ(line)
line.startsWith("@ALLCALL") ||
Varicode::startsWithCQ(line) ||
Varicode::startsWithHB(line)
);
#if AUTO_PREPEND_DIRECTED_ALLOW_TEXT_CALLSIGNS
auto calls = Varicode::parseCallsigns(line);
bool lineStartsWithStandardCall = !calls.isEmpty() && line.startsWith(calls.first()) && calls.first().length() > 2;
bool lineStartsWithStandardCall = !calls.isEmpty() && line.startsWith(calls.first()) && calls.first().length() > 3;
#else
bool lineStartsWithStandardCall = false;
#endif
@@ -1823,7 +1881,7 @@ QList<QPair<QString, int>> Varicode::buildMessageFrames(
}
if(useDat){
frames.append({ frame, Varicode::JS8CallData });
frames.append({ frame, Varicode::JS8Call });
line = line.mid(m);
}
}
@@ -1839,16 +1897,12 @@ QList<QPair<QString, int>> Varicode::buildMessageFrames(
BuildMessageFramesThread::BuildMessageFramesThread(
const QString &mycall,
//const QString &basecall,
const QString &mygrid,
//bool compound,
const QString &selectedCall,
const QString &text, QObject *parent):
QThread(parent),
m_mycall{mycall},
//m_basecall{basecall},
m_mygrid{mygrid},
//m_compound{compound},
m_selectedCall{selectedCall},
m_text{text}
{
@@ -1857,19 +1911,20 @@ BuildMessageFramesThread::BuildMessageFramesThread(
void BuildMessageFramesThread::run(){
auto results = Varicode::buildMessageFrames(
m_mycall,
//m_basecall,
m_mygrid,
//m_compound,
m_selectedCall,
m_text
);
QList<QString> frames;
QList<int> bits;
foreach(auto pair, results){
frames.append(pair.first);
bits.append(pair.second);
// TODO: jsherer - we wouldn't normally use decodedtext.h here... but it's useful for computing the actual frames transmitted.
QStringList textList;
qDebug() << "frames:";
foreach(auto frame, results){
auto dt = DecodedText(frame.first, frame.second);
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
textList.append(dt.message());
}
emit resultReady(frames, bits);
auto transmitText = textList.join("");
emit resultReady(transmitText, results.length());
}
+19 -17
View File
@@ -21,22 +21,28 @@ public:
JS8Call = 0, // [000] <- any other frame of the message
JS8CallFirst = 1, // [001] <- the first frame of a message
JS8CallLast = 2, // [010] <- the last frame of a message
JS8CallData = 4, // [100] <- raw data frame (no frame type header)
JS8CallFlag = 4, // [100] <- flagged frame (no frame type header)
};
/*
000 = heartbeat
001 = compound
010 = compound directed
011 = directed
1XX = data, with the X lsb bits dropped
*/
enum FrameType {
FrameUnknown = 255, // [11111111] <- only used as a sentinel
FrameHeartbeat = 0, // [000]
FrameCompound = 1, // [001]
FrameCompoundDirected = 2, // [010]
FrameDirected = 3, // [011]
FrameReservedA = 4, // [100] <- Reserved for future use, likely an extension of one of these formats.
FrameDataUncompressed = 5, // [101]
FrameDataCompressed = 6, // [110]
FrameReservedB = 7, // [111] <- Reserved for future use, likely binary data / other formats.
FrameData = 4, // [10X] // but this only encodes the first 2 msb bits and drops the lsb
FrameDataCompressed = 6, // [11X] // but this only encodes the first 2 msb bits and drops the lsb
};
static const quint8 FrameTypeMax = 7;
static const quint8 FrameTypeMax = 6;
static QString frameTypeString(quint8 type) {
const char* FrameTypeStrings[] = {
@@ -44,10 +50,9 @@ public:
"FrameCompound",
"FrameCompoundDirected",
"FrameDirected",
"FrameReservedA",
"FrameDataUncompressed",
"FrameData",
"FrameUnknown", // 5
"FrameDataCompressed",
"FrameReservedB"
};
if(type > FrameTypeMax){
@@ -63,7 +68,9 @@ public:
static QMap<QString, QString> defaultHuffTable();
static QString cqString(int number);
static QString hbString(int number);
static bool startsWithCQ(QString text);
static bool startsWithHB(QString text);
static QString formatSNR(int snr);
static QString formatPWR(int dbm);
@@ -130,6 +137,7 @@ public:
static bool isCommandAllowed(const QString &cmd);
static bool isCommandBuffered(const QString &cmd);
static int isCommandChecksumed(const QString &cmd);
static bool isCommandAutoreply(const QString &cmd);
static bool isValidCallsign(const QString &callsign, bool *pIsCompound);
static bool isCompoundCallsign(const QString &callsign);
@@ -146,13 +154,11 @@ public:
static QStringList unpackDirectedMessage(QString const& text, quint8 *pType);
static QString packDataMessage(QString const& text, int *n);
static QString unpackDataMessage(QString const& text, quint8 *pType);
static QString unpackDataMessage(QString const& text);
static QList<QPair<QString, int>> buildMessageFrames(
QString const& mycall,
//QString const& basecall,
QString const& mygrid,
//bool compound,
QString const& selectedCall,
QString const& text
);
@@ -164,21 +170,17 @@ class BuildMessageFramesThread : public QThread
Q_OBJECT
public:
BuildMessageFramesThread(QString const& mycall,
//QString const& basecall,
QString const& mygrid,
//bool compound,
QString const& selectedCall,
QString const& text,
QObject *parent=nullptr);
void run() override;
signals:
void resultReady(QStringList, QList<int>);
void resultReady(QString, int);
private:
QString m_mycall;
//QString m_basecall;
QString m_mygrid;
//bool m_compound;
QString m_selectedCall;
QString m_text;
};
+16507
View File
File diff suppressed because it is too large Load Diff
+220537
View File
File diff suppressed because it is too large Load Diff
+11691
View File
File diff suppressed because it is too large Load Diff
+628
View File
@@ -0,0 +1,628 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#include "sqlite3.h"
/*
** The following structure holds pointers to all of the SQLite API
** routines.
**
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each other's shared
** libraries!
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
int (*bind_null)(sqlite3_stmt*,int);
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
const char * (*column_decltype)(sqlite3_stmt*,int i);
const void * (*column_decltype16)(sqlite3_stmt*,int);
double (*column_double)(sqlite3_stmt*,int iCol);
int (*column_int)(sqlite3_stmt*,int iCol);
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
const char * (*column_name)(sqlite3_stmt*,int);
const void * (*column_name16)(sqlite3_stmt*,int);
const char * (*column_origin_name)(sqlite3_stmt*,int);
const void * (*column_origin_name16)(sqlite3_stmt*,int);
const char * (*column_table_name)(sqlite3_stmt*,int);
const void * (*column_table_name16)(sqlite3_stmt*,int);
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
const void * (*column_text16)(sqlite3_stmt*,int iCol);
int (*column_type)(sqlite3_stmt*,int iCol);
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
int (*declare_vtab)(sqlite3*,const char*);
int (*enable_shared_cache)(int);
int (*errcode)(sqlite3*db);
const char * (*errmsg)(sqlite3*);
const void * (*errmsg16)(sqlite3*);
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
int (*expired)(sqlite3_stmt*);
int (*finalize)(sqlite3_stmt*pStmt);
void (*free)(void*);
void (*free_table)(char**result);
int (*get_autocommit)(sqlite3*);
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
void *(*malloc)(int);
char * (*mprintf)(const char*,...);
int (*open)(const char*,sqlite3**);
int (*open16)(const void*,sqlite3**);
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
void (*result_int)(sqlite3_context*,int);
void (*result_int64)(sqlite3_context*,sqlite_int64);
void (*result_null)(sqlite3_context*);
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
int (*value_numeric_type)(sqlite3_value*);
const unsigned char * (*value_text)(sqlite3_value*);
const void * (*value_text16)(sqlite3_value*);
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
char *(*vmprintf)(const char*,va_list);
/* Added ??? */
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
/* Added by 3.3.13 */
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*),
void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
void (*mutex_enter)(sqlite3_mutex*);
void (*mutex_free)(sqlite3_mutex*);
void (*mutex_leave)(sqlite3_mutex*);
int (*mutex_try)(sqlite3_mutex*);
int (*open_v2)(const char*,sqlite3**,int,const char*);
int (*release_memory)(int);
void (*result_error_nomem)(sqlite3_context*);
void (*result_error_toobig)(sqlite3_context*);
int (*sleep)(int);
void (*soft_heap_limit)(int);
sqlite3_vfs *(*vfs_find)(const char*);
int (*vfs_register)(sqlite3_vfs*,int);
int (*vfs_unregister)(sqlite3_vfs*);
int (*xthreadsafe)(void);
void (*result_zeroblob)(sqlite3_context*,int);
void (*result_error_code)(sqlite3_context*,int);
int (*test_control)(int, ...);
void (*randomness)(int,void*);
sqlite3 *(*context_db_handle)(sqlite3_context*);
int (*extended_result_codes)(sqlite3*,int);
int (*limit)(sqlite3*,int,int);
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
int (*backup_finish)(sqlite3_backup*);
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
int (*backup_pagecount)(sqlite3_backup*);
int (*backup_remaining)(sqlite3_backup*);
int (*backup_step)(sqlite3_backup*,int);
const char *(*compileoption_get)(int);
int (*compileoption_used)(const char*);
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*));
int (*db_config)(sqlite3*,int,...);
sqlite3_mutex *(*db_mutex)(sqlite3*);
int (*db_status)(sqlite3*,int,int*,int*,int);
int (*extended_errcode)(sqlite3*);
void (*log)(int,const char*,...);
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
const char *(*sourceid)(void);
int (*stmt_status)(sqlite3_stmt*,int,int);
int (*strnicmp)(const char*,const char*,int);
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
int (*wal_autocheckpoint)(sqlite3*,int);
int (*wal_checkpoint)(sqlite3*,const char*);
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
/* Version 3.7.16 and later */
int (*close_v2)(sqlite3*);
const char *(*db_filename)(sqlite3*,const char*);
int (*db_readonly)(sqlite3*,const char*);
int (*db_release_memory)(sqlite3*);
const char *(*errstr)(int);
int (*stmt_busy)(sqlite3_stmt*);
int (*stmt_readonly)(sqlite3_stmt*);
int (*stricmp)(const char*,const char*);
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
void(*)(void*));
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
void(*)(void*),unsigned char);
int (*cancel_auto_extension)(void(*)(void));
int (*load_extension)(sqlite3*,const char*,const char*,char**);
void *(*malloc64)(sqlite3_uint64);
sqlite3_uint64 (*msize)(void*);
void *(*realloc64)(void*,sqlite3_uint64);
void (*reset_auto_extension)(void);
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
void(*)(void*));
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
/* Version 3.8.11 and later */
sqlite3_value *(*value_dup)(const sqlite3_value*);
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
/* Version 3.9.0 and later */
unsigned int (*value_subtype)(sqlite3_value*);
void (*result_subtype)(sqlite3_context*,unsigned int);
/* Version 3.10.0 and later */
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
/* Version 3.18.0 and later */
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
/* Version 3.20.0 and later */
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
sqlite3_stmt**,const char**);
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
sqlite3_stmt**,const void**);
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
void *(*value_pointer)(sqlite3_value*,const char*);
int (*vtab_nochange)(sqlite3_context*);
int (*value_nochange)(sqlite3_value*);
const char *(*vtab_collation)(sqlite3_index_info*,int);
/* Version 3.24.0 and later */
int (*keyword_count)(void);
int (*keyword_name)(int,const char**,int*);
int (*keyword_check)(const char*,int);
sqlite3_str *(*str_new)(sqlite3*);
char *(*str_finish)(sqlite3_str*);
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
void (*str_append)(sqlite3_str*, const char *zIn, int N);
void (*str_appendall)(sqlite3_str*, const char *zIn);
void (*str_appendchar)(sqlite3_str*, int N, char C);
void (*str_reset)(sqlite3_str*);
int (*str_errcode)(sqlite3_str*);
int (*str_length)(sqlite3_str*);
char *(*str_value)(sqlite3_str*);
/* Version 3.25.0 and later */
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
void(*xDestroy)(void*));
/* Version 3.26.0 and later */
const char *(*normalized_sql)(sqlite3_stmt*);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
sqlite3 *db, /* Handle to the database. */
char **pzErrMsg, /* Used to set error string on failure. */
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
);
/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition. But the main library does not want to redefine
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
#define sqlite3_bind_null sqlite3_api->bind_null
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
#define sqlite3_bind_text sqlite3_api->bind_text
#define sqlite3_bind_text16 sqlite3_api->bind_text16
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
#define sqlite3_changes sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
#define sqlite3_column_blob sqlite3_api->column_blob
#define sqlite3_column_bytes sqlite3_api->column_bytes
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
#define sqlite3_column_count sqlite3_api->column_count
#define sqlite3_column_database_name sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype sqlite3_api->column_decltype
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
#define sqlite3_column_double sqlite3_api->column_double
#define sqlite3_column_int sqlite3_api->column_int
#define sqlite3_column_int64 sqlite3_api->column_int64
#define sqlite3_column_name sqlite3_api->column_name
#define sqlite3_column_name16 sqlite3_api->column_name16
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
#define sqlite3_column_table_name sqlite3_api->column_table_name
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
#define sqlite3_column_text sqlite3_api->column_text
#define sqlite3_column_text16 sqlite3_api->column_text16
#define sqlite3_column_type sqlite3_api->column_type
#define sqlite3_column_value sqlite3_api->column_value
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
#define sqlite3_create_collation sqlite3_api->create_collation
#define sqlite3_create_collation16 sqlite3_api->create_collation16
#define sqlite3_create_function sqlite3_api->create_function
#define sqlite3_create_function16 sqlite3_api->create_function16
#define sqlite3_create_module sqlite3_api->create_module
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
#define sqlite3_errcode sqlite3_api->errcode
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired sqlite3_api->expired
#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover sqlite3_api->global_recover
#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
#define sqlite3_malloc sqlite3_api->malloc
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
#define sqlite3_reset sqlite3_api->reset
#define sqlite3_result_blob sqlite3_api->result_blob
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
#define sqlite3_result_text sqlite3_api->result_text
#define sqlite3_result_text16 sqlite3_api->result_text16
#define sqlite3_result_text16be sqlite3_api->result_text16be
#define sqlite3_result_text16le sqlite3_api->result_text16le
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
#define sqlite3_value_bytes sqlite3_api->value_bytes
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
#define sqlite3_value_double sqlite3_api->value_double
#define sqlite3_value_int sqlite3_api->value_int
#define sqlite3_value_int64 sqlite3_api->value_int64
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
#define sqlite3_value_text sqlite3_api->value_text
#define sqlite3_value_text16 sqlite3_api->value_text16
#define sqlite3_value_text16be sqlite3_api->value_text16be
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
#define sqlite3_blob_close sqlite3_api->blob_close
#define sqlite3_blob_open sqlite3_api->blob_open
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
#define sqlite3_mutex_free sqlite3_api->mutex_free
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
#define sqlite3_mutex_try sqlite3_api->mutex_try
#define sqlite3_open_v2 sqlite3_api->open_v2
#define sqlite3_release_memory sqlite3_api->release_memory
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
#define sqlite3_limit sqlite3_api->limit
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
#define sqlite3_backup_finish sqlite3_api->backup_finish
#define sqlite3_backup_init sqlite3_api->backup_init
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
#define sqlite3_backup_step sqlite3_api->backup_step
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
#define sqlite3_db_config sqlite3_api->db_config
#define sqlite3_db_mutex sqlite3_api->db_mutex
#define sqlite3_db_status sqlite3_api->db_status
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
#define sqlite3_log sqlite3_api->log
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
#define sqlite3_sourceid sqlite3_api->sourceid
#define sqlite3_stmt_status sqlite3_api->stmt_status
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
/* Version 3.7.16 and later */
#define sqlite3_close_v2 sqlite3_api->close_v2
#define sqlite3_db_filename sqlite3_api->db_filename
#define sqlite3_db_readonly sqlite3_api->db_readonly
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
#define sqlite3_errstr sqlite3_api->errstr
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
#define sqlite3_stricmp sqlite3_api->stricmp
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
#define sqlite3_bind_text64 sqlite3_api->bind_text64
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
#define sqlite3_load_extension sqlite3_api->load_extension
#define sqlite3_malloc64 sqlite3_api->malloc64
#define sqlite3_msize sqlite3_api->msize
#define sqlite3_realloc64 sqlite3_api->realloc64
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
/* Version 3.8.11 and later */
#define sqlite3_value_dup sqlite3_api->value_dup
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
/* Version 3.9.0 and later */
#define sqlite3_value_subtype sqlite3_api->value_subtype
#define sqlite3_result_subtype sqlite3_api->result_subtype
/* Version 3.10.0 and later */
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
/* Version 3.18.0 and later */
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
/* Version 3.20.0 and later */
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
#define sqlite3_result_pointer sqlite3_api->result_pointer
#define sqlite3_value_pointer sqlite3_api->value_pointer
/* Version 3.22.0 and later */
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
#define sqlite3_value_nochange sqlite3_api->value_nochange
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
/* Version 3.24.0 and later */
#define sqlite3_keyword_count sqlite3_api->keyword_count
#define sqlite3_keyword_name sqlite3_api->keyword_name
#define sqlite3_keyword_check sqlite3_api->keyword_check
#define sqlite3_str_new sqlite3_api->str_new
#define sqlite3_str_finish sqlite3_api->str_finish
#define sqlite3_str_appendf sqlite3_api->str_appendf
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
#define sqlite3_str_append sqlite3_api->str_append
#define sqlite3_str_appendall sqlite3_api->str_appendall
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
#define sqlite3_str_reset sqlite3_api->str_reset
#define sqlite3_str_errcode sqlite3_api->str_errcode
#define sqlite3_str_length sqlite3_api->str_length
#define sqlite3_str_value sqlite3_api->str_value
/* Version 3.25.0 and later */
#define sqlite3_create_window_function sqlite3_api->create_window_function
/* Version 3.26.0 and later */
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
# define SQLITE_EXTENSION_INIT3 \
extern const sqlite3_api_routines *sqlite3_api;
#else
/* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* SQLITE3EXT_H */
+4
View File
@@ -566,3 +566,7 @@ void WideGraph::setRedFile(QString fRed)
{
ui->widePlot->setRedFile(fRed);
}
void WideGraph::setTurbo(bool turbo){
ui->widePlot->setTurbo(turbo);
}
+1
View File
@@ -50,6 +50,7 @@ public:
void drawRed(int ia, int ib);
void setVHF(bool bVHF);
void setRedFile(QString fRed);
void setTurbo(bool turbo);
signals:
void freezeDecode2(int n);
+2 -2
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1083</width>
<height>337</height>
<height>154</height>
</rect>
</property>
<property name="windowTitle">
@@ -43,7 +43,7 @@
<property name="minimumSize">
<size>
<width>400</width>
<height>100</height>
<height>10</height>
</size>
</property>
<property name="frameShape">
+8 -2
View File
@@ -77,7 +77,10 @@ SOURCES += \
DriftingDateTime.cpp \
jsc.cpp \
jsc_list.cpp \
jsc_map.cpp
jsc_map.cpp \
jsc_checker.cpp \
Message.cpp \
Inbox.cpp
HEADERS += qt_helpers.hpp \
pimpl_h.hpp pimpl_impl.hpp \
@@ -105,7 +108,10 @@ HEADERS += qt_helpers.hpp \
messagereplydialog.h \
keyeater.h \
DriftingDateTime.h \
jsc.h
jsc.h \
jsc_checker.h \
Message.h \
Inbox.h
INCLUDEPATH += qmake_only