Porównaj commity

...

1459 Commity
1.1a ... master

Autor SHA1 Wiadomość Data
Roeland Jansen 85178de1d5 fixed small issue in the install stuff 2024-02-26 20:00:50 +01:00
Roeland Jansen c7e8e90928 Fix for original Streamdeck (maybe XL as well) and Add XKeysXK3 (very early) support 2024-02-20 18:19:08 +01:00
Phil Taylor 9db9be5dec Add XKeysXK3 (very early) support 2024-02-20 17:06:52 +00:00
Phil Taylor 637e94dfd8 FIx for original Streamdeck (maybe XL as well?) 2024-02-20 16:53:45 +00:00
Elliott Liggett b68874d328 Merge branch 'desktop-files' into 'master'
Add AppStream metainfo file, standard size icon

Thank you, AsciiWolf, for helping us with flatpak (and flathub). 

See merge request eliggett/wfview!19
2023-11-20 17:48:16 +00:00
AsciiWolf e5c6e2030a Use correct aspect ratio icon 2023-11-18 01:58:46 +01:00
AsciiWolf 9be0acdf2e Add AppStream metainfo file, standard size icon 2023-11-17 00:28:33 +01:00
Roeland Jansen 1805861274 DERP! the channel spacing 6.125 is not half of 12.5 kHz. Fixed it. 2023-08-13 21:09:00 +02:00
Phil Taylor b4c079f7f4 Prepare for v1.64 release 2023-07-16 14:05:53 +01:00
Phil Taylor 80d6614ca7 Fix compile warnings 2023-07-16 14:00:18 +01:00
Phil Taylor 7df55bc41f Fix errors identified by clang scan-build 2023-07-16 10:26:28 +01:00
Roeland Jansen 54b00b9022 added list of known CI-V addresses, interfaces, rates 2023-05-29 11:42:16 +02:00
Roeland Jansen 0c072f4665 added libudev-dev as prereq to build on debian based systems 2023-05-03 08:04:17 +02:00
M0VSE 6fc63df321 Fix user not having access to ldconfig 2023-04-27 18:11:31 +01:00
M0VSE d5e4a67ac1 Fix libQCustomPlot library issue 2023-04-27 17:52:20 +01:00
Roeland Jansen c7e53f6a4d added initial ic905 and usb multi-controller support 2023-04-19 07:52:23 +02:00
Roeland Jansen 375acead89 Merge branch 'multi-usb' 2023-04-19 07:36:20 +02:00
Phil Taylor e274271820 Add support for IC-905 2023-04-17 11:19:00 +01:00
Phil Taylor 34655f6348 Allow user to select which LED is updated by the button. 2023-04-15 21:13:43 +01:00
Phil Taylor 8ad74ac7f6 First step at improving LED support 2023-04-15 20:13:20 +01:00
Phil Taylor 5d897c127a Make TX LED work on RC28 2023-04-15 11:34:41 +01:00
Phil Taylor 3c90a9363b Various fixes 2023-04-15 11:25:35 +01:00
Phil Taylor c392874b3b Comment out RC28 LED for now. 2023-04-14 21:36:46 +01:00
Phil Taylor 7b101d5ad4 Another attempt to fix for GCC 2023-04-14 21:33:45 +01:00
Phil Taylor 6a2e2024ef Fix compile error 2023-04-14 21:03:15 +01:00
Phil Taylor d941c831f3 Resize the controller display on tab change 2023-04-14 10:26:54 +01:00
Phil Taylor f35ac25ad3 Various other fixes 2023-04-13 15:28:46 +01:00
Phil Taylor 58f38c1735 Add RC28 LED Control to the features and disable controls that don't make sense 2023-04-13 14:36:16 +01:00
Phil Taylor 59bc2077e4 Replace + with | in keyboard shortcuts 2023-04-13 14:02:43 +01:00
Phil Taylor 8b786c1821 Fix recursive calling of pageChanged() 2023-04-12 11:14:40 +01:00
Phil Taylor 5ded2a0e79 Some more fixes 2023-04-12 10:24:00 +01:00
M0VSE c9300f4d86 Add linux USB hotplug 2023-04-11 20:25:29 +01:00
Roeland Jansen 1549819ad6 Fedora 36 instr. added 2023-04-11/Knud OZ1DGN 2023-04-11 19:17:11 +02:00
M0VSE 4874d70215 Fix linux compile 2023-04-10 13:46:29 +01:00
Phil Taylor d5f0e0f63c Lots more features and other fixes 2023-04-09 23:53:51 +01:00
Phil Taylor 1da3696ba2 Merge branch 'tristate' into multi-usb 2023-04-03 14:31:48 +01:00
Phil Taylor 289170e22d Enable wf by default 2023-04-02 21:11:14 +01:00
Phil Taylor ae0271c7f9 Use tristate checkbox for Scope enable/disable (also add saving state) 2023-04-02 21:09:37 +01:00
Phil Taylor a0f3f7de07 More work, tidying and improving stablity 2023-04-02 20:07:13 +01:00
Phil Taylor 0304ac67f6 Add backup/restore of button config 2023-03-29 23:33:18 +01:00
Phil Taylor 468cd2de0d Add various commands, monitor, NB, NR etc. 2023-03-28 21:58:46 +01:00
Phil Taylor 592c583d19 Add USB hotplug support in Windows 2023-03-28 19:07:54 +01:00
Phil Taylor cadf835d95 Receive current knob values from rig 2023-03-27 12:38:01 +01:00
Phil Taylor 75288b5e78 Allow storing of icons and various other fixes 2023-03-26 23:23:40 +01:00
Phil Taylor 6fd0d4e763 various other fixes and stability improvements 2023-03-26 16:08:53 +01:00
Phil Taylor 03c45663dc Fix crash when clicking on a knob. 2023-03-25 16:58:28 +00:00
Phil Taylor ac58289188 Initial support for Stream Deck Pro (other Stream Deck support to follow) 2023-03-25 09:09:42 +00:00
Phil Taylor d7ba3d9d9a Fix for wrong VFO being set on haveBandStackReg 2023-03-21 15:37:57 +00:00
Phil Taylor d1688a99c5 Fix controller setup window resizing 2023-03-21 13:24:48 +00:00
Phil Taylor a74f68d9d4 Various fixes 2023-03-21 13:17:35 +00:00
Phil Taylor f663550da7 Set tab name correctly 2023-03-20 15:37:11 +00:00
M0VSE 9d63c5cb71 Fix window issue in linux 2023-03-20 15:32:04 +00:00
Phil Taylor eb65ae0b1c Various fixes
Improve UI handling, add disable option
2023-03-18 16:38:24 +00:00
Phil Taylor 898d5960d8 Allow main knob to be used for other values than VFO 2023-03-18 01:34:40 +00:00
Phil Taylor a461babf73 Fix warning 2023-03-18 00:17:33 +00:00
Phil Taylor 792fac11d6 Support multiple USB controllers 2023-03-17 23:35:40 +00:00
Phil Taylor f3a25fade4 Remove unnecessary stepType setting from cwsender.ui 2023-03-12 18:25:17 +00:00
Roeland Jansen 3fa14ebc37 v1.62 released; performance fix 9700 and cw sidetone 2023-03-12 12:44:46 +01:00
Roeland Jansen 6049e1dee6 Merge branch 'sidetone' 2023-03-12 12:34:47 +01:00
Roeland Jansen e8ca39ca18 fixes the dreaded connection timeouts some 9700 users have 2023-03-10 08:19:03 +01:00
Phil Taylor 48a9710c11 Add improved connection timeout for IC9700 2023-03-09 17:47:52 +00:00
Phil Taylor 5328838c73 better control of rapid commands when mode changes 2023-02-21 11:46:14 +00:00
Phil Taylor 87a261be12 Move periodic pbt/passband to rapid queue 2023-02-21 11:11:55 +00:00
Phil Taylor b738a38cbe fix compile warnings from rigctl 2023-02-21 10:53:58 +00:00
Phil Taylor b2af4c898e Merge branch 'master' into sidetone 2023-02-21 10:48:01 +00:00
Phil Taylor cf4e872e4f Merge branch 'master' of https://gitlab.com/eliggett/wfview 2023-02-20 22:20:14 +00:00
Phil Taylor 37c30404d8 Fix for shuttle detection on Linux 2023-02-20 22:19:55 +00:00
Phil Taylor 5b9a5baaa1 Add printsupport back 2023-02-20 18:26:22 +00:00
Roeland Jansen fc0bd2232d changelog updated after rigctld-fixes 2023-02-20 19:24:44 +01:00
Phil Taylor 2186a74490 Minor change to p and P commands in rigctld 2023-02-20 13:05:23 +00:00
Phil Taylor b9288175bd Add remaining rigctld commands (mainly unimplemented) 2023-02-20 12:46:09 +00:00
Phil Taylor 7901ceba79 Add remaining rigctld commands (mainly unimplemented) 2023-02-20 12:43:26 +00:00
Phil Taylor e49eb2878e Rearrange signals 2023-02-20 11:48:53 +00:00
Phil Taylor c8b97e8952 Emit finished() if sending is stopped prematurely 2023-02-20 10:34:21 +00:00
Phil Taylor a6b1bce69e Disconnect signals when not in use 2023-02-20 10:31:09 +00:00
Phil Taylor e6644cdc11 Update cwsidetone.cpp 2023-02-18 15:14:05 +00:00
Phil Taylor fe0fc0a5bb Compile issue 2023-02-18 15:13:05 +00:00
Phil Taylor 5fb9588c4a Bit more tidying 2023-02-18 14:25:36 +00:00
Phil Taylor 62f923d8ad Add support for push audio and various other fixes 2023-02-18 13:18:42 +00:00
Phil Taylor 9f97df0ea5 Make generateData more readable 2023-02-18 11:03:13 +00:00
Phil Taylor ed1e8c3a8e Add message stacking 2023-02-17 23:57:53 +00:00
Phil Taylor acec37ea17 Improve timing 2023-02-17 23:21:29 +00:00
Phil Taylor 428ea9156c Change way we set sidetone volume 2023-02-17 18:08:44 +00:00
Phil Taylor 18254cad10 Log if write fails 2023-02-17 17:56:10 +00:00
Phil Taylor 67685dc100 Stop writing sidetone audio on error 2023-02-17 17:46:12 +00:00
Phil Taylor 71fd70f78b Sample type fixes 2023-02-17 17:26:21 +00:00
Phil Taylor f9ca8e7e84 Restart audio device if stopped/suspended 2023-02-17 16:56:01 +00:00
Phil Taylor acaed4601e Hopefully fix audio. 2023-02-17 16:49:19 +00:00
Phil Taylor 1177fa3419 Disable sidetone if unchecked 2023-02-17 16:28:56 +00:00
Phil Taylor 97ed3f6f42 Fix compile in linux 2023-02-17 14:34:08 +00:00
Phil Taylor e594efdbbc Try to stop crash if there is no default audio device 2023-02-17 14:30:22 +00:00
Phil Taylor 3ce35500b9 Fix Qt5 compile (hopefully) 2023-02-17 14:01:09 +00:00
Phil Taylor 9eb89a9cb1 First working cw sidetone
Still needs better timing and volume
2023-02-17 13:58:02 +00:00
Phil Taylor fd6d132fd3 Various fixes 2023-02-14 20:27:32 +00:00
Phil Taylor 6f1d4e24b7 Merge branch 'master' into sidetone 2023-02-14 18:48:10 +00:00
Phil Taylor 8b7377f096 Add some feature in the hope of supporting sidetone 2023-02-14 18:47:32 +00:00
Roeland Jansen ce9e3e9f2c ecoder, collission-detection added 2023-02-14 16:10:38 +01:00
Phil Taylor dd4770a85f Merge branch 'collision-detection' into ecoder 2023-02-13 15:37:26 +00:00
Phil Taylor 32e662237b Make ptt react correctly 2023-02-13 15:14:27 +00:00
Phil Taylor 3582c95c58 Fixes to collision detection. 2023-02-12 23:15:22 +00:00
Phil Taylor da71bb3bc3 Remove debugging 2023-02-12 23:14:51 +00:00
Phil Taylor 0397b4b68a Fixes to collision detection. 2023-02-12 23:14:39 +00:00
Phil Taylor feac83b997 Attempt at simple collision detection 2023-02-12 22:37:58 +00:00
Phil Taylor 9afc661c4c Update usbcontroller.cpp 2023-02-12 17:17:29 +00:00
Phil Taylor 6de14df1da Fix compile warnings 2023-02-12 17:14:26 +00:00
Phil Taylor 7e89e9f457 Add support for Xencelabs QuickKeys 2023-02-12 16:45:21 +00:00
Phil Taylor 3cb54f9cd7 Attempt at simple collision detection 2023-02-11 11:40:30 +00:00
Phil Taylor 80838e4f82 Some more changes 2023-02-11 11:39:18 +00:00
Phil Taylor 54c75d5def Multiply knob values * 10 2023-02-10 18:52:51 +00:00
Phil Taylor 8b59efbf33 Another try 2023-02-10 18:40:11 +00:00
Phil Taylor 9db0698927 Quick test 2023-02-10 18:26:34 +00:00
Phil Taylor 251239e445 Update usbcontroller.cpp 2023-02-10 18:13:50 +00:00
Phil Taylor a3a82cd442 Merge branch 'master' into ecoder 2023-02-10 18:11:42 +00:00
Phil Taylor 3461a0e5e5 Correct usbMutex 2023-02-10 18:10:32 +00:00
Phil Taylor 3429786e10 Reset knobValues to 0 after sending 2023-02-10 15:51:01 +00:00
Phil Taylor c2e9100a40 Hopefully fix random buttons 2023-02-10 15:47:23 +00:00
Phil Taylor c8a29bb400 Add mutex to ensure thread safety 2023-02-10 15:23:57 +00:00
Phil Taylor fa47bfb4bc Update usbcontroller.cpp 2023-02-10 13:34:04 +00:00
Phil Taylor 82425b445e Try again 2023-02-10 13:28:09 +00:00
Phil Taylor 7aa7546660 More work on knobs 2023-02-10 09:52:51 +00:00
Phil Taylor 4e61a455b5 Hide setup screen if disabled 2023-02-10 00:31:12 +00:00
Phil Taylor cad3bb9418 Various (I hope) improvements! 2023-02-10 00:27:01 +00:00
Phil Taylor 1f1800f046 Flip bits in knob command 2023-02-09 18:43:42 +00:00
Phil Taylor 5ed380c03d Remove debug setup 2023-02-09 18:35:07 +00:00
Phil Taylor a8951813f5 Provisional support for knobs 2023-02-09 13:21:51 +00:00
Roeland Jansen 6e5e22a672 another compile fix 2023-02-08 19:00:44 +01:00
Elliott Liggett bbbfe38e0b Very minor thing to help compiling with older hidapi. 2023-02-08 08:26:36 -08:00
Roeland Jansen 6a76efa368 compilation fixes 2023-02-08 11:26:33 +01:00
Phil Taylor 17a6547264 Merge branch 'master' into ecoder 2023-02-08 10:15:16 +00:00
Phil Taylor 1515e135e5 Fix for old hidapi without version info. 2023-02-08 10:12:48 +00:00
Phil Taylor 0ff2551026 Fix compile if controller disabled 2023-02-07 23:31:28 +00:00
Phil Taylor cb339edc1f Fix compile if controller disabled 2023-02-07 23:29:50 +00:00
Phil Taylor f4a86ac02e Add more buttons 2023-02-07 23:05:42 +00:00
Phil Taylor b783f8057a tuning knob? 2023-02-07 22:37:26 +00:00
Phil Taylor 1064038138 Another try 2023-02-07 21:12:02 +00:00
Phil Taylor dda3c8ee9d Update usbcontroller.cpp 2023-02-07 21:01:54 +00:00
Phil Taylor 63b8a356e8 Another try for buttons 2023-02-07 20:59:53 +00:00
Phil Taylor 4fc37290e5 try to fix ecoder buttons 2023-02-07 20:51:20 +00:00
Phil Taylor 72e8bc6fa6 Remove debug code 2023-02-07 20:32:46 +00:00
Phil Taylor 8a28a89760 Correct order! 2023-02-07 19:41:39 +00:00
Phil Taylor 5298949f3a Add support for ecoder buttons 2023-02-07 19:37:33 +00:00
Phil Taylor 1e217bc5b8 Some initial updates 2023-02-07 19:02:05 +00:00
Phil Taylor fbea7f1a13 Merge branch 'ecoderplus' into 'ecoder'
Ecoderplus

See merge request eliggett/wfview!17
2023-02-07 18:41:02 +00:00
Dawid Szymanski - SQ6EMM/SN6M 32639c5394 Ecoderplus 2023-02-07 18:41:02 +00:00
Roeland Jansen b373685fd3 v1.61 2023-02-07 18:56:41 +01:00
Roeland Jansen ea1fefc219 Merge branch 'wf-fix' 2023-02-07 18:52:37 +01:00
Phil Taylor 3d2c16201b Fix invalid scope data in combine mode 2023-02-07 17:51:52 +00:00
Roeland Jansen 6e0ebcdd5a removed empty file 2023-02-07 18:20:18 +01:00
Roeland Jansen 2488d62f2e fixes stuff after 1.60 release 2023-02-07 18:17:57 +01:00
Phil Taylor 40f49c56e7 Try again 2023-02-07 17:11:53 +00:00
Phil Taylor 529d101540 Quick fix 2023-02-07 16:50:02 +00:00
Phil Taylor 14a4b25e97 Add a comment about usb device types 2023-02-07 15:22:22 +00:00
Phil Taylor 78fa248963 Slightly better way of defining USB device types 2023-02-07 14:49:17 +00:00
Phil Taylor 7de515b70d Add spacer 2023-02-07 10:10:04 +00:00
Phil Taylor 76694361b5 Add small space above sensitivity slider 2023-02-07 09:40:38 +00:00
Phil Taylor 0e28f288ff Add sensitivity control to USB controllers. 2023-02-07 09:32:33 +00:00
Phil Taylor b619be3e2a Another fix 2023-02-06 19:54:52 +00:00
Phil Taylor 64c0007c78 More USB fixes 2023-02-06 19:51:30 +00:00
Phil Taylor b566a760ed Add device path 2023-02-06 18:50:49 +00:00
Phil Taylor 69afce7712 Check hidapi version 2023-02-06 18:19:12 +00:00
Phil Taylor 5654fa524e More attempts to fix MacOS 2023-02-06 17:52:47 +00:00
Phil Taylor 3d053c3c96 Require exclusive access for MacOS 2023-02-06 15:54:35 +00:00
Phil Taylor 872c8aee30 Update usbcontroller.cpp 2023-02-06 15:48:04 +00:00
Phil Taylor e2d6101a53 Fic mac build 2023-02-06 15:46:48 +00:00
Phil Taylor b35e1af185 Update usbcontroller.h 2023-02-06 15:43:53 +00:00
Phil Taylor a60cb39483 More improvements to device enumeration 2023-02-06 15:33:59 +00:00
Phil Taylor 6464f28159 Merge branch 'master' into usb-macfix 2023-02-06 15:03:19 +00:00
Phil Taylor 7b7d21d3a7 Improve USB device enumeration and fix for MacOS 2023-02-06 15:02:48 +00:00
Roeland Jansen 16eb4591eb updated CHANGELOG 2023-02-06 10:45:08 +01:00
Roeland Jansen eae5b93f0e Merge branch 'wsjtx-fix' 2023-02-06 10:44:34 +01:00
Phil Taylor 02c1dcdb8b Request passband at startup 2023-02-05 21:58:49 +00:00
Phil Taylor f4e772e1c7 Update wfmain.cpp 2023-02-05 21:51:00 +00:00
Phil Taylor 4a3f8692b5 Update rigState on receipt of new passband from rig. 2023-02-05 21:50:24 +00:00
Phil Taylor 2ec62b6c80 Make CRC hex 2023-02-05 21:43:51 +00:00
Phil Taylor 01e01321d3 This might cause a compile warning? 2023-02-05 21:40:59 +00:00
Phil Taylor f0c8842c05 Actually send the response! 2023-02-05 21:33:02 +00:00
Phil Taylor 979dffc176 Add some more commands 2023-02-05 21:28:24 +00:00
Phil Taylor 2128e6fc10 Merge branch 'wsjtx-fix' into pbt-color-picker 2023-02-05 20:15:42 +00:00
Phil Taylor fd86efa4b9 Add color picker for PBT 2023-02-05 13:21:12 +00:00
Phil Taylor 27ac972f4a Add support for latest version of wsjt-x to rigctld 2023-02-05 11:30:38 +00:00
Elliott Liggett bb632b8e2b Fixed placement of "out of range" data byte reading. 2023-02-04 09:57:12 -08:00
Roeland Jansen 11f8cb702f v1.60 milestone released 2023-02-04 14:49:58 +01:00
Roeland Jansen 82f268508e Merge branch 'pbt-lsb-fix' 2023-02-04 12:34:17 +01:00
Phil Taylor a1db8d1d60 Another attempt to fix 2023-02-04 11:32:52 +00:00
Roeland Jansen a08ada4cab Merge branch 'pbt-lsb-fix' 2023-02-04 12:31:23 +01:00
Phil Taylor 5671e26591 Hopefully fix wfserver compiling 2023-02-04 11:30:30 +00:00
Roeland Jansen 953399de06 Merge branch 'pbt-lsb-fix' 2023-02-04 12:11:20 +01:00
Phil Taylor 903d1965ba Hide half duplex combo to avoid confusion 2023-02-04 10:26:42 +00:00
Phil Taylor eae1fc725e Fix some more bits in wfview.pro 2023-02-04 00:02:59 +00:00
Phil Taylor 857c62f99f Move opus to .dll for 1.60R 2023-02-03 23:10:40 +00:00
Phil Taylor 7b2aca6cbd Same PBT fix for CW and RTTY 2023-02-03 20:34:59 +00:00
Phil Taylor f3da86940f Fix for displaying PBT in LSB mode 2023-02-03 19:58:37 +00:00
Roeland Jansen c70bbb0998 Merge branch 'usb-ui-help-text' 2023-02-03 20:15:58 +01:00
Phil Taylor d7fa78fcd2 Add Help text to usbControllerSetup 2023-02-03 19:08:08 +00:00
Roeland 0af2615833 Merge branch 'tx-rx-missed-fix' 2023-02-03 19:51:34 +01:00
Phil Taylor b928f23051 Only accept rigstate updates from rig if value is not in updated condition 2023-02-03 18:08:19 +00:00
Roeland Jansen 41aa95129a small steps... until 1.60 hits 2023-02-03 18:39:10 +01:00
Roeland Jansen 072ab1967f Merge branch 'band-switching' 2023-02-03 18:32:57 +01:00
Phil Taylor 75b86a0e4a Remove setting that causes error 2023-02-03 17:29:39 +00:00
Phil Taylor b334241ea0 Allow plot click to display frequency if nothing else is under it 2023-02-03 11:21:11 +00:00
Phil Taylor a511282505 Simplify command creation 2023-02-02 23:46:39 +00:00
Phil Taylor 4ea80af164 Merge branch 'morecontrols' into band-switching 2023-02-02 23:12:43 +00:00
Phil Taylor 80dc5d2df6 Bit of tidying 2023-02-02 23:11:49 +00:00
Phil Taylor 3993046771 Remove UDP congestion mitigation 2023-02-02 22:53:52 +00:00
Phil Taylor 06c3e33b4d Initialize lastdata first. 2023-02-02 17:45:24 +00:00
Phil Taylor d0cd7e2eb3 Use correct data for F1 key 2023-02-02 16:45:45 +00:00
Phil Taylor 5237c930e5 Ensure link LED is turned on at startup 2023-02-02 16:23:41 +00:00
Phil Taylor 777d08ef24 Turn off link LED when shutdown 2023-02-02 16:21:59 +00:00
Phil Taylor c4fcc89830 Reduce to only send 3 bytes (report+data) 2023-02-02 16:17:41 +00:00
Phil Taylor 193e07284e LED not working, maybe due to data size? 2023-02-02 15:47:59 +00:00
Phil Taylor 6c44ea9e0d More fixes 2023-02-02 15:02:32 +00:00
Phil Taylor ad50d41071 Fix warning 2023-02-02 11:24:22 +00:00
Phil Taylor 1ac8f5c2f0 Fix GCC build error 2023-02-02 11:23:17 +00:00
Phil Taylor e20900dbcf Query RC-28 for version 2023-02-02 00:03:13 +00:00
Phil Taylor a192e6643b Tidy-up wfserver.pro 2023-02-02 00:02:59 +00:00
Phil Taylor c6bd93a2b6 Stop shuttle emitting a signal every 100ms! 2023-02-01 18:30:46 +00:00
Phil Taylor 4816427954 Stop shuttle emitting a signal every 100ms! 2023-02-01 18:29:26 +00:00
Elliott Liggett 156f45d42f Added quicksplit checkbox 2023-02-01 09:21:17 -08:00
Elliott Liggett bbcc0e4842 Added "only available in FM" repeater setup warning. 2023-02-01 08:46:13 -08:00
Elliott Liggett 4411c1480e Cleaned up some debug code, checked repter-split checkbox by default. 2023-02-01 08:14:36 -08:00
Phil Taylor 5fa14d13e1 Try to get RC-28 LEDs working 2023-02-01 12:16:04 +00:00
Phil Taylor 180b7b0095 Merge branch 'morecontrols' into band-switching 2023-02-01 09:42:09 +00:00
Phil Taylor 071606fe5a More commands 2023-02-01 09:41:18 +00:00
Phil Taylor 096c223715 I've added a "Swap VFOs" command to the USB controller, which seems to work. 2023-02-01 09:24:26 +00:00
Elliott Liggett eaf7eb126e Disabled function that does not work with the cw combo box. 2023-01-31 22:38:22 -08:00
Elliott Liggett 38e6cb2ef4 removed unused functions 2023-01-31 22:36:37 -08:00
Elliott Liggett 3c31687b15 Added additional tone and tone mode sync up for split mode 2023-01-31 22:11:45 -08:00
Elliott Liggett a5f3750988 Cleaned up repeater-related debug code. 2023-01-31 22:08:27 -08:00
Elliott Liggett eea17e5e09 Possibly the tone issue is solved. 2023-01-31 21:52:24 -08:00
Elliott Liggett d503df03bd Continued repeater status work... 2023-01-31 18:00:12 -08:00
Elliott Liggett 17d6493338 Potentially fixed TONE and TSQL for rigs other than the mighty IC-9700. 2023-01-31 14:03:51 -08:00
Elliott Liggett cb7cf6c218 Added "scope out of range" notification. 2023-01-31 09:35:55 -08:00
Phil Taylor 2696d2c8d9 Fix for band +/- buttons 2023-01-30 23:54:45 +00:00
Phil Taylor 63a7ec0a21 Final tidying for Windows Builld 2023-01-30 21:43:47 +00:00
Phil Taylor 28c9d1beb2 More fixes for windows building 2023-01-30 19:12:42 +00:00
Phil Taylor db9f6cb933 Improve windows compile fix 2023-01-30 19:06:23 +00:00
Phil Taylor 2c9c304844 Fix windows build error 2023-01-30 18:51:50 +00:00
Roeland Jansen b2915b9f5e fixed build info for opensuse 15.x 2023-01-30 19:49:49 +01:00
Roeland Jansen 3bdee82501 v1.59 2023-01-30 19:16:19 +01:00
Roeland Jansen 199295b6ae Merge branch 'morecontrols' 2023-01-30 18:53:20 +01:00
Roeland Jansen c89a7bde97 Merge branch 'rc28-shuttle' 2023-01-30 18:53:13 +01:00
Phil Taylor 0b37b1f984 Fix compile warning 2023-01-30 17:49:42 +00:00
Elliott Liggett fc4bce8cd7 Fixed issue with number 3 in frequency button tab. 2023-01-30 09:10:39 -08:00
Elliott Liggett 5d5723fae6 Added focus protection to the split tx frequency box. It will not update
while it has keyboard focus.
2023-01-30 08:44:06 -08:00
Elliott Liggett eec2fff4ce Added focus protection around the offset frequency box. 2023-01-30 08:40:10 -08:00
Phil Taylor db686b1c8b Enable USB_CONTROLLER build by default 2023-01-30 16:27:40 +00:00
Phil Taylor 5afcfb4e1d Fix for MAC compiling 2023-01-30 16:17:48 +00:00
Phil Taylor cb81bef3bc Fix for MAC compiling 2023-01-30 16:16:07 +00:00
Phil Taylor db5f8a0893 Add buttons to reset buttons/commands 2023-01-30 16:15:43 +00:00
Phil Taylor 479671386e Various fixes to USB controllers 2023-01-30 12:01:29 +00:00
Elliott Liggett 3faf8d331c Added Mode AM and removed some annoying signed warnings. 2023-01-29 21:54:41 -08:00
Phil Taylor 3ca82deb6c Add some more USB commands 2023-01-30 00:31:33 +00:00
Phil Taylor 8d8f945cfa Add support for band+/band- buttons 2023-01-29 19:46:13 +00:00
Phil Taylor 12f7a9cf0a Merge branch 'morecontrols' into rc28-shuttle 2023-01-29 19:26:54 +00:00
Phil Taylor 9d711f3a17 Add some more USB controller features/fixes 2023-01-29 19:26:21 +00:00
Elliott Liggett 78ec6b1423 Fixed issue with auto track getting unchecked. 2023-01-29 11:04:12 -08:00
Phil Taylor 0e9a26dbc1 Merge branch 'rc28-shuttle' into 'rc28-shuttle'
space/typo fix

See merge request eliggett/wfview!15
2023-01-29 18:46:06 +00:00
Elliott Liggett de9f510d76 Merge branch 'morecontrols' of gitlab.com:eliggett/wfview into morecontrols 2023-01-29 10:40:39 -08:00
Elliott Liggett 2d1773720d Added split state LED for split. 2023-01-29 10:39:24 -08:00
Dawid SQ6EMM e13d85489d space/typo fix 2023-01-29 19:15:41 +01:00
Phil Taylor 5926c12a20 Merge branch 'morecontrols' into rc28-shuttle 2023-01-29 16:30:59 +00:00
Phil Taylor c55ff52fc0 Remove passband/PBT commands for FM 2023-01-29 16:29:37 +00:00
Phil Taylor 79decc552b Merge branch 'pbt-fixes' into rc28-shuttle 2023-01-29 16:25:34 +00:00
Phil Taylor 5d5ea25fb6 Remove a bit of debugging and fix compile warning 2023-01-29 15:15:41 +00:00
Phil Taylor 7e7dceaa99 Various shuttle fixes incorporating #54 2023-01-29 15:08:47 +00:00
Phil Taylor 166905ee76 Remove passband/PBT commands for FM 2023-01-29 13:09:04 +00:00
Elliott Liggett c91d06fea5 Added update of mode to CW sender. Modified cw sender UI slightly for
spacing.
2023-01-27 22:34:40 -08:00
Elliott Liggett bc508565ee Merge remote-tracking branch 'origin/pbt-fixes' into morecontrols
Fixed bugs in offset frequency
2023-01-27 22:11:04 -08:00
Elliott Liggett 264badb9c9 Added offset command to periodic polling 2023-01-27 21:48:26 -08:00
Elliott Liggett 6976120d48 Working manual repeater offset, split, tones, tones on sub vfo, etc! 2023-01-27 21:42:57 -08:00
Elliott Liggett 8903c7cb07 Forgot the signal/slot out of the queue! 2023-01-27 14:55:35 -08:00
Elliott Liggett b30230fc05 Fixing broken TSQL 2023-01-27 14:47:18 -08:00
Elliott Liggett 2c6884d827 Added sub VFO repeater access and tone control, hopefully will work for
IC-7610 and IC-7850.
2023-01-27 14:05:50 -08:00
Elliott Liggett 404d6ddceb Button name clarification on M->S 2023-01-27 12:52:12 -08:00
Elliott Liggett f660681c53 Added MS and AB VFO operations. 2023-01-27 12:44:23 -08:00
Phil Taylor eb782da010 Query PBT status after reset 2023-01-27 10:36:28 +00:00
Phil Taylor fa41571eca Fix for remove_if 2023-01-27 02:04:51 +00:00
Phil Taylor 5d0a95cd00 Use remove_if() for command queue removal 2023-01-27 02:00:11 +00:00
Phil Taylor 5dc9107f00 Merge branch 'master' into pbt-fixes 2023-01-27 01:51:10 +00:00
Phil Taylor 5128ea0e69 Lots of fixes for PBT and command handling - experimental 2023-01-27 01:41:35 +00:00
Roeland Jansen 5db5f40ed4 small compiling fixes and magic pbt/cw calculations 2023-01-26 07:35:23 +01:00
Roeland Jansen fe36ff1ac7 Merge branch 'pbt-fixes' 2023-01-26 07:33:00 +01:00
Phil Taylor 49501273d0 Fix for shuttle resource files 2023-01-25 21:37:12 +00:00
Phil Taylor ea46d6c625 Add math.h for cwsender 2023-01-25 21:22:06 +00:00
Roeland Jansen 13f06e1dd7 Merge branch 'pbt-fixes' 2023-01-25 22:17:23 +01:00
Phil Taylor ded6bd1ade Add CW Speed spinbox to CW sender 2023-01-25 18:01:24 +00:00
Phil Taylor 4b40e20d98 Remove some debugging 2023-01-25 15:39:01 +00:00
Roeland Jansen 6df7099cb3 Merge branch 'pbt-fixes' 2023-01-25 13:17:03 +01:00
Phil Taylor 5483732766 Merge branch 'master' into pbt-fixes 2023-01-25 11:42:13 +00:00
Phil Taylor 8b8668a6de Finally PBT works in all modes/filter widths/cw pitch settings. 2023-01-25 11:41:50 +00:00
Roeland Jansen bc0f9f01c7 Merge branch 'morecontrols' 2023-01-25 09:16:36 +01:00
Elliott Liggett be0aee6183 Split mode is working, can also live-sync frequency and mode. 2023-01-25 00:15:20 -08:00
Roeland Jansen 85e38d940f Merge branch 'pbt-fixes' 2023-01-25 07:47:41 +01:00
Elliott Liggett 4fea16c356 Refined split interface controls. Offset is KHz, automatic tracking mode
added.
2023-01-24 16:35:46 -08:00
Elliott Liggett ae64677c42 Merge branch 'master' into morecontrols 2023-01-24 15:17:17 -08:00
Phil Taylor a1d3f93dad PBT should now display correctly in ALL modes! 2023-01-24 20:12:23 +00:00
Roeland Jansen 7f97625e38 modified CHANGELOG 2023-01-24 19:49:43 +01:00
Elliott Liggett d53c9b028e Added a rapidPollCmdQueue for things we need to poll rapidly on not-s-
meter-intervals. Moved command types to wfviewtypes.h.
2023-01-24 10:37:26 -08:00
Elliott Liggett 0a7f6b0b65 Started work on the UI for a split control interface. 2023-01-24 09:21:09 -08:00
Roeland Jansen 2df82d4f92 bumped to v1.58 2023-01-24 17:22:34 +01:00
Phil Taylor 152f71c6cf Merge branch 'cwcw' into filterwidth 2023-01-24 11:20:01 +00:00
Phil Taylor 2ada127124 Delete cwsender.ui 2023-01-24 11:19:26 +00:00
Phil Taylor 646ee94341 Merge branch 'filterwidth' of https://gitlab.com/eliggett/wfview into filterwidth 2023-01-24 11:11:20 +00:00
Elliott Liggett 68ed3dc56b Fixed issue with older version of qt. 2023-01-23 20:56:17 -08:00
Elliott Liggett 4137fce70c Minor changes to UI file to get it building and to restore Enter key
functionality.
2023-01-23 20:35:32 -08:00
Phil Taylor 7ebfcdefbd Make cw textbox a combobox 2023-01-24 01:34:30 +00:00
Phil Taylor b89ae0459e Make cw textbox a combobox 2023-01-24 01:33:57 +00:00
Phil Taylor 525f984f01 Merge remote-tracking branch 'origin/cwcw' into filterwidth 2023-01-24 00:40:08 +00:00
Phil Taylor 9c3ca568ed Make PTT Enabled by default, user has the option to disable it. #74 2023-01-23 21:34:35 +00:00
Phil Taylor 4e89c91f0d Fix cosmetic bug #62 2023-01-23 21:27:33 +00:00
Phil Taylor f93dd83268 Remove some commented code 2023-01-23 21:26:43 +00:00
Phil Taylor 9349679e5b Various fixes 2023-01-23 13:44:15 +00:00
Elliott Liggett cba4ad345b Fixed up many key shortcuts, added HJKL key shortcuts. 2023-01-22 23:41:31 -08:00
Elliott Liggett 3297f66208 Mistake in tooltip keeps man from sleeping. See page 4 for full story. 2023-01-22 21:10:09 -08:00
Elliott Liggett 294fac72c6 Added some more CW-related tooltips for usability. 2023-01-22 21:04:43 -08:00
Elliott Liggett 27dd547e2a Added some tooltips and mode-awareness to the CW window. 2023-01-22 20:59:01 -08:00
Elliott Liggett a205e003c9 Lining up the text a little better with printHex. 2023-01-22 20:38:27 -08:00
Elliott Liggett 4a0f5a7f59 Fixed signed issue with waterfall data. 2023-01-22 15:24:21 -08:00
Phil Taylor e7091cb2c2 Make PBT display correctly 2023-01-22 17:19:44 +00:00
Elliott Liggett deade9a38e Added universal printhex header and functions. Changed radio traffic to
log to new category "rigTraffic".
2023-01-21 13:38:39 -08:00
Elliott Liggett c5c01cf81d removed a bit more debug and added some focus-force code for the CW
window.
2023-01-21 13:06:47 -08:00
Elliott Liggett 7a4f708e68 Added Keyer macros to settings. 2023-01-21 11:18:26 -08:00
Elliott Liggett c26409b2a8 Now with padding 2023-01-21 10:43:54 -08:00
Elliott Liggett ff50718563 Added CW sequence number 2023-01-21 10:31:04 -08:00
Elliott Liggett 2f098be1a9 Macro buttons are now filled with macro text, up to 8 characters. 2023-01-21 09:58:35 -08:00
Elliott Liggett f772801b02 Fixed WPM and removed some extra debug. 2023-01-21 09:37:36 -08:00
Elliott Liggett fd1dc860c1 Added CW logging category and additional (and needed) debug info for the
CW features.
2023-01-21 09:18:15 -08:00
Elliott Liggett 5664842f47 minor change 2023-01-21 00:25:41 -08:00
Elliott Liggett b3258c57a5 Added read/write for break in mode and key speed. Macro buttons working
although not saved.
2023-01-20 23:23:47 -08:00
Elliott Liggett 23c191a091 Morse code, initial commit. Does not read back WPM and breaking mode
yet, although it can set them.
2023-01-20 22:11:30 -08:00
Phil Taylor 93d20cc1ba Fix compile errors after merge 2023-01-20 11:24:29 +00:00
Phil Taylor ee4f00e153 Merge remote-tracking branch 'origin/horizpbt' into filterwidth 2023-01-20 09:31:21 +00:00
Elliott Liggett 1e79d5d32d Changed transceiver adjustments to be horizontal. Added passband width
control to the transceiver adjustments.
2023-01-19 23:02:54 -08:00
Roeland Jansen 18281798d6 efixes pushed to master 2023-01-19 19:07:04 +01:00
Phil Taylor c98d7094f9 Merge remote-tracking branch 'origin/efixes' into filterwidth 2023-01-19 16:18:29 +00:00
Phil Taylor 037f05297d Start to fix PBT 2023-01-19 16:16:47 +00:00
Elliott Liggett 71326cd385 Added preference for automatic sideband. 2023-01-18 23:17:28 -08:00
Elliott Liggett b99249692f Cleaned up some old mode selection code. 2023-01-18 22:50:18 -08:00
Elliott Liggett e9e042fad8 Change mode selection code to use the command queue (as it should have).
Beginnings of automatic sideband options.
2023-01-18 22:27:06 -08:00
Phil Taylor f224068ec1 Fix LSB passband resize 2023-01-18 19:19:48 +00:00
Phil Taylor e94c3e53c5 Correctly handle filter width (remove PBT for now) 2023-01-18 18:52:05 +00:00
Elliott Liggett 0c27bf7208 This is a stylistic thing that I saw which I could not let go. 2023-01-17 21:49:17 -08:00
Elliott Liggett 05295acc6f Added version mismatch warning messages. 2023-01-17 21:43:58 -08:00
Elliott Liggett fc753ffd39 cleanup of prefs 2023-01-17 21:13:16 -08:00
Elliott Liggett f820d289b2 Re-arranged the preference structure to match how we save the
preferences.
2023-01-17 21:09:54 -08:00
Elliott Liggett 9c0aea0102 Changed Show More button to also raise the transceiver adjustments
window. Added "reset PBT" button to the transceiver adjustments window.
2023-01-17 20:53:34 -08:00
Phil Taylor a0f7d5d86f Remove attempt to reduce PA latency 2023-01-17 11:20:08 +00:00
Phil Taylor a6ea32d996 Allow resize passband when moved. 2023-01-16 22:14:09 +00:00
Phil Taylor 450ccefb60 Remove debugging messages 2023-01-16 13:06:04 +00:00
Phil Taylor ca84555c15 Add move passband 2023-01-16 12:24:22 +00:00
Phil Taylor 8fca384135 Hopefully fix building with QCP < 2.0.0 2023-01-15 12:27:23 +00:00
Phil Taylor 794a8b71c8 Merge branch 'filterwidth' of https://gitlab.com/eliggett/wfview into filterwidth 2023-01-15 11:15:32 +00:00
Phil Taylor 3baf3eae65 Fix crash when no audio device is found 2023-01-15 11:14:28 +00:00
Phil Taylor ffd7abb376 Disabling compiling USB_CONTROLLER by default 2023-01-15 10:37:21 +00:00
Phil Taylor 120899e9f8 Various fixes to allow Qt6 compiling on mac 2023-01-15 10:34:54 +00:00
Roeland Jansen b468c514df added var filterwidth 2023-01-14 19:59:04 +01:00
Roeland Jansen c221fb4a04 Merge branch 'filterwidth' 2023-01-14 19:58:02 +01:00
Phil Taylor c3ba36ebfd More mac stuff 2023-01-14 11:23:19 +00:00
Phil Taylor d1ec010e68 more mac fixes 2023-01-14 00:40:28 +00:00
Phil Taylor e2f4646207 See if this fixes issue with mac compiling? 2023-01-14 00:35:27 +00:00
Phil Taylor 19818dc3b3 Fix for fix of mac build! 2023-01-14 00:21:55 +00:00
Phil Taylor 58f86f029b Fix for mac compile 2023-01-14 00:17:53 +00:00
Phil Taylor b285b81d72 Rename to IF filter width to match documentation 2023-01-13 21:07:55 +00:00
Phil Taylor 8f98696bec Change wording 2023-01-13 21:06:50 +00:00
Phil Taylor 4f4cd5146c Display current passband on status bar 2023-01-13 21:04:10 +00:00
Phil Taylor cac454cbf6 More tidying of code 2023-01-13 20:53:51 +00:00
Phil Taylor 3e46b5a42d More tidying 2023-01-13 19:40:38 +00:00
Phil Taylor 41e5e4b1c3 Another fix 2023-01-13 19:28:34 +00:00
Phil Taylor d48bdfa6e2 Fix parentheses warning from GCC 2023-01-13 19:19:04 +00:00
Phil Taylor 4ee8741157 Few fixes to passband dragging 2023-01-13 18:50:06 +00:00
Phil Taylor efb953a8c9 Allow on-screen adjustment of filter width 2023-01-13 18:14:11 +00:00
Roeland Jansen 596607e95a amended CHANGELOG and WHATSNEW 2023-01-13 13:41:00 +01:00
Phil Taylor 5c210f0699 Fix invalid filter width being sent to rig by rigctld. 2023-01-13 12:26:11 +00:00
Phil Taylor 996c813251 Fix another minor issue with wfview.pro 2023-01-13 10:55:59 +00:00
Phil Taylor 8f5016a2f4 Fix problem if USB_CONTROLLER isn't enabled 2023-01-13 10:44:11 +00:00
Roeland Jansen f86a721a05 cleanup 2023-01-13 10:57:00 +01:00
Roeland Jansen 7052dbf6ef shuttle merged; not automaically built in due to the current state 2023-01-13 10:53:51 +01:00
Phil Taylor 5d2089c3e1 Allow riigctld set_mode command to not set passband 2023-01-12 20:28:45 +00:00
Phil Taylor 460641972a Neaten wfview.pro 2023-01-12 20:16:23 +00:00
Phil Taylor b2d62dab3c Fix conflicting items in ui 2023-01-12 19:52:21 +00:00
Phil Taylor c0a70ae0b7 Fix logfile for wfserver 2023-01-12 19:47:55 +00:00
Phil Taylor b45bf9ce41 Fix compile issues 2023-01-12 19:39:35 +00:00
Phil Taylor 0d9a01cd1f Merge latest master and make USB controllers a compile time directive 2023-01-12 19:20:52 +00:00
Phil Taylor 93f18fae9e Merge branch 'master' into shuttle 2023-01-12 18:50:18 +00:00
Roeland Jansen 29897e5795 CHAnGELOG format changed as it takes too much time 2023-01-11 19:24:56 +01:00
Roeland Jansen 1deaec3720 v1.56 pushed -- mostly audio fixes and QT5/6 compatibility 2023-01-11 19:21:08 +01:00
Phil Taylor b7f83a7807 Rename in/out Formats to avoid confusion 2023-01-09 10:44:02 +00:00
Phil Taylor 8a4b9f1934 Fix all audio formats and some compile warnings! 2023-01-07 20:52:07 +00:00
Phil Taylor 03ebafae5b Fix typo 2023-01-07 11:36:53 +00:00
Phil Taylor 00a5c78e98 Fix building wfserver 2023-01-07 11:28:06 +00:00
Phil Taylor d9ff07486d Fix compile error on Linux 2023-01-06 10:42:31 +00:00
Phil Taylor 4a8de3c0c9 Add function to handle connect/disconnect 2023-01-05 20:00:31 +00:00
Phil Taylor 3e149ee742 Add option of popup alert 2023-01-05 19:37:53 +00:00
Phil Taylor 373b670482 Change serial port signal for QT6. 2023-01-03 12:02:10 +00:00
Phil Taylor 7bb5e0f9c5 Various audio fixes (needs checking with Qt5) 2023-01-02 20:07:34 +00:00
Phil Taylor 322cc54ad6 Fix portaudio 2023-01-02 17:56:22 +00:00
Phil Taylor 4e62f365cd Fix for QTAudio when using QT6 and above. 2023-01-02 16:11:48 +00:00
Roeland Jansen 24ac791ad4 updated to v1.55, see WHATSNEW 2023-01-02 15:49:33 +01:00
Roeland Jansen 5dabcb34df Merge branch 'QT6.2' 2023-01-02 15:42:38 +01:00
Phil Taylor 39dacf54f2 Fix wfserver device detection 2023-01-02 13:39:59 +00:00
Phil Taylor e6a5152734 Prevent memory leak on exit 2023-01-02 12:38:05 +00:00
roeland jansen b3f76fce67 Merge branch 'standardHFfix' into 'master'
fixed missing 160m band

See merge request eliggett/wfview!14
2023-01-02 08:12:00 +00:00
Phil Taylor 436428b3a9 Support hotplug audio on QT6+ 2023-01-02 01:11:25 +00:00
Phil Taylor a327b2690e Fix resampler compiler warnings. 2023-01-02 00:21:37 +00:00
Phil Taylor 7348fc2ed0 Remove Exception from RT audio as it doesn't exist in newer versions of RTAudio 2023-01-01 21:40:46 +00:00
Phil Taylor ff6dd19e53 Tidy-up device enumeration for Qt audio 2023-01-01 20:56:13 +00:00
Phil Taylor db0112c8a3 Log enumeration of audio devices 2023-01-01 20:51:52 +00:00
Phil Taylor 6199c648c1 Fix some old warnings 2023-01-01 20:28:59 +00:00
Phil Taylor 32528a02b8 Fix codec selection issue in both QT5 and 6 2023-01-01 16:35:47 +00:00
Phil Taylor 91ce6040e0 Make sure compilation with QT5 still works 2023-01-01 16:17:48 +00:00
Dawid SQ6EMM 8ead34b253 fixed missing 160m band 2022-12-31 02:02:16 +01:00
Phil Taylor 891fd68a52 Fixed after merge 2022-12-29 16:06:42 +00:00
Phil Taylor f4c455396a Merge branch 'audio-fixes' into QT6.2 2022-12-29 15:26:41 +00:00
Phil Taylor a89af116e9 Merge updated 2022-12-29 14:16:22 +00:00
Phil Taylor aabe690bae Fix compile errors/warnings in Linux 2022-12-29 09:21:25 +00:00
Phil Taylor 14fc07905e Try to make dial smoother 2022-12-29 00:28:42 +00:00
Phil Taylor 0aca239b2a Add some more debugging 2022-12-29 00:25:14 +00:00
Phil Taylor 2bf14520d8 Make comboboxes smaller on Linux 2022-12-29 00:06:03 +00:00
Phil Taylor 0b51d5bb05 Make combobox smaller and add scrollbar 2022-12-28 23:55:32 +00:00
Phil Taylor 72e8b2ec2f Illuminate PTT LED on TX 2022-12-28 22:45:42 +00:00
Phil Taylor c3fa41490a Make RC28 buttons work 2022-12-28 22:25:41 +00:00
Phil Taylor 978a444759 Merge branch 'shuttle' into 'shuttle'
RC28 started to work (no LED feedback yet) MVP done

See merge request eliggett/wfview!12
2022-12-28 21:38:39 +00:00
Dawid Szymański 3aa4375bdf RC28 started to work (no LED feedback yet) MVP done 2022-12-28 21:38:39 +00:00
Phil Taylor 7dfdc5e3e2 Move audio device selection to dedicated class 2022-12-28 16:57:05 +00:00
Phil Taylor f232ff2396 Make it compile.
Currently band switching from Shuttle is broken since I changed the bandtype to a struct. I will fix this soon!
2022-12-28 10:21:45 +00:00
Phil Taylor d9e839b6f2 Merge branch 'master' into shuttle 2022-12-28 10:07:02 +00:00
Roeland Jansen 0d2d9ba23e bumped to v1.54, see WHATSNEW 2022-12-28 09:57:09 +01:00
Roeland Jansen 28d3c55e2f Merge branch 'termbinfail' 2022-12-28 09:54:37 +01:00
Elliott Liggett 093e6e799c Fixed termbin button issue when connection fails. Cleaned up some
logging.
2022-12-27 19:37:12 -08:00
Roeland Jansen ac3894f897 Merge branch 'server-fixes' 2022-12-20 11:49:07 +01:00
Phil Taylor e8142a11ba DIsable tcpserver on wfserver 2022-12-19 20:04:07 +00:00
Phil Taylor 3bf095020c Fix serial port detection. 2022-12-19 19:41:23 +00:00
Phil Taylor e56294406a Swap logfile/settings file on servermain 2022-12-19 19:26:51 +00:00
Roeland Jansen 8d3406a8ae Merge branch 'resetpeaks' 2022-12-03 12:32:41 +01:00
Elliott Liggett f6b1428267 Now tracking the plasma buffer user-desired size properly. 2022-12-02 13:32:02 -08:00
Elliott Liggett 82dfb99822 A little cleaner on the plasma mod. 2022-12-02 12:50:05 -08:00
Elliott Liggett 8cfb3f70e5 Added clearing to the plasma underlay display. 2022-12-02 12:38:08 -08:00
Phil Taylor 0b39b91665 PA stop stream if latency exceeded and start again when data is received. 2022-12-01 13:16:05 +00:00
Phil Taylor 65ba69822a Attempt to fix PortAudio issue 2022-12-01 13:08:29 +00:00
Phil Taylor f91dea47b5 Stop log warning on wfserver 2022-12-01 12:32:10 +00:00
Roeland Jansen 9367d605f4 fixed WHATSNEW formatting 2022-11-29 10:30:53 +01:00
Roeland Jansen 508f870062 CHANGELOG and WHATSNEW updated for 1.53 2022-11-29 10:29:10 +01:00
Roeland Jansen 06e4567b12 bumped 1.53 2022-11-29 09:40:07 +01:00
Phil Taylor 4c76cf6320 Add missing prefs 2022-11-28 09:44:42 +00:00
Phil Taylor 0a1a7b2336 Merge remote-tracking branch 'origin/pollprefs' into various-fixes 2022-11-28 09:27:53 +00:00
Elliott Liggett 8a1347f17c Added some tooltips that nobody will notice. 2022-11-26 21:45:27 -08:00
Elliott Liggett 4f6da00206 Added polling preferences and changed UI elements to radio buttons with
spin box.
2022-11-26 21:43:47 -08:00
Elliott Liggett 39caf41905 Added program version number to the settings file. Currently it is merely
written to and not used.
2022-11-26 20:53:12 -08:00
Elliott Liggett b25c8a93f3 Moved preferences to prefs.h, which should make it easier to add new
preferences. Moved custom types (as it seemed useful here and there) to
wfviewtypes.h. Let's use the wfviewtypes.h file for any kind of datatype
which more than one module can make use of.
2022-11-26 20:45:32 -08:00
Phil Taylor 81f9e9bfcf Update some rig definitions to work with new band struct. 2022-11-26 19:10:59 +00:00
Phil Taylor 7138ef69ea Merge branch 'master' into various-fixes 2022-11-26 19:02:11 +00:00
Phil Taylor 1fe19166f3 Add some more commands 2022-11-26 19:01:16 +00:00
Elliott Liggett afcf087a70 Fixed color preset zero issue. 2022-11-24 11:43:27 -08:00
Elliott Liggett e1e9167622 Fixed unusual set of conditions in which manual CI-V address would fail
to identify the connected radio. The fix is to continually poll the RigID
until one is received. Radios that don't support RigID will need to
check both boxes in wfview (use rig as model number) to manually ID the
radio.
2022-11-23 23:26:11 -08:00
Elliott Liggett 9a63a6c4c4 Fixed minor typo in debug text. 2022-11-23 22:45:29 -08:00
Elliott Liggett bb5ae03235 Cleaned up rigidentities 2022-11-23 21:56:36 -08:00
Elliott Liggett 45244c7c64 Fixed annoying indentation issue. 2022-11-23 20:44:32 -08:00
Elliott Liggett a5ac42fe57 Fixed broken RTS preference. Added preliminary (and untested) support
for the IC-703, 737, 738, and 756.
2022-11-23 16:59:10 -08:00
Elliott Liggett 9da6f77078 Fixed issue causing the current color preset to not be load (previously
preset zero was always used).
2022-11-23 13:36:13 -08:00
Roeland Jansen b57e4ebd76 added libs for suse builds; it also builds on leap 15.5 2022-11-01 12:16:55 +01:00
Phil Taylor a1252eec1e Fix passband warnings 2022-10-31 13:33:47 +00:00
Phil Taylor 29060eb43e Add skimmer support (setting not saved) 2022-10-31 12:39:27 +00:00
Phil Taylor 209c5a9b0b Key KEYSPD 2022-10-31 12:15:56 +00:00
Phil Taylor b46dfb8f3e Add AR Cluster support 2022-10-31 12:15:42 +00:00
Phil Taylor d47b9be7e1 Add more commands to rigctld 2022-10-31 12:03:04 +00:00
Phil Taylor f7c532007e Make bandType a struct containing frequency and default SSB mode 2022-10-29 15:12:30 +01:00
Phil Taylor 429aba7d68 Remove spot display processing timer 2022-10-29 00:20:27 +01:00
Phil Taylor e49e00c3ad Silly error in setting default cluster 2022-10-29 00:18:04 +01:00
Phil Taylor bf340e7790 Send bye when disconnecting from cluster 2022-10-28 20:04:32 +01:00
Phil Taylor 3a07830d47 Add passband to rigctld and allow setting 2022-10-28 20:04:14 +01:00
Phil Taylor 5ffbfc0f1d Merge branch 'master' into shuttle 2022-10-25 10:19:56 +01:00
Roeland Jansen 103dc9c86a combobox resizing fix 2022-10-25 08:25:02 +02:00
Phil Taylor 034ec90662 Stop it cutting off some devices 2022-10-24 00:09:18 +01:00
Phil Taylor ce9ab6d7ff Resize according to boundingrect 2022-10-23 23:45:53 +01:00
Phil Taylor e2338edde6 Resize based on font size 2022-10-23 22:58:23 +01:00
Phil Taylor 16dd595f52 Try new universal resize code 2022-10-23 22:45:11 +01:00
Phil Taylor eb363db09c Try analogue? 2022-10-23 19:32:55 +01:00
Phil Taylor b1b6f26b7d Update wfmain.cpp 2022-10-23 19:20:24 +01:00
Phil Taylor 4452e0127b More buttons 2022-10-23 19:13:11 +01:00
Phil Taylor b0ebed916c Update usbcontroller.h 2022-10-23 19:08:31 +01:00
Phil Taylor 1c8f08a077 More button assignments 2022-10-23 19:06:48 +01:00
Phil Taylor 91b4ab9f94 Reorder button assignment 2022-10-23 18:56:31 +01:00
Phil Taylor 75aab75b46 start to support analogue 2022-10-23 18:54:18 +01:00
Phil Taylor d753315c55 Some more buttons and add commands 2022-10-23 00:17:50 +01:00
Phil Taylor 6a0997017e Add some button mapping 2022-10-23 00:02:44 +01:00
Phil Taylor 6255542ee1 Map some buttons 2022-10-22 23:50:48 +01:00
Phil Taylor a2c348f646 More changes 2022-10-22 23:43:49 +01:00
Phil Taylor ba07c26a2b More gamepad stuff 2022-10-22 23:36:19 +01:00
Phil Taylor 2dad92b9f6 Update usbcontroller.cpp 2022-10-22 23:30:15 +01:00
Phil Taylor 45c7429c40 Make retransmit messages debug() 2022-10-22 23:27:04 +01:00
Phil Taylor ecd93b3841 More gamepad 2022-10-22 23:23:30 +01:00
Phil Taylor 09cd0ba541 Update usbcontroller.cpp 2022-10-22 23:19:52 +01:00
Phil Taylor eff37c586c Update usbcontroller.cpp 2022-10-22 23:18:45 +01:00
Phil Taylor 710566715b More gamepad stuff 2022-10-22 23:17:34 +01:00
Phil Taylor 358375be8a Add gamepad detection 2022-10-22 20:55:08 +01:00
Phil Taylor 677eb3c944 Merge branch 'master' into shuttle 2022-10-22 20:20:48 +01:00
Roeland Jansen 6609aa58d9 added qt xml dev lib for suse 2022-10-22 14:48:44 +02:00
Phil Taylor 3f84e093be Remove buttons that no longer exist from Shuttle 2022-10-17 00:29:11 +01:00
Roeland Jansen ce12135c4a bands page reorganized 2022-10-14 17:48:35 +02:00
Phil Taylor 066af2d9b8 Move Setup button to experimental and fix storing buttons 2022-10-11 23:56:00 +01:00
Phil Taylor 3dd1d7bb9a Fix command numbering 2022-10-11 23:33:12 +01:00
Phil Taylor cb0ace1a51 Merge branch 'master' into shuttle 2022-10-11 16:47:48 +01:00
Phil Taylor 5d0f6e82c5 Merge branch 'cluster' into shuttle 2022-10-11 16:42:34 +01:00
Roeland Jansen faf5caefa3 Merge branch 'cluster' 2022-10-11 15:04:22 +02:00
Phil Taylor e15496e0b6 Disable click/drag tuning by default 2022-10-11 13:17:23 +01:00
Roeland Jansen f8cef53a7d added cluster support 2022-10-10 17:11:05 +02:00
Phil Taylor f4e25d2273 Bit more tidying of spotting code 2022-10-10 12:55:12 +01:00
Phil Taylor 3ec54f1ebb make spots appear at the actual top of wf 2022-10-09 20:24:01 +01:00
Phil Taylor 6862009e94 Add sendOutput() back to tcp cluster 2022-10-09 14:35:24 +01:00
Phil Taylor b7bcd58578 Add Pop-Out button for cluster screen 2022-10-09 14:32:09 +01:00
Phil Taylor 22abc65849 Add cluster spot color picker 2022-10-09 14:23:07 +01:00
Phil Taylor cc6e4d042a Left click on spot to change freq 2022-10-08 01:09:41 +01:00
Phil Taylor f7e2631ee3 Update wfmain.cpp 2022-10-08 00:55:07 +01:00
Phil Taylor 62d9ec2442 Update wfmain.cpp 2022-10-06 11:17:46 +01:00
Phil Taylor fa9cab1374 Make spot window size to fit content. 2022-10-06 11:12:55 +01:00
Phil Taylor 880a9c3da0 Add right-click on spot to popup dialog 2022-10-06 11:02:22 +01:00
Phil Taylor b110ce7fbb Bit of tidying 2022-10-05 14:26:42 +01:00
Phil Taylor 4d158f5078 Remove calls for QSqlDatabase when USESQL is not configured 2022-10-05 13:43:07 +01:00
Phil Taylor f31aadd991 Add optional SQL in wfview.pro 2022-10-05 12:45:25 +01:00
Phil Taylor b011165d5b Make SQL db optional 2022-10-05 12:43:39 +01:00
Phil Taylor 9fdc09c5be Remove old code 2022-10-05 11:38:24 +01:00
Phil Taylor 855438e843 Update query 2022-10-05 11:05:29 +01:00
Phil Taylor 711b86e91b Add memory sqlite db for cluster spots. 2022-10-05 11:03:15 +01:00
Phil Taylor 9db695cc63 Delete all spots if cluster disabled 2022-09-30 19:06:17 +01:00
Phil Taylor 2d58ea2afb Fix crash when adding cluster server 2022-09-30 18:41:57 +01:00
Phil Taylor 4db4510501 Comment unused line 2022-09-30 17:29:10 +01:00
Phil Taylor 3b1efbd69e Change default to isdefault! 2022-09-30 17:26:21 +01:00
Phil Taylor e6713dc516 Merge branch 'master' into cluster 2022-09-30 17:07:26 +01:00
Phil Taylor 7d141608bf Add TCP spot client 2022-09-30 17:05:42 +01:00
Roeland Jansen d5aeec61ba v1.51 with fixes,passband stuff 2022-09-29 18:45:13 +02:00
Phil Taylor f48e65d147 Fix for squished screen and bump version to 1.51 2022-09-29 17:22:14 +01:00
Phil Taylor e7e7821f2b Comment out some unused variables 2022-09-29 17:18:48 +01:00
Phil Taylor dbc13a0533 Initial work on cluster spots. 2022-09-29 17:17:51 +01:00
Phil Taylor cef827f7f8 Only request passband when there is a scope available 2022-09-28 17:53:28 +01:00
Phil Taylor f7bde0fe64 Change default passband colors. 2022-09-28 17:42:12 +01:00
Phil Taylor bbc2613942 Fix passband colorswatch 2022-09-28 17:34:15 +01:00
Phil Taylor 0bb57a859d See if this works better for color pickers? 2022-09-27 10:22:27 +01:00
Phil Taylor 1193841103 Ignore second VFO scope data (for now) 2022-09-27 09:37:24 +01:00
Phil Taylor b3756391c1 Silently ignore server audio issues if server is not enabled. 2022-09-27 08:57:22 +01:00
Phil Taylor 242d39ce39 Always use 8bit encoding for audio device names 2022-09-27 08:44:55 +01:00
Phil Taylor 51878e5a3d Make multimedia-plugins message only for Linux 2022-09-27 08:30:17 +01:00
Phil Taylor b7af0d4edd Remove obsolete code 2022-09-26 21:43:22 +01:00
Phil Taylor 518e1700ae Remove logging of audio device realm 2022-09-26 21:43:22 +01:00
Phil Taylor 87ebd0cdcc Fix default audio device selection and hopefully fix device language issue 2022-09-26 21:43:22 +01:00
Phil Taylor 08b6224471 Add PSK modes to IC-7610 and to passband. 2022-09-26 21:22:02 +01:00
Phil Taylor ac0771f034 Add passband for FM mode 2022-09-26 20:46:25 +01:00
Elliott Liggett 65b4a9cc17 Added click-drag tuning. Needs refinement but it's a start. 2022-09-26 11:53:56 -07:00
Phil Taylor 0c530303c7 Move to 3 columns 2022-09-26 12:10:41 +01:00
Phil Taylor 9d9a817f97 Allow changing of passband color 2022-09-26 11:59:16 +01:00
Phil Taylor d8e244f33a First look at a passband indicator 2022-09-26 01:44:49 +01:00
Roeland Jansen 70101487a3 ready for v1.50 2022-09-23 22:14:49 +02:00
Roeland Jansen e93086f6ac Delete quit confirmation checkbox 2022-09-23 19:48:42 +02:00
Roeland Jansen fe459fa736 Merge branch 'logfix' 2022-09-23 19:47:32 +02:00
Phil Taylor 6e7d006b0e Delete quit confirmation checkbox 2022-09-23 18:40:01 +01:00
Roeland Jansen 32d214b24f Remove redundant CL args 2022-09-23 18:48:41 +02:00
Roeland Jansen dfcbc3b2f6 Merge branch 'logfix' 2022-09-23 18:47:17 +02:00
Phil Taylor f838e22498 Remove redundant CL args 2022-09-23 17:42:36 +01:00
Roeland Jansen 70fbd989f1 additional logging fixes 2022-09-23 18:33:40 +02:00
M0VSE d9190a5060 Finally fix compile warning! 2022-09-23 17:18:42 +01:00
Phil Taylor b6d9c26ebb another warning fix 2022-09-23 17:11:25 +01:00
Phil Taylor 5216e78390 Another compile warning fix attempt 2022-09-23 17:07:30 +01:00
Phil Taylor c62d8832f1 Hopefully fix compile warning on linux 2022-09-23 17:02:06 +01:00
Phil Taylor 7fc3a7bf79 Quick fix to remove a debug 2022-09-23 16:49:32 +01:00
Phil Taylor 26510c4166 Use date/time for log name if none specified 2022-09-23 16:46:33 +01:00
Phil Taylor 3ee237e736 Fix logfile/directory opening in Windows 2022-09-23 15:45:39 +01:00
Roeland Jansen 1aff6b9cb6 resize fixes for non-spectrum rigs, bug fixing users, updated to v1.48 2022-09-23 07:55:07 +02:00
Elliott Liggett 79531712b0 Fixed glitch when tabs are changed prior to rigcaps. 2022-09-22 21:14:05 -07:00
Elliott Liggett 9c49395fa0 Additional resize fixes for non-spectrum rigs. 2022-09-22 21:06:49 -07:00
Elliott Liggett 11c1d2f5df Hide UI elements not needed for non-spectrum radios. 2022-09-22 20:53:57 -07:00
Roeland Jansen 71537c21e1 updated CHANGELOG and WHATSNEW 2022-09-21 17:03:36 +02:00
Roeland Jansen 12ea418f1e updated CHANGELOG and WHATSNEW 2022-09-21 17:01:44 +02:00
Phil Taylor 3dbfc94419 Fix that was stopping users being created when none existed 2022-09-21 15:38:28 +01:00
Phil Taylor 2f35e009e9 Merge branch 'master' into shuttle 2022-09-20 22:53:26 +01:00
Phil Taylor eda1f9fcd3 Merge branch 'master' of https://gitlab.com/eliggett/wfview 2022-09-20 18:57:09 +01:00
Phil Taylor ae6f1f2ca3 Add quick fix for rigctld fmv issue 2022-09-20 18:56:53 +01:00
Roeland Jansen 9ecdd02246 Added dialog box to the toFixed button where an edge can be selected; bumped to v1.47 2022-09-20 19:06:12 +02:00
Elliott Liggett cd3320ec9a Added dialog box to the toFixed button where an edge can be selected. 2022-09-20 08:58:12 -07:00
Roeland Jansen 6b44b81a2a removed .swp 2022-09-19 17:08:50 +02:00
Roeland Jansen 520b1d051a Added controls for custom scope edges, hide/show scope controls
depending upon the scope mode the radio reports.
        Fixed clear peaks button to work with the plasma underlay.
        both audio system button are disabled when connected to radio and enabled when not.
        Remove password from log
        Fix server user handling
2022-09-19 17:06:00 +02:00
Phil Taylor 31969d0647 Add change mode commands 2022-09-19 02:03:02 +01:00
Phil Taylor 722e5b3c35 Allow PTT to be toggled 2022-09-19 01:34:25 +01:00
Phil Taylor 5ccc2fc375 Fix for saving buttons 2022-09-19 01:14:11 +01:00
Elliott Liggett 881823a839 Added controls for custom scope edges, hide/show scope controls
depending upon the scope mode the radio reports.
2022-09-18 13:13:33 -07:00
Phil Taylor e6506cd55f Add storing button config 2022-09-18 21:00:44 +01:00
Elliott Liggett bb2593be6f Fixed clear peaks button to work with the plasma underlay. 2022-09-18 12:22:11 -07:00
Phil Taylor c87dc5ef73 Fixed after merge 2022-09-18 17:42:41 +01:00
Phil Taylor 546330e829 Merge master into shuttle 2022-09-18 16:36:52 +01:00
Phil Taylor 4bd80cb9e5 Make sure both audio system button are disabled when connected to radio and enabled when not. 2022-09-18 15:23:37 +01:00
Phil Taylor 079f03886f Remove password from log! 2022-09-18 15:02:31 +01:00
Phil Taylor a04f7f57d3 Fix server user handling 2022-09-18 14:59:03 +01:00
Roeland Jansen 8638086f3f removed lingering files 2022-09-18 13:05:08 +02:00
Roeland Jansen c09c548eb0 log, connect and dial changed/fixed; bumped to v1.45 2022-09-18 13:04:13 +02:00
Roeland Jansen 6dd7cc0247 Merge branch 'log' 2022-09-18 12:54:15 +02:00
Elliott Liggett a7ba906569 Log will automatically scroll to bottom on show. 2022-09-17 15:02:21 -07:00
Phil Taylor 0c22f81690 Remove focus from connect button once clicked. 2022-09-17 22:43:40 +01:00
Phil Taylor 4dcc7c4753 Move connect button 2022-09-17 22:31:43 +01:00
Phil Taylor 77f48f5f0c Update wfmain.cpp
Add enable/disable audioSystemServerCombo
2022-09-17 21:04:46 +01:00
Phil Taylor da0644f1ba Merge branch 'log' of https://gitlab.com/eliggett/wfview into log 2022-09-17 20:58:41 +01:00
Phil Taylor fca463f346 Add "Cancel" to connect button 2022-09-17 20:57:49 +01:00
Elliott Liggett 0735c35cec Fixed bug where the frequency dial skipped extra when crossing zero. 2022-09-17 12:05:32 -07:00
Roeland Jansen b13de1d9ee missing space and lowercased Termbin.com to termbin.com 2022-09-17 10:36:07 +02:00
Roeland Jansen 81607a8069 merged log branch and updated to 1.44 2022-09-17 10:26:13 +02:00
Elliott Liggett cf50e9d18a Added an additional combo box for the audio system selection under the
Radio Server page of settings.
2022-09-16 13:43:01 -07:00
Elliott Liggett aba2928d42 Added dedication in the about box. 2022-09-16 13:22:58 -07:00
Phil Taylor 7e2682170f Make Windows expand audio combo when clicked 2022-09-16 20:51:16 +01:00
Elliott Liggett 221086ed4f Minor edit to margins 2022-09-15 17:35:29 -07:00
Elliott Liggett b54f724ce9 Removed some additional padding that was left in parts of the UI. 2022-09-15 17:04:01 -07:00
Elliott Liggett 6ed1a8e80e Changed windows 'open log' command to launch notepad. 2022-09-15 16:31:27 -07:00
Elliott Liggett de46d62346 Removed extra disconnect message from logging host. 2022-09-15 14:13:14 -07:00
Elliott Liggett d90104a79e Added flush to the text stream to termbin. 2022-09-15 14:09:16 -07:00
Elliott Liggett b849df9f7f Better scrolling behavior. The log is now aware if you are not at the
bottom and will not force scroll if so. Otherwise, it will bring the
horizontal scroll back to the left-edge.
2022-09-15 11:59:04 -07:00
Elliott Liggett 940f5fb961 Renamed URL message box in case we add an additional message box later. 2022-09-15 11:55:45 -07:00
Elliott Liggett d4ae4181ed Clarified control label to Scroll Down versus To Bottom. 2022-09-15 11:52:52 -07:00
Elliott Liggett 4e3af7cccd Changed font for better compatibility. Added some controls for scrolling
behavior.
2022-09-15 11:52:08 -07:00
Elliott Liggett c5f626065a Debug mode can now be toggled from the logging window. 2022-09-15 09:53:50 -07:00
Elliott Liggett d25c9ca245 Removed extra output on non-server builds. 2022-09-15 09:49:03 -07:00
Elliott Liggett 2225953d03 Added debug logging button, however, it doesn't propagate the debug
signal through all the modules yet. So, for now, it is hidden.
2022-09-15 09:42:19 -07:00
Elliott Liggett 95994ed737 Restored version to log file, fixed reversed log entries. 2022-09-15 09:33:09 -07:00
Elliott Liggett 42e3ee444d Removed word wrapping from the log 2022-09-14 18:35:45 -07:00
Elliott Liggett 73b9c88e5e Cut log window polling rate in half for lower CPU. 100ms is plenty fast. 2022-09-14 18:32:28 -07:00
Elliott Liggett 1b6cff85f4 Removed audio volume logging. 2022-09-14 18:15:20 -07:00
Elliott Liggett 8b688548c2 Keep the logging window up after the message box. Added "log" logging
category.
2022-09-14 17:53:22 -07:00
Elliott Liggett 3290b64a0b Added logging window capability with termbin support. 2022-09-14 17:07:23 -07:00
Roeland Jansen c97f0f7826 v1.43: resize bug fixed 2022-09-09 19:54:16 +02:00
Elliott Liggett 2198e3ca19 Found an extra 10 pixels due to some layout padding I left in
accidently.
2022-09-09 09:41:32 -07:00
Elliott Liggett a1d2f57d8b Main window may now be made smaller. Settings combo box sizes now
limited.
2022-09-09 09:34:31 -07:00
Elliott Liggett d658e21220 Fixed issue where build paths with a space in the name would cause the
git hash to fail capture.
2022-09-09 09:28:52 -07:00
Roeland Jansen 7145de132f audiometer support and changes to WHATSNEW/CHANGELOG 2022-08-26 09:08:23 +02:00
Roeland Jansen b91c033ef6 Merge branch 'master' into audiometer 2022-08-25 10:38:13 +02:00
Roeland Jansen 76389c0fbd added color picker support 2022-08-25 10:37:46 +02:00
Elliott Liggett 39cf34af23 Fixed dB meter, it needed the scale multiplied by 2. 2022-08-24 22:23:32 -07:00
Elliott Liggett 4f4abfc41a Cleaner COMP label without the "0" position 2022-08-24 22:02:20 -07:00
Elliott Liggett 0f226fdca5 Added tic marks, removed audio RMS calculation for now at least. 2022-08-24 21:52:36 -07:00
Elliott Liggett 9623226b0c Added average metering. 2022-08-24 16:06:41 -07:00
Elliott Liggett fbf1c4bce9 Removed annoying debug message. 2022-08-24 15:21:29 -07:00
Elliott Liggett 4ea7ec8090 Fixed up signals and slots related to audio levels, removed extra junk
code, added preliminary RMS and Peak audio availablility.
2022-08-24 15:02:00 -07:00
Elliott Liggett d90eb6f11f Using peak scale color now 2022-08-24 10:17:11 -07:00
Roeland Jansen be95896205 Merge branch 'master' into audiometer 2022-08-24 18:17:57 +02:00
Roeland Jansen 25d3d40548 Merge branch 'color' 2022-08-24 09:42:43 +02:00
Elliott Liggett 2afcef5ef0 log scale, incomplete, needs tickmarks, etc. 2022-08-23 23:17:57 -07:00
Elliott Liggett f7e787e097 Log scale for audio meters 2022-08-23 23:10:58 -07:00
Elliott Liggett 9fb74ed6e1 Audio metering initial. Very messy but you can select TxRxAudio as the
meter type and wfview will show you TX or RX audio depending upon if you
are transmitting or not. You can also select only TxAudio or RxAudio.
This is nice for looking at Tx audio levels prior to transmitting, for
example, or metering the radio's "monitor" audio while transmitting.
2022-08-23 22:24:05 -07:00
Elliott Liggett d3493988af Minor ui adjustment 2022-08-23 17:01:11 -07:00
Elliott Liggett c989dba9f9 Color preset UI now expands to fit. Finally. 2022-08-23 10:56:16 -07:00
Elliott Liggett 31f62fde67 Moved some preset controls. 2022-08-23 10:47:19 -07:00
Elliott Liggett 1471567808 Clarified what some controls do in the UI related to color and underlay. 2022-08-23 10:41:26 -07:00
Elliott Liggett b8ba9a16dc Added protection against transparent colors. Added revert feature to
revert to default color preset for the selected preset. Added save
single preset capability.
2022-08-23 10:35:59 -07:00
Roeland Jansen 173a311c7a Merge branch 'color' 2022-08-23 08:05:55 +02:00
Elliott Liggett 7e80eb0ed7 Cleaned up lots of debug info messages. 2022-08-22 21:31:31 -07:00
Elliott Liggett d49b6cd082 Oops, forgot to clarify the button name. 2022-08-22 21:22:45 -07:00
Elliott Liggett 8012a58bd9 Added separate colors for the high meter scale and the peak indicator. 2022-08-22 21:22:01 -07:00
Elliott Liggett 2a456b2adb Small cleanup. 2022-08-22 20:44:58 -07:00
Elliott Liggett fa0752518d More color tuning! 2022-08-22 19:39:20 -07:00
Elliott Liggett 9afc44ce42 Refresh the meter when updating colors immediately. 2022-08-22 18:09:20 -07:00
Elliott Liggett da1cd8b14f Added our "classic" color schemes back in. More tuning needed but a good
start.
2022-08-22 17:57:54 -07:00
Elliott Liggett 6f7f1f84ec Added presets and preset naming to the settings file. 2022-08-22 16:49:35 -07:00
Phil Taylor d1ffbe84f5 Still more work required 2022-08-22 23:09:09 +01:00
Elliott Liggett 59d2d735e6 Added preset names 2022-08-22 09:44:00 -07:00
Elliott Liggett 7e4d3f76d5 Fixed stretched grid color swatch. This has to be a qt uic bug. 2022-08-22 09:04:19 -07:00
Elliott Liggett 92904f8ae5 Forgot the axis color from default. 2022-08-21 23:59:48 -07:00
Elliott Liggett 952585261c Forgot text color from default load-in 2022-08-21 23:54:37 -07:00
Elliott Liggett d11ae30b1a Fixed bug relate to pressing cancel in the color picker. 2022-08-21 23:50:02 -07:00
Elliott Liggett 1388c756c4 Fixed alpha channel issue 2022-08-21 21:51:50 -07:00
Elliott Liggett 16237a47f5 Slightly better closing for settings 2022-08-21 21:32:49 -07:00
Elliott Liggett a84fb6d091 Cleaner tab add/remove code for the settings tab. 2022-08-21 21:19:08 -07:00
Elliott Liggett 93b1af6eb6 Removed unused function 2022-08-21 18:05:20 -07:00
Elliott Liggett ecb9b8fbb4 Now all colors can be edited. 2022-08-21 17:52:52 -07:00
Elliott Liggett 2a509a6177 Color editing for a few parameters is working. Lots of new helper
functions introduced to make coding simpler.
2022-08-21 16:47:17 -07:00
Elliott Liggett ac8a98049e More connections from picker to UI. 2022-08-21 00:33:59 -07:00
Elliott Liggett b77715e0d8 Color preferences. We can now set a single color and also detach the
settings tab.
2022-08-21 00:17:44 -07:00
Phil Taylor 4574e2b7b2 Staged merge of master 2022-08-20 19:43:58 +01:00
Elliott Liggett 4b0ce8537e Added line input to color functions 2022-08-19 10:32:06 -07:00
Elliott Liggett 1423e7c300 Added color picker functions and demonstration UI elements 2022-08-19 09:41:13 -07:00
Roeland Jansen 105675a128 modified version numbers, WHATSNEW and CHANGELOG 2022-08-19 08:12:22 +02:00
Roeland Jansen bd097dc3a5 Merge branch 'plasma' 2022-08-19 07:34:38 +02:00
Elliott Liggett ab65f8e38d Finally remembered to remove annoying commented-out code. 2022-08-18 20:56:24 -07:00
Elliott Liggett 088d34af8b Removed checkbox from prior peak hold mode. 2022-08-18 20:54:50 -07:00
Elliott Liggett d8dc9daa15 One more thing for qcp 1.3 2022-08-18 16:45:58 -07:00
Elliott Liggett a947ba6b18 Added support for qcp 1.3 2022-08-18 16:40:10 -07:00
Elliott Liggett 0e15e8ec1e Merge branch 'plasma' into audiofix 2022-08-18 14:31:22 -07:00
Elliott Liggett 1d14d9520e Fixed issue where spectrum greater than 128 was negative. 2022-08-18 11:52:41 -07:00
Elliott Liggett ebb2c59a45 Added "pre-sorted" flag to plasma average mode plotting. 2022-08-18 11:11:57 -07:00
Elliott Liggett a7587963b0 Fixed issue where the waterfall colors re-scaled to min-max versus user
preference upon wf length change.
2022-08-18 11:07:29 -07:00
Elliott Liggett c59050e632 Removed issue with plasma buffer resizing with the waterfall. 2022-08-18 10:54:54 -07:00
Elliott Liggett 7093ac104a Removed unused variables, corrected spelling. 2022-08-18 10:24:07 -07:00
Elliott Liggett f1f58a10cf Slight reduction in CPU usage with regards to wf, more to come. 2022-08-18 09:56:06 -07:00
Elliott Liggett 7639880861 Fixed issue with the floor and ceiling not updating initially. The
waterfall is now ranged prior to replot each time.
2022-08-17 23:30:02 -07:00
Elliott Liggett b2204b3519 Fixed resize; added mutex. 2022-08-17 22:38:44 -07:00
Elliott Liggett 5215984de8 Minor change for slightly faster averages. 2022-08-17 21:46:47 -07:00
Elliott Liggett 123084c779 Slightly faster plotting due to data being already sorted. 2022-08-17 19:58:04 -07:00
Elliott Liggett 03a279087e Added underlayBufferSize to the preferences. 2022-08-17 18:46:00 -07:00
Elliott Liggett 6ebb3b7680 Added some preferences for the plasma. 2022-08-17 18:41:35 -07:00
Elliott Liggett 32d55ef490 Fixed spectrum line length 2022-08-17 16:34:26 -07:00
Elliott Liggett 53bed16b45 Added floor and ceiling adjustments for the plots. 2022-08-17 16:21:33 -07:00
Elliott Liggett 02e6733cdd Fixed ancient issue with layering of the plot data 2022-08-17 15:51:26 -07:00
Elliott Liggett c753089ac7 Added spectrum plasma metering. 2022-08-17 15:10:07 -07:00
Phil Taylor 9a77baaead Shutdown audio when radio is turned off. 2022-08-04 20:46:15 +01:00
Phil Taylor ac2c104209 Re-order audio handler destructors 2022-07-05 10:37:10 +01:00
Phil Taylor bcc16b8d29 Send blank audio packet on disconnct 2022-07-05 10:31:45 +01:00
Phil Taylor a9e9c80708 Fix silly bug introduced in server audio TX combo 2022-06-14 10:31:45 +01:00
roeland jansen 5dcb0819a8 Merge branch 'master' into 'master'
Added IC-746

See merge request eliggett/wfview!9 

Thanks to Philip Kubat
2022-05-26 15:16:40 +00:00
Roeland Jansen d6263223af dropped openSUSE 15.2, out of support 2022-05-24 17:55:03 +02:00
Roeland Jansen 485d012b42 WHATSNEW 2022-05-24 17:37:19 +02:00
Roeland Jansen b4f379d52d Merge branch 'wfserver' 2022-05-24 11:18:41 +02:00
Phil Taylor 06017148dd Update main.cpp 2022-05-24 10:13:44 +01:00
Phil Taylor 5cb81b412f Try to quit wfserver on ctrl-c 2022-05-24 10:08:18 +01:00
Phil Taylor 227ea8fc34 Small .pro file update and cleanup 2022-05-20 18:25:16 +01:00
Phil Taylor c807c40bd2 Small .pro file update and cleanup 2022-05-20 18:24:28 +01:00
Phil Taylor f2e9a90000 Support newer versions of rtaudio that don't generate exceptions 2022-05-20 15:50:47 +01:00
Phil Taylor cd03ac40d5 Update INSTALL.md 2022-05-19 16:03:06 +00:00
Phil Taylor 62c48ac2c2 Test some shuttle changes 2022-05-17 08:53:24 +01:00
Roeland Jansen 49773706d7 Merge branch 'wfserver' 2022-05-15 13:11:35 +02:00
Phil Taylor 05f7283930 Merge branch 'wfserver' into shuttle 2022-05-14 15:50:26 +01:00
Phil Taylor 079a50980d Fix RT/PA builds on MacOs 2022-05-14 15:05:48 +01:00
Phil Taylor 5ef50c9706 Update rthandler.cpp 2022-05-14 14:02:31 +01:00
Phil Taylor 8f5ba2efb1 Convert audioHandler functions to virtual 2022-05-14 13:54:09 +01:00
Phil Taylor b3f611543c Make RT/PA a subclass of audioHandler 2022-05-14 13:45:56 +01:00
Phil Taylor bcde69c92b Update commhandler.cpp 2022-05-14 11:48:58 +01:00
Phil Taylor 2e1d88c194 Update commhandler.cpp 2022-05-14 11:40:58 +01:00
Phil Taylor d468e01d20 Update commhandler.cpp 2022-05-14 11:39:52 +01:00
Phil Taylor 1305f06eab Update commhandler.cpp 2022-05-14 11:38:35 +01:00
Phil Taylor b049704dd2 Use qtimer to signal a reconnect 2022-05-14 11:35:41 +01:00
Phil Taylor 6078a31a3c Add timeout if no data received on serial port for 2s 2022-05-14 11:24:09 +01:00
Phil Taylor f003a8a1b8 Update commhandler.cpp 2022-05-14 11:13:20 +01:00
Phil Taylor 630d2eaba3 Update commhandler.cpp 2022-05-14 11:10:27 +01:00
Phil Taylor e248882e31 Add reconnect on failure to commHandler() 2022-05-14 11:07:05 +01:00
Phil Taylor 466571a758 Use goto statement for error handling. 2022-05-14 10:41:44 +01:00
Phil Taylor b95cf79318 Update rthandler.cpp 2022-05-14 10:33:31 +01:00
Phil Taylor 50eb498026 Another error check 2022-05-14 10:30:26 +01:00
Phil Taylor 28a3209c21 Update rthandler.cpp 2022-05-14 01:37:03 +01:00
Phil Taylor 35d54468cd Update rthandler.cpp 2022-05-14 01:31:28 +01:00
Phil Taylor 30073d07d7 Update rthandler.cpp 2022-05-14 01:31:04 +01:00
Phil Taylor c1461947eb If audio device fails to open, retry 10 times before giving up. 2022-05-14 01:27:59 +01:00
Phil Taylor 30f9574dd6 If audio device fails to open, retry 10 times before giving up. 2022-05-14 01:27:44 +01:00
Phil Taylor 48562aa23b Don't try to connect to radio we are already connected to 2022-05-14 01:11:36 +01:00
Phil Taylor 8fd8fa390e Fix mod meters in PA/RT 2022-05-14 01:11:35 +01:00
Phil Taylor 22692a6897 Don't try to connect to radio we are already connected to 2022-05-14 01:11:15 +01:00
Phil Taylor 647b51449b Fix mod meters in PA/RT 2022-05-14 01:11:00 +01:00
Phil Taylor f0cec0279c Quick tidy of logging. 2022-05-13 19:16:08 +01:00
Phil Taylor c84cc4330d Add waterfallFormat to wfserver 2022-05-13 18:50:42 +01:00
Phil Taylor 129348c12f Add waterfallFormat to wfserver 2022-05-13 18:45:13 +01:00
Phil Taylor 19c16daa06 Merge branch 'wfserver' into shuttle 2022-05-13 18:32:07 +01:00
Phil Taylor b78f613ef2 Bit of code-tidying and minor fixes 2022-05-13 16:09:26 +01:00
Roeland Jansen 2b9d163613 Merge branch 'wfserver' 2022-05-13 13:43:13 +02:00
Phil Taylor 6a5f9ce988 Portaudio try to find compatible format 2022-05-13 12:35:28 +01:00
Roeland Jansen dccafb9ffb Merge branch 'wfserver' 2022-05-13 11:23:45 +02:00
M0VSE 1aa45dc849 Fix latency display on rtaudio 2022-05-13 10:20:17 +01:00
Roeland Jansen a7671b403d Merge branch 'wfserver' 2022-05-13 11:07:44 +02:00
Phil Taylor 0b74407448 Set default audio device if not found 2022-05-13 09:55:47 +01:00
Phil Taylor 4f4527bc6b Set default audio device if not found 2022-05-13 09:55:16 +01:00
Roeland Jansen 9285809819 Merge branch 'wfserver' 2022-05-13 08:19:23 +02:00
Phil Taylor e75c4873f0 Fix button cmd combos 2022-05-13 00:11:34 +01:00
Phil Taylor 6043e857e1 Fixed vcproj 2022-05-13 00:00:43 +01:00
Phil Taylor 11c0973897 Merge branch 'wfserver' into shuttle 2022-05-12 23:54:48 +01:00
Phil Taylor b28dab4dc2 Use a mutex to protect RT buffer. 2022-05-12 20:30:51 +01:00
Phil Taylor a855c931b6 Add amplitude to output audio 2022-05-12 20:04:30 +01:00
Phil Taylor c90611e444 Fix 8 bit audio encoding. 2022-05-12 20:04:15 +01:00
Phil Taylor 717b71ad4c Update servermain.cpp 2022-05-12 15:57:45 +01:00
Phil Taylor 2e433ed71f Add pa/rt to server 2022-05-12 15:53:48 +01:00
Phil Taylor e6ff2ae152 Update servermain.cpp 2022-05-12 14:29:08 +01:00
Phil Taylor 5eb294dc6d Update servermain.cpp 2022-05-12 13:42:19 +01:00
Phil Taylor 728f01abf4 Update servermain.cpp 2022-05-12 13:39:00 +01:00
Phil Taylor cd1f0f0ba9 Update servermain.cpp 2022-05-12 13:33:34 +01:00
Phil Taylor 33211908bc Update servermain.cpp 2022-05-12 13:27:35 +01:00
Phil Taylor 95ec59d46d make PulseAudio the default 2022-05-12 13:13:59 +01:00
Phil Taylor 6b7387cba2 Update servermain.cpp 2022-05-12 12:35:53 +01:00
Phil Taylor 92b43e8fa2 Update servermain.h 2022-05-12 12:29:29 +01:00
Phil Taylor 578b993f70 Various fixes 2022-05-12 12:24:27 +01:00
Phil Taylor 44f6ec2740 Add back support for portaudo and rtaudio APIs 2022-05-12 01:46:20 +01:00
Roeland Jansen eded80efe8 Merge branch 'wfserver' 2022-05-11 07:41:39 +02:00
Phil Taylor 63c5e0257d Some more tidying 2022-05-11 00:22:08 +01:00
Phil Taylor 04ad04757d More post merge tidying 2022-05-11 00:18:28 +01:00
Phil Taylor 2fa83028d3 Fix merge error 2022-05-11 00:15:06 +01:00
Phil Taylor 772375fb9d Split udpHandler into multiple class files 2022-05-11 00:11:29 +01:00
Phil Taylor 498f5020a5 make latency too high trigger at lower value 2022-05-11 00:01:04 +01:00
Phil Taylor 00f15a059e Add some more audio status 2022-05-10 23:55:18 +01:00
Phil Taylor 30ca8aa44a Try to force 16bit int instead of 8bit uint 2022-05-09 18:51:26 +01:00
Phil Taylor fba9c6f207 Try to force minimum of 48K sample rate for native audio 2022-05-09 18:47:12 +01:00
Roeland Jansen 5694963450 Merge branch 'wfserver' 2022-05-09 11:48:05 +02:00
Phil Taylor 82faf2c463 Remove extra Opus configuration 2022-05-09 10:38:33 +01:00
Phil Taylor 8d924b6fda Configure buffer for input audio 2022-05-09 10:33:30 +01:00
Phil Taylor bddf283e7a Always use "preferred" format where possible 2022-05-09 00:29:07 +01:00
Phil Taylor ec169ca3d4 Fixes to audioconverter 2022-05-08 22:48:39 +01:00
Phil Taylor fda7d21239 Update audioconverter.cpp 2022-05-08 21:48:47 +01:00
Phil Taylor 3e0c008144 Fix if 0 samples detected 2022-05-08 20:57:35 +01:00
Phil Taylor 7098564121 use quit() instead of exit() to cleanly shutdown 2022-05-08 19:44:31 +01:00
Phil Taylor 75f1f2d6ea Update servermain.cpp 2022-05-08 19:37:29 +01:00
Phil Taylor 135640df44 Remove parent from classes that are moved to a thread 2022-05-08 19:35:47 +01:00
Phil Taylor ed3ba16a8d Update udpserver.cpp 2022-05-08 19:33:22 +01:00
Phil Taylor ac677db7ac Change class constructors to include parent 2022-05-08 19:31:05 +01:00
Phil Taylor 066c1b58ac Merge branch 'wfserver' of https://gitlab.com/eliggett/wfview into wfserver 2022-05-08 18:45:35 +01:00
Phil Taylor 7cb31cc8af Update udphandler.cpp 2022-05-08 18:45:22 +01:00
Phil Taylor b8838e2468 some improvements to audio 2022-05-08 18:44:20 +01:00
Roeland Jansen 9ef7fbab0a Merge branch 'wfserver' 2022-05-08 16:08:22 +02:00
Phil Taylor 181c2eeb07 Log when port is being closed 2022-05-08 12:19:35 +01:00
Phil Taylor 3deb7ab6ec Update audioconverter.h 2022-05-08 11:54:42 +01:00
Phil Taylor 376fe72b49 Update audioconverter.h 2022-05-08 11:52:24 +01:00
Phil Taylor 8e38a8efb2 Create function to convert Icom format to QAudioFormat 2022-05-08 11:46:33 +01:00
Roeland Jansen 3308bbeb54 Merge branch 'wfserver' 2022-05-08 11:19:51 +02:00
Phil Taylor 72bef7f783 Fix build for new audioconverter 2022-05-08 10:19:21 +01:00
Roeland Jansen ad71e437a2 Merge branch 'wfserver' 2022-05-08 11:16:35 +02:00
Phil Taylor 71f88cdfed Skip unneeded float conversion for Opus 2022-05-08 10:04:36 +01:00
Phil Taylor bbbb36ebae Remove Opus FEC for now 2022-05-07 11:14:01 +01:00
Phil Taylor 3068b0f5cc Update audiohandler.cpp 2022-05-07 10:54:20 +01:00
Phil Taylor 05c3433bcd More testing 2022-05-07 10:51:02 +01:00
Phil Taylor 1e51e36c9d Backup out of last change 2022-05-07 10:43:28 +01:00
Phil Taylor 0d529b4a1b Update audiohandler.cpp 2022-05-06 23:27:25 +01:00
Phil Taylor de6db645de Update audioconverter.cpp 2022-05-06 23:19:31 +01:00
Phil Taylor 550407e0a9 Update wfserver.pro 2022-05-06 23:15:32 +01:00
Phil Taylor 9118d8f4dc Update audiohandler.cpp 2022-05-06 23:12:29 +01:00
Phil Taylor 78f16b7cff Add experimental audio converter 2022-05-06 23:10:46 +01:00
Roeland Jansen 4125737819 Merge branch 'wfserver' 2022-05-06 08:14:43 +02:00
Phil Taylor 5bd29096e5 Found issue with splitwaterfall function 2022-05-05 18:48:45 +01:00
Phil Taylor 8b958d572c Fix some compile warnings and try to support sharing lan connected rigs 2022-05-05 18:09:16 +01:00
Roeland Jansen 3bc0b4840a WHATSNEW 2022-05-05 13:41:31 +02:00
Roeland Jansen 159d757d53 Merge branch 'wfserver' 2022-05-05 13:41:04 +02:00
Phil Taylor bf5f819927 found another small retransmit bug 2022-05-05 11:16:59 +01:00
Roeland Jansen 7956684f7d Merge branch 'wfserver' 2022-05-05 10:44:22 +02:00
Phil Taylor 7924d2b87f Fix retransmit missing message 2022-05-05 09:01:04 +01:00
Phil Taylor f662d1f7cd Found another retransmit bug in server 2022-05-05 08:57:50 +01:00
Roeland Jansen b3068c269d Merge branch 'wfserver' 2022-05-05 08:41:04 +02:00
Phil Taylor 069c5368d8 More debugging 2022-05-05 02:01:20 +01:00
Phil Taylor 7b5f29f4fe More retransmit debugging 2022-05-05 01:49:21 +01:00
Phil Taylor 4b19ed522f Hopefully fix occasional retransmit bug 2022-05-05 00:31:55 +01:00
Phil Taylor 24841c5da9 Fix debug message 2022-05-05 00:23:42 +01:00
Phil Taylor cac93198a6 Debugging retransmission (again!) 2022-05-05 00:06:50 +01:00
Phil Taylor 85ba0fb569 When using Float, force 32bit as Mac doesn't like it otherwise 2022-05-04 22:29:05 +01:00
Phil Taylor 3aefa68939 More fixes to make client and server behave in same way 2022-05-04 20:37:58 +01:00
Phil Taylor bdca404457 Make udpserver and client behave the same way for retransmit 2022-05-04 20:21:29 +01:00
Phil Taylor f42fbc2e54 Try using float for all audio. Not tested on Linux/Mac 2022-05-04 15:43:34 +01:00
Roeland Jansen df2fb20d78 WHATSNEW 2022-05-03 14:57:34 +02:00
Roeland Jansen 6826586ef6 Merge branch 'wfserver' 2022-05-03 13:15:22 +02:00
Phil Taylor 105d1782ed Remove unnecessary code 2022-05-03 11:21:08 +01:00
Phil Taylor 2b04b84eb1 Fix for uLaw encoding 2022-05-03 10:37:41 +01:00
Roeland Jansen f3bb4655ff Merge branch 'wfserver' 2022-05-03 08:12:37 +02:00
Phil Taylor 8d75d01e2c Set Opus complexity to 7 2022-05-02 17:15:41 +01:00
Phil Taylor 95cace832b Try a reduced complexity on Opus encoder 2022-05-02 16:41:28 +01:00
Phil Taylor 8217b12bc2 Update udpserver.cpp 2022-05-02 16:13:47 +01:00
Phil Taylor a929b2b8a8 Name threads to ease debugging 2022-05-02 16:11:35 +01:00
Phil Taylor 76e52c42db Add parens 2022-05-02 16:01:54 +01:00
Phil Taylor fb99a57272 Tidy some connections 2022-05-02 15:58:41 +01:00
Phil Taylor 43f423f1ad Tidy getnextaudiochunk() 2022-05-02 13:53:49 +01:00
Phil Taylor 92288aa768 Increase late audio timeout to 100ms 2022-05-02 13:08:42 +01:00
Phil Taylor 09ea7a2c26 Try readyRead instead of notify 2022-05-02 13:03:27 +01:00
Phil Taylor 7bf2f54255 Use notify instead of timer for audio input 2022-05-02 12:55:58 +01:00
Phil Taylor fb0d662b40 Add debugging back after revert. 2022-05-02 11:56:40 +01:00
Phil Taylor 94bb78af50 Revert "Add some more debugging when audio is delayed"
This reverts commit bb6c615b4c.
2022-05-02 11:52:23 +01:00
Phil Taylor ab36165d9d Revert "Update audiohandler.cpp"
This reverts commit 7130f71335.
2022-05-02 11:52:09 +01:00
Phil Taylor 8f3a8d38d4 Revert "Update audiohandler.cpp"
This reverts commit 60824c2055.
2022-05-02 11:51:36 +01:00
Phil Taylor 1ba9713408 Revert "Reduce audio polling time"
This reverts commit 26ea3bc3dc.
2022-05-02 11:51:12 +01:00
Phil Taylor 26ea3bc3dc Reduce audio polling time 2022-05-02 11:47:44 +01:00
Phil Taylor 60824c2055 Update audiohandler.cpp 2022-05-02 11:32:28 +01:00
Phil Taylor 7130f71335 Update audiohandler.cpp 2022-05-02 11:29:34 +01:00
Phil Taylor bb6c615b4c Add some more debugging when audio is delayed 2022-05-02 11:22:05 +01:00
Phil Taylor 2525641e76 Update audiohandler.cpp 2022-04-28 12:32:40 +01:00
Phil Taylor 5b50127d0b Replace deprecated hex modifier 2022-04-28 10:52:46 +01:00
Phil Taylor d0df7004ac Improve hex encoding 2022-04-28 10:46:47 +01:00
Phil Taylor ff17a74df8 Make missing packets qInfo instead of qDebug 2022-04-28 10:32:55 +01:00
Phil Taylor a9c21871b2 Update audiohandler.cpp 2022-04-28 10:05:51 +01:00
Phil Taylor 382f0951e5 Try to support all possible native audio formats 2022-04-28 10:02:51 +01:00
Phil Taylor b510b70f04 Add WFVIEW response type back in 2022-04-28 09:42:32 +01:00
Phil Taylor 2ec20ce18b Comment out debug message 2022-04-27 12:58:42 +01:00
Phil Taylor eb85bb1802 Improve logging and some code cleanup 2022-04-27 12:56:54 +01:00
Phil Taylor 7f003c588e Shuttle button commands now working (mostly) 2022-04-26 14:50:16 +01:00
Phil Taylor 41c5637c30 rename counter to jogCounter to make it clearer. 2022-04-26 08:52:08 +01:00
Phil Taylor 8fc9c48d5c Hopefully fix limited range warning 2022-04-26 08:45:57 +01:00
Phil Taylor 49d1cc085a Add default constructor for BUTTON() 2022-04-26 08:41:58 +01:00
Phil Taylor 3ef1950dc2 Add WFVIEW response type back in 2022-04-26 08:40:58 +01:00
Phil Taylor 120bd7d302 Link the correct hidapi library in Linux 2022-04-25 17:55:58 +01:00
Phil Taylor 45b01cafb3 Update shuttlesetup.h 2022-04-25 17:44:32 +01:00
Phil Taylor 96037cd055 Various fixes 2022-04-25 17:40:41 +01:00
Phil Taylor aa002ed0b5 Change band via queue 2022-04-22 14:59:49 +01:00
Phil Taylor 8ee8d23fb9 'Almost' working shuttle support 2022-04-22 11:11:21 +01:00
Phil Taylor fad416c5f3 Merge branch 'wfserver' into shuttle 2022-04-20 15:39:11 +01:00
Roeland Jansen b2d2ee7001 Merge branch 'wfserver' 2022-04-20 14:44:58 +02:00
Phil Taylor 6716a57d5b Fix wfserver 2022-04-20 13:43:45 +01:00
Roeland Jansen e0f50f579f Merge branch 'wfserver' 2022-04-20 14:38:17 +02:00
Phil Taylor 86502a5c3a Various compatibility improvements 2022-04-20 13:35:23 +01:00
Roeland Jansen 5685f6aa67 Merge branch 'wfserver' 2022-04-19 08:15:18 +02:00
Phil Taylor d86f8958b2 Add support for splitting/combining waterfall/scope data 2022-04-18 20:29:50 +01:00
Roeland Jansen 4ba435845b added contributors and whatsnew changes 2022-04-18 14:13:53 +02:00
Roeland Jansen c1f9358d38 updated WHATSNEW and CHANGELOG 2022-04-14 18:02:11 +02:00
Roeland Jansen 2ff36e26b7 bumped versions for wfserver and wfview to 1.2e 2022-04-14 08:20:48 +02:00
Phil Taylor 4fe9b2cba7 Move wfserver configuration and add simple keyboard handler 2022-04-13 12:55:59 +01:00
Phil Taylor a3977395c1 Merge branch 'wfserver' of https://gitlab.com/eliggett/wfview into wfserver 2022-04-11 23:25:30 +01:00
Phil Taylor e834396387 Force 16 bit samples if 24 is requested. 2022-04-11 23:24:56 +01:00
Roeland Jansen b67b43d0cb added eigen3 for suse build 2022-04-11 14:20:24 +02:00
Phil Taylor 55fdf52436 Update audiohandler.cpp 2022-04-11 12:13:48 +01:00
Phil Taylor 7542cc3f56 Update audiohandler.cpp 2022-04-11 12:11:10 +01:00
Phil Taylor b7dee4f5f4 Update audiohandler.cpp 2022-04-11 12:04:40 +01:00
Phil Taylor 2b588ffce0 Switch back to using a timer. 2022-04-11 11:59:38 +01:00
Phil Taylor af2be44919 Update main.cpp 2022-04-11 11:54:06 +01:00
Phil Taylor 1e94a97964 Add time to wfserver debugging 2022-04-11 11:52:57 +01:00
Phil Taylor 718d54ee3b Update audiohandler.cpp 2022-04-11 11:49:48 +01:00
Phil Taylor 9d63c36e51 Update audiohandler.cpp 2022-04-11 11:44:53 +01:00
Phil Taylor c0a1000c9a Update audiohandler.cpp 2022-04-11 11:35:33 +01:00
Phil Taylor 74de3087c8 Update audiohandler.cpp 2022-04-11 11:28:32 +01:00
Phil Taylor 3296e16195 Found bug in server audio 2022-04-11 11:26:52 +01:00
Phil Taylor 3815ac67e7 Update audiohandler.cpp 2022-04-11 09:59:21 +01:00
Phil Taylor ecbac9b48c Update audiohandler.cpp 2022-04-11 09:53:58 +01:00
Phil Taylor 5ba0a382a9 Update audiohandler.cpp 2022-04-11 09:49:25 +01:00
Phil Taylor 4ca21b84cb More opus changes 2022-04-11 00:33:39 +01:00
Phil Taylor 109bdb2812 Update audiohandler.cpp 2022-04-11 00:23:08 +01:00
Phil Taylor 0a711e5c1f Try a different method 2022-04-11 00:05:54 +01:00
Phil Taylor e068bc5745 Fix for opus? 2022-04-10 23:19:45 +01:00
Phil Taylor 50c8b4e545 Change audio output to use single/slot 2022-04-10 23:13:51 +01:00
Phil Taylor a108f1ca99 TX Audio fixes. 2022-04-08 18:55:41 +01:00
Phil Taylor 87c0850c5b Fixed retransmit bug in server code. 2022-04-08 18:42:37 +01:00
Phil Taylor 9e269d774a Add some more startup logging and improve windows startup speed. 2022-04-08 15:51:59 +01:00
Phil Taylor 03b324be1e Set HighDpiScaling attribute 2022-04-08 15:28:46 +01:00
Phil Taylor e87719bfd1 Merge branch 'wfserver' of https://gitlab.com/eliggett/wfview into wfserver 2022-04-08 14:40:43 +01:00
Phil Taylor 1f25ca67e8 Fixes to TCP server and attempt auto port detection on non-linux! 2022-04-08 14:40:05 +01:00
Phil Taylor 2ee20d9415 Fix max build 2022-04-08 12:12:31 +01:00
Phil Taylor 0aaf5de976 Hopefully fix silly retransmit bug 2022-04-08 11:22:33 +01:00
Phil Taylor 87b1a9f84d Change some log messages 2022-04-08 09:58:58 +01:00
Phil Taylor 23b37f2754 Attempt to fix weird retransmission bug 2022-04-08 09:53:02 +01:00
Phil Taylor 2ca376a3c1 Opus now should work with any native sample rate/type 2022-04-07 19:23:38 +01:00
Phil Taylor 4f5e4addb6 Update audiohandler.cpp 2022-04-07 19:04:49 +01:00
Phil Taylor 86237afd8b Update audiohandler.cpp 2022-04-07 18:57:42 +01:00
Phil Taylor c027413ee2 Update audiohandler.cpp 2022-04-07 18:52:43 +01:00
Phil Taylor 2a889488c4 Update audiohandler.cpp 2022-04-07 18:48:47 +01:00
Phil Taylor e4d5efb3d5 Update audiohandler.cpp 2022-04-07 18:37:47 +01:00
Phil Taylor d543f1474d Update audiohandler.cpp 2022-04-07 18:35:44 +01:00
Phil Taylor a21a44df86 Opus issue 2022-04-07 17:35:58 +01:00
Phil Taylor 53cae9173d Use floating point opus encoder/decoder 2022-04-07 16:03:50 +01:00
Phil Taylor 0f7a5566fc Fix underrun handler 2022-04-06 22:02:43 +01:00
Phil Taylor f00051ecd4 Use signal/slot for audio signal reporting 2022-04-06 21:52:22 +01:00
Phil Taylor cfc22dcb30 Allow for 8bit signed (in case computer uses it!) 2022-04-06 19:40:14 +01:00
Phil Taylor 833371530a Enable High DPI Scaling 2022-04-06 19:39:43 +01:00
Phil Taylor 47772a4925 Few more audio fixes 2022-04-05 19:02:29 +01:00
Phil Taylor 38fdec3da6 More tidying and use float resampler 2022-04-05 16:47:43 +01:00
Phil Taylor 45ac1fbe1c Remove ringbuffer as no longer needed 2022-04-04 19:22:11 +01:00
Phil Taylor ac70ba5f83 Add debug to make sure buffer size is really changing 2022-04-04 11:52:59 +01:00
Phil Taylor 2cc875ff7c Try to fix linux audio stopping on latency change 2022-04-04 11:47:55 +01:00
Phil Taylor 64b4ef2019 Few more fixes and move windows builds into separate directories 2022-04-04 11:12:06 +01:00
Phil Taylor cf7a947beb Remove debugging message 2022-04-04 00:37:07 +01:00
M0VSE 5c2d6e57b2 Fix linux compile 2022-04-04 00:23:23 +01:00
Phil Taylor 83c494ecc1 Remove rtaudio/portaudio for now 2022-04-04 00:01:08 +01:00
Phil Taylor 389f661c79 Working (in Windows) audio output 2022-04-03 20:16:52 +01:00
Phil Taylor 8ec62fec8d Merge branch 'master' into wfserver 2022-03-23 17:28:11 +00:00
Phil Taylor acf4c1bf63 Start of test to include Eigen 2022-03-23 17:27:47 +00:00
roeland jansen e5b975038c Merge branch 'fix/typos' into 'master'
Fix spelling errors

See merge request eliggett/wfview!8
2022-03-23 15:45:51 +00:00
Daniele Forsi 32f438aa01 Fix spelling errors 2022-03-23 15:45:51 +00:00
roeland jansen 6bd1395c1a Merge branch 'master' into 'master'
Fixed broken implementation of "set_level RFPOWER" in rigctld

See merge request eliggett/wfview!11
2022-03-23 15:45:23 +00:00
Phil Taylor c5cf0fdf57 Slightly better tcp server implementation (still needs UI adding) 2022-03-23 13:19:05 +00:00
Phil Taylor bfd9ddea52 Initial tcpserver support (needs work) 2022-03-23 10:12:42 +00:00
Russ Woodman - K5TUX 72663310c5 Fixed broken implementation of "set_level RFPOWER" in rigctld 2022-03-19 14:05:46 -05:00
Phil Taylor ece5933d55 Some extra debugging 2022-03-18 15:41:11 +00:00
Philip Kubat 38274cc3c8 Added IC-746 2022-02-07 20:31:29 -05:00
Phil Taylor 468cfa1303 Add metahandler 2022-02-02 16:26:40 +00:00
Phil Taylor feb5d13d13 Add some debugging to find audio/serial ports 2022-02-02 16:07:03 +00:00
Phil Taylor 824a91b125 Few more fixes 2022-02-02 16:02:40 +00:00
Phil Taylor 21a8bbc1a6 Qt 5.9 compatibility 2022-01-30 10:55:12 +00:00
Phil Taylor 156d03706a Update udpserver.cpp 2022-01-30 10:52:40 +00:00
Phil Taylor 46cd6c1e53 Hopefully fix Linux compile error 2022-01-30 10:29:23 +00:00
Phil Taylor 9ae8bc660c Lots more fixes and tweaks 2022-01-29 22:50:58 +00:00
Phil Taylor dd9be7c99c Tuning lost packets 2022-01-28 09:52:26 +00:00
Phil Taylor 30d5858663 Max missing packets slightly less than buffer size 2022-01-28 09:43:53 +00:00
Phil Taylor c0fabb3999 Update udphandler.cpp 2022-01-27 23:51:25 +00:00
Phil Taylor 6427be05b8 Update udphandler.cpp 2022-01-27 23:47:17 +00:00
Phil Taylor be7dbbb395 Missing ; 2022-01-27 23:40:29 +00:00
Phil Taylor 9d2801a505 Improve congestion calculation 2022-01-27 23:39:45 +00:00
Phil Taylor 3568c80fcc Fix mutex 2022-01-27 23:28:34 +00:00
Phil Taylor fe7bdf1345 Flush buffers on excessive missing 2022-01-27 23:24:54 +00:00
Phil Taylor d29c1ddba7 More retransmit fixes 2022-01-27 23:12:07 +00:00
Phil Taylor 3d1e04c556 Fix compile issue 2022-01-27 22:52:50 +00:00
Phil Taylor 77b7462f74 Restore partial QT5.9 compatibility 2022-01-27 22:51:28 +00:00
Phil Taylor bce66393fb Remove unnecessary code 2022-01-27 22:44:30 +00:00
Phil Taylor 2f4fe061b3 Improve missing packet handling 2022-01-27 19:11:16 +00:00
Phil Taylor 4a1be30c40 Non-working standalone server 2022-01-26 09:49:52 +00:00
Phil Taylor 5ae3549ba5 Treat GUID as 16 bytes rather than trying to be clever! 2022-01-23 17:54:40 +00:00
Phil Taylor 87a36426cf Fix some compile warnings 2022-01-23 16:43:58 +00:00
Phil Taylor 264ad231c0 Now supports multiple radios on OEM server 2022-01-23 15:06:31 +00:00
Phil Taylor ff47fbd82f Make radio selection visible when there is more than 1 radio. 2022-01-22 22:53:06 +00:00
Phil Taylor 1c8bc62fcc More linux build fixes 2022-01-22 18:49:07 +00:00
Phil Taylor 45e074783a Hopefully fix linux compile 2022-01-22 18:32:08 +00:00
Phil Taylor 3ff6e7180a Add radio_cap_packet MetaType for server 2022-01-22 15:32:53 +00:00
Phil Taylor 88d2124f35 Add MetaType for radio_cap_packet 2022-01-22 15:28:41 +00:00
Phil Taylor 39540612c7 More multi-radio support (nearly working!) 2022-01-22 15:12:36 +00:00
Phil Taylor 96de9c55fa More work on multi-radio support 2022-01-21 23:58:18 +00:00
Phil Taylor 41e90bb309 Merge branch 'master' into wfserver 2022-01-21 19:23:45 +00:00
Phil Taylor fcc7c9a5dc Lots of changes, mainly for multi-radio support 2022-01-21 19:23:32 +00:00
Elliott Liggett 440429be9f Adjusted window size for radios without spectrum. Thanks K5TUX. 2022-01-20 23:26:46 -08:00
Phil Taylor e4cc2962b3 Fix wfserver linux build 2022-01-18 09:06:23 +00:00
Phil Taylor 4e086ac220 Fix building both wfview and wfserver together 2022-01-18 09:03:41 +00:00
Phil Taylor 9f059c9e73 Fix portaudio build 2022-01-18 08:58:02 +00:00
Phil Taylor bcadb2176b Remove unnecessary signal/slots 2022-01-18 00:18:52 +00:00
Phil Taylor 55baec6100 Only show server status message once 2022-01-18 00:14:37 +00:00
Phil Taylor 4ebfe457c7 Tidying of server code 2022-01-18 00:11:15 +00:00
Phil Taylor 387b26187d Initial server commit 2022-01-17 17:23:55 +00:00
Phil Taylor 28812be8be Buffer for correct latency 2022-01-16 19:17:32 +00:00
Phil Taylor b87e0de05d Force refilling buffer once it has been flushed. 2022-01-16 19:04:44 +00:00
Phil Taylor b691398f6a Increase audio buffer size 2022-01-16 18:54:41 +00:00
Phil Taylor 914477d1dc Tidy code after merge 2022-01-16 18:47:13 +00:00
Phil Taylor ada263efed Merge branch 'master' into audio-enhance 2022-01-16 18:28:36 +00:00
Phil Taylor a75c6e0fdf Zero audio to stop blip at startup 2022-01-15 16:31:50 +00:00
Roeland Jansen 01ea44df0b Merge branch 'master' into settings 2022-01-15 16:01:47 +01:00
Phil Taylor 3abb4bc584 Revert "Try to send outgoing audio every 10ms"
This reverts commit b8f6feacbf.
2022-01-14 20:58:06 +00:00
Phil Taylor b8f6feacbf Try to send outgoing audio every 10ms 2022-01-14 20:55:41 +00:00
Phil Taylor 03799b2cda More fixes 2022-01-14 20:52:25 +00:00
Phil Taylor dcb4712740 Move buffering code 2022-01-14 20:41:56 +00:00
Phil Taylor 7d5ec8a065 Check when audio has been buffered 2022-01-14 20:29:27 +00:00
Phil Taylor b4884e773a Ensure buffer is at least 1/2 filled before starting 2022-01-14 20:23:59 +00:00
Phil Taylor 918238835d Catch excessive missing packets 2022-01-14 20:12:50 +00:00
Phil Taylor 2eace96be9 Set tx/rx gain in server 2022-01-14 19:57:12 +00:00
Phil Taylor ed7d88eb1e Fix that didn't work! 2022-01-14 19:43:48 +00:00
Phil Taylor d9a611e118 Set latency for tx and rx 2022-01-14 19:40:25 +00:00
Phil Taylor 4a200006eb Extra audio debugging 2022-01-14 18:57:20 +00:00
Phil Taylor 02f222355e Set latency for tx and rx 2022-01-14 16:23:01 +00:00
Phil Taylor 5a9342d9a9 Clear audio buffer if it's full 2022-01-14 16:21:32 +00:00
Phil Taylor 94a89dea33 Clear audio buffer if too many packets are delayed 2022-01-14 16:00:05 +00:00
Phil Taylor 317cbd640a Minor fix to retransmit handling 2022-01-14 15:49:35 +00:00
Phil Taylor e00b598fd9 Hopefully improve retransmit search 2022-01-14 14:10:21 +00:00
Phil Taylor ce0544ac6a Ignore single missing audio packet 2022-01-13 21:53:53 +00:00
Phil Taylor 4696fe6824 Set buffer size with a #define 2022-01-13 21:50:43 +00:00
Phil Taylor 99ca97370b Correctly remove items from the buffers! 2022-01-13 21:12:27 +00:00
Phil Taylor 1291990d54 Reduce number of mutex locks during retransmit processing 2022-01-13 20:26:42 +00:00
Phil Taylor 4fa83b79f0 More debugging to isolate audio stalling 2022-01-13 20:16:14 +00:00
Phil Taylor 184af7a582 Add extra debugging 2022-01-13 19:54:43 +00:00
Phil Taylor d4868ae14c Latency on server is wrong way round! 2022-01-13 19:34:34 +00:00
Phil Taylor e00fa26229 trying to find the cause of server audio issue 2022-01-13 11:17:13 +00:00
Phil Taylor 5a92c071d1 Set audio send period on server 2022-01-12 20:01:17 +00:00
Roeland Jansen f8351ad610 Revert "Beginning of the new Settings tab. Does not compile as-is yet."
This reverts commit 0c807f54c2.
2022-01-12 19:19:14 +01:00
Roeland Jansen 9cbcb3aa1c Revert "Brought back the Save Settings button"
This reverts commit 888824f9a4.
2022-01-12 19:19:12 +01:00
Roeland Jansen b85c268f2c Revert "Added more pages."
This reverts commit 700ac53b28.
2022-01-12 19:19:11 +01:00
Roeland Jansen ae5684238c Revert "Working preferences with a list."
This reverts commit 26f15cc9db.
2022-01-12 19:19:09 +01:00
Roeland Jansen 0a42db97c2 Revert "Changed width of list, other minor tweaks."
This reverts commit 6b30cb53bc.
2022-01-12 19:19:06 +01:00
Roeland Jansen 942d7beb99 Revert "Added clock and UTC toggle."
This reverts commit 314d78ad05.
2022-01-12 19:19:04 +01:00
Roeland Jansen 1667df89ba Revert "Slightly wider radio connection box"
This reverts commit 7564239a68.
2022-01-12 19:19:03 +01:00
Roeland Jansen 91d90f2ae6 Revert "Changed the order of the mod source combos"
This reverts commit 9a781c671e.
2022-01-12 19:18:58 +01:00
Roeland Jansen 837cc5fa8b Revert "Larger vsp combo box... seems like it resizes though?"
This reverts commit 37a2c1caf3.
2022-01-12 19:18:57 +01:00
Roeland Jansen eaa7a8edad Revert "Change to width of group box"
This reverts commit c860fa77a1.
2022-01-12 19:18:55 +01:00
Roeland Jansen 809f67ad19 Revert "Changed the enable/disable for some network UI elements."
This reverts commit 7977de42d9.
2022-01-12 19:18:54 +01:00
Roeland Jansen 4f34e54b02 Revert "A little more on the enable/disable UI elements. Should be good."
This reverts commit 8e95919aa9.
2022-01-12 19:18:53 +01:00
Roeland Jansen 9dd9293036 Revert "Masked password input after focus change."
This reverts commit 605a87dec9.
2022-01-12 19:18:52 +01:00
Roeland Jansen d1d0194600 Revert "Integrate server setup into new settings pages"
This reverts commit e1cdcad65b.
2022-01-12 19:18:50 +01:00
Roeland Jansen 54d08c5b8a Revert "Edited some size constraints for better resizing and full-screen mode."
This reverts commit c8b4992bab.
2022-01-12 19:18:35 +01:00
Roeland Jansen 41ec08ecba Revert "Minor typo with the new audio selection combo box, only on PORTAUDIO"
This reverts commit d1165980a9.
2022-01-12 19:18:34 +01:00
Roeland Jansen a231cb086f Revert "Added forced manual RTS setting"
This reverts commit 8dd42ba392.
2022-01-12 19:18:32 +01:00
Roeland Jansen d742c7564a Revert "Allow dynamic restarting of server"
This reverts commit 3f06ab6061.
2022-01-12 19:18:30 +01:00
Roeland Jansen 9e87d35069 Revert "Clear server status when disabled"
This reverts commit 2c82561ff5.
2022-01-12 19:18:29 +01:00
Roeland Jansen 91f4269de8 Revert "Update server users table dynamically"
This reverts commit cf1caf0a0f.
2022-01-12 19:18:27 +01:00
Roeland Jansen f36f4db497 Revert "Fix typo for portaudio/rtaudio builds"
This reverts commit daf94543ac.
2022-01-12 19:18:19 +01:00
Phil Taylor 89ac99b3f9 Bit of tidying 2022-01-07 14:52:33 +00:00
Phil Taylor 82b655cc09 Try to fix lock condition in server 2022-01-07 14:42:32 +00:00
Phil Taylor db702123f9 Keep audio mutex until all processing is done 2022-01-07 12:31:15 +00:00
Phil Taylor 6e44480d6b Revert "Tidying of audio handling"
This reverts commit 5a6ff84892.
2022-01-07 12:28:43 +00:00
Phil Taylor 3036108d6f Revert "Hopefully fix opus issue in last commit?"
This reverts commit 7dd325c3ae.
2022-01-07 12:28:30 +00:00
Phil Taylor 7dd325c3ae Hopefully fix opus issue in last commit? 2022-01-07 12:16:33 +00:00
Phil Taylor 5a6ff84892 Tidying of audio handling 2022-01-07 12:09:36 +00:00
Phil Taylor 6c29eb12a2 Improve FEC operation with opus 2022-01-06 13:44:29 +00:00
Phil Taylor 9284a49469 Try again to fix server restart! 2022-01-06 10:08:36 +00:00
Phil Taylor 43fb31e8d0 reconnect server signal/slots after restart 2022-01-06 10:03:58 +00:00
Phil Taylor 5e2c77b872 Spotted another error in audio settings. 2022-01-06 09:53:47 +00:00
Phil Taylor 3035e5c712 Attempt to enable FEC, not sure if it works though? 2022-01-05 15:27:46 +00:00
Phil Taylor 8bf107fadc Fix a few compile warnings 2022-01-05 14:53:12 +00:00
Phil Taylor 9b8221b32e Ignore wrong ping seq 2022-01-05 14:45:34 +00:00
Phil Taylor f77defd9d7 Fix silly typo which was causing audio crash! 2022-01-05 14:40:40 +00:00
Phil Taylor a91450c90b Maybe fix server audio issue? 2022-01-04 21:30:48 +00:00
Phil Taylor 1611058f77 Maybe fix audio crash? 2022-01-04 21:26:03 +00:00
Phil Taylor 18646ab0cf Add SERVERCONFIG metatype 2022-01-04 19:55:48 +00:00
Phil Taylor fce3a3d6be Try to fix server 2022-01-04 19:50:38 +00:00
Phil Taylor 8ec82e7406 Various tidying in server and client code 2022-01-04 19:04:36 +00:00
Phil Taylor 360ceccdc6 Update wfmain.cpp 2022-01-04 18:42:47 +00:00
Phil Taylor 93e2c5529e Merge branch 'settings' into audio-enhance 2022-01-04 18:40:44 +00:00
Phil Taylor 6f719d8961 Merge branch 'rigctl-enhancement' into audio-enhance 2022-01-04 18:37:07 +00:00
Phil Taylor ff6d0a6a65 Merge settings branch 2022-01-04 18:34:34 +00:00
Phil Taylor 88ebf74e14 Fixes to allow both QT5 and QT6 to compile 2021-12-31 12:06:17 +00:00
Phil Taylor 4203b62327 Quick fixes for v6.2 2021-12-31 00:34:51 +00:00
Phil Taylor 60a1d40549 Fixes to maintain QT6.2 support 2021-12-31 00:30:22 +00:00
Phil Taylor 2a0b79449d Merge 2021-12-31 00:03:05 +00:00
Phil Taylor 7d95f2d863 Merge latest settings changes 2021-12-31 00:02:47 +00:00
Phil Taylor daf94543ac Fix typo for portaudio/rtaudio builds 2021-12-30 18:27:22 +00:00
Phil Taylor cf1caf0a0f Update server users table dynamically 2021-12-30 18:22:34 +00:00
Phil Taylor 2c82561ff5 Clear server status when disabled 2021-12-30 11:24:44 +00:00
Phil Taylor 3f06ab6061 Allow dynamic restarting of server 2021-12-30 11:17:54 +00:00
Elliott Liggett 8dd42ba392 Added forced manual RTS setting 2021-12-30 01:52:23 -08:00
Elliott Liggett d1165980a9 Minor typo with the new audio selection combo box, only on PORTAUDIO
builds.
2021-12-29 19:49:16 -08:00
Elliott Liggett c8b4992bab Edited some size constraints for better resizing and full-screen mode. 2021-12-29 17:52:35 -08:00
Phil Taylor e1cdcad65b Integrate server setup into new settings pages 2021-12-30 00:48:39 +00:00
Elliott Liggett 605a87dec9 Masked password input after focus change. 2021-12-24 08:21:50 -08:00
Elliott Liggett 8e95919aa9 A little more on the enable/disable UI elements. Should be good. 2021-12-23 21:04:53 -08:00
Elliott Liggett 7977de42d9 Changed the enable/disable for some network UI elements. 2021-12-23 21:02:35 -08:00
Elliott Liggett c860fa77a1 Change to width of group box 2021-12-23 20:55:48 -08:00
Elliott Liggett 37a2c1caf3 Larger vsp combo box... seems like it resizes though? 2021-12-23 20:45:58 -08:00
Elliott Liggett 9a781c671e Changed the order of the mod source combos 2021-12-23 20:26:53 -08:00
Elliott Liggett 7564239a68 Slightly wider radio connection box 2021-12-23 20:15:39 -08:00
Elliott Liggett 314d78ad05 Added clock and UTC toggle. 2021-12-23 20:05:34 -08:00
Elliott Liggett 6b30cb53bc Changed width of list, other minor tweaks. 2021-12-23 19:52:56 -08:00
Elliott Liggett 26f15cc9db Working preferences with a list. 2021-12-23 19:45:58 -08:00
Elliott Liggett 700ac53b28 Added more pages. 2021-12-23 19:34:45 -08:00
Elliott Liggett 888824f9a4 Brought back the Save Settings button 2021-12-23 16:52:29 -08:00
Elliott Liggett 0c807f54c2 Beginning of the new Settings tab. Does not compile as-is yet. 2021-12-23 14:30:58 -08:00
Elliott Liggett 4be3398dfa About box updated to include Patreon site and to indicate path for
stylesheet only as applicable.
2021-12-20 14:40:41 -08:00
Roeland Jansen 1dc5cc0428 added 500 Hz step for VFO 2021-12-11 10:49:06 +01:00
Roeland Jansen da9f60e0bc Merge branch 'rigctl-enhancement' 2021-12-10 12:09:32 +01:00
Phil Taylor 60118169e1 Properly handle different rigctld client versions 2021-12-07 14:52:47 +00:00
Phil Taylor 247817077c Add RIT function and other rigctl fixes 2021-12-07 12:32:51 +00:00
Roeland Jansen e729c34ec5 Merge branch 'rigctl-enhancement' 2021-12-06 17:41:55 +01:00
Roeland Jansen 55cda83ec2 WHATSNEW updated 2021-12-06 17:41:11 +01:00
Phil Taylor 81c9563f16 Various changes and fixes to rigctld/rigstate 2021-12-04 19:21:23 +00:00
Phil Taylor e104262bff Merge branch 'master' into rigctl-enhancement 2021-12-04 17:22:36 +00:00
Roeland Jansen 43119e101c removed another swapfile (some day I'll learn..) and normalized WHATSNEW 2021-12-04 18:19:01 +01:00
Roeland Jansen 0d9dfed85e WHATSNEW and CHANGELOG updated 2021-12-04 18:09:32 +01:00
Phil Taylor 0d9c7b5e30 Merge branch 'master' into QT6.2 2021-12-01 10:24:42 +00:00
Phil Taylor d71fb9ef4a Merge branch 'master' into rigctl-enhancement 2021-12-01 10:22:29 +00:00
Phil Taylor b1ef680dbf Another "minor" update for RX only rigs 2021-12-01 10:21:40 +00:00
Phil Taylor f67bed5832 Disable certain TX commands for RX only rigs 2021-12-01 10:13:21 +00:00
Phil Taylor 47b439b741 Rewrite rigstate (again!) 2021-12-01 10:01:05 +00:00
Roeland Jansen 104b395545 missing space 2021-11-26 18:05:32 +01:00
Roeland Jansen 66734b3be0 Merge branch 'audio-enhance' 2021-11-23 08:19:17 +01:00
Phil Taylor 9ca9379f88 Merge branch 'ui-enhance' into rigctl-enhancement 2021-11-23 00:40:46 +00:00
Phil Taylor 10fc10ef82 Merge branch 'master' into rigctl-enhancement 2021-11-23 00:40:05 +00:00
Phil Taylor 8ddf6880ee Windows support files 2021-11-23 00:39:36 +00:00
Phil Taylor c5d2ecb793 Change rigstate to a class 2021-11-23 00:39:10 +00:00
Elliott Liggett ac72eed7c8 Merge remote-tracking branch 'origin/master' into ui-enhance
Also added in changes for the size of the combo audio source boxes.
2021-11-22 13:36:54 -08:00
Phil Taylor 9ba216f1d9 Merge branch 'audio-enhance' of https://gitlab.com/eliggett/wfview into audio-enhance 2021-11-22 10:37:38 +00:00
Phil Taylor ee6889d163 Add mutex within rigState to protect access 2021-11-22 10:37:21 +00:00
Roeland Jansen 9ff394e0cd changed debug command 2021-11-19 20:50:53 +01:00
Roeland Jansen a4a9297747 Merge branch 'audio-enhance' 2021-11-19 20:48:05 +01:00
Phil Taylor b0ffc94ff9 Add more version info 2021-11-19 18:48:15 +00:00
Roeland Jansen 1f4878d453 Merge branch 'audio-enhance' 2021-11-19 19:29:40 +01:00
Phil Taylor d86eb07832 Fix WFVIEW_VERSION in mac/linux 2021-11-19 18:26:45 +00:00
Roeland Jansen 8908f5a34c Merge branch 'audio-enhance' 2021-11-19 19:01:30 +01:00
Phil Taylor 39f07414ee Add --version command line argument and WFVIEW_VERSION #define 2021-11-19 17:52:18 +00:00
Elliott Liggett 13af5c0b1b A little less green in our gray. 2021-11-18 13:13:54 -08:00
Elliott Liggett 1a03214f59 Added size rules for audio source combo boxes. 2021-11-18 13:12:12 -08:00
Roeland Jansen cbaac5fd26 Merge branch 'audio-enhance' 2021-11-18 18:51:19 +01:00
Roeland Jansen 62087bfd5b Merge branch 'master' of gitlab.com:eliggett/wfview 2021-11-18 18:50:28 +01:00
Phil Taylor 62771f6b59 Fix silly bug in retransmit code 2021-11-18 15:17:51 +00:00
Phil Taylor 130d105535 Fix silly bug in retransmit code 2021-11-18 15:17:28 +00:00
Phil Taylor 4743cd126b Fix silly bug in retransmit code 2021-11-18 14:09:09 +00:00
Phil Taylor 9f0673ae71 Fixes to tidy-up QT6.2 support 2021-11-18 14:08:40 +00:00
Phil Taylor 395469daf3 Merge branch 'audio-enhance' into QT6.2 2021-11-18 12:23:27 +00:00
Phil Taylor cc2f2b2576 Remove some extra logging from audio 2021-11-18 12:20:36 +00:00
Phil Taylor 42675ae770 Add mutex for incoming audio on udp and server 2021-11-15 19:28:44 +00:00
Phil Taylor b5591e0867 Force PA to use 48K Sample Rate if default is 44.1K 2021-11-15 15:26:18 +00:00
Phil Taylor 04526db635 Try using slot for audio again 2021-11-15 15:02:00 +00:00
Phil Taylor 0cc2945d28 Server only tries mutex lock for 10ms before giving up. 2021-11-10 20:45:59 +00:00
Roeland Jansen 1503ecd9f7 Merge branch 'audio-enhance' 2021-11-10 20:32:26 +01:00
Phil Taylor c99439e759 Check number of samples in opus packet before attempting decode 2021-11-10 18:07:48 +00:00
Phil Taylor 81c83357f2 Catch exception in opus_decode 2021-11-10 17:44:33 +00:00
Roeland Jansen a2cfc8c064 Merge branch 'audio-enhance' 2021-11-10 08:41:44 +01:00
Phil Taylor bb53558c92 Small changes to audio handler 2021-11-09 15:55:43 +00:00
Roeland Jansen d99b14cc41 Merge branch 'audio-enhance' 2021-11-07 15:43:19 +01:00
Phil Taylor 827614e080 Add SSE2 enhancements to resampler 2021-11-07 14:24:25 +00:00
Phil Taylor f04284db0e Update audiohandler.h 2021-11-07 14:18:20 +00:00
Phil Taylor ca552a0d80 Enable SSE or NEON enhancements for resampler 2021-11-07 14:11:22 +00:00
Phil Taylor 6247611d85 Fix resample ratio for input and output (hopefully!) 2021-11-07 13:49:00 +00:00
Phil Taylor 6fbd9cec70 Create resampleRatio 2021-11-07 13:27:52 +00:00
Roeland Jansen 847e60791f Merge branch 'audio-enhance' 2021-11-07 13:31:28 +01:00
Phil Taylor 1c0f33c721 Close PA stream after stopping it! 2021-11-07 12:16:25 +00:00
Phil Taylor 93869b1bea Fix Linux rtaudio build 2021-11-07 09:58:41 +00:00
Phil Taylor 2b3c016546 Merge branch 'rigs' into audio-enhance 2021-11-07 09:43:02 +00:00
Elliott Liggett 1d03764684 Pulled out some debug code that isn't needed. 2021-11-07 01:28:35 -07:00
Elliott Liggett 0315033f89 Fixed manual rig ID issue with uninitialized variable. 2021-11-07 00:24:08 -07:00
Elliott Liggett 88430db9ac Added override allowing the user-specified CI-V address to also be used
as the Rig ID (model). This is useful for older radios that do not reply
to Rig ID queries. For radios using the default CI-V address, it should
"just work".
2021-11-06 23:59:03 -07:00
Elliott Liggett 863dd6ba95 Merge remote-tracking branch 'origin/rigs' into rigs 2021-11-06 22:50:13 -07:00
Elliott Liggett fe3d645711 Added PTT "snooping" to the commHandler, such that radios needing RTS
set for PTT will work. Includes replying to PTT queries with the RTS
status. There is currently no UI to manually select radios that need
RTS.
2021-11-06 22:49:10 -07:00
Roeland Jansen bd5a233563 deleted a lingering swapfile from one of my vim sessions 2021-11-06 13:10:41 +01:00
Roeland Jansen 35cb1ed053 Merge branch 'audio-enhance' 2021-11-06 13:10:21 +01:00
Roeland Jansen d58a078f70 deleted a lingering swapfile from one of my vim sessions 2021-11-06 13:09:55 +01:00
Roeland Jansen facdd7dfbd Merge branch 'audio-enhance' into rigs 2021-11-06 13:07:30 +01:00
Phil Taylor 35bc1afb4b Change MAX/MIN to use qMax/qMin instead 2021-11-06 10:42:57 +00:00
Phil Taylor 589df71805 Change MAX/MIN to use qMax/qMin instead 2021-11-06 10:42:13 +00:00
Phil Taylor 0f48959a75 Merge remote-tracking branch 'origin/rigs' into audio-enhance 2021-11-06 10:20:11 +00:00
Elliott Liggett 77509aead6 Added RTS PTT support commHandler and rigCommander. RTS is only sent
from rigCommander at this time, the pty is not parsed.
2021-11-05 23:21:36 -07:00
Elliott Liggett cd7ea97242 Added geometry constraints to the transceiver adjustments window, and
disable controls which do not function except for debug builds.
2021-11-05 17:38:07 -07:00
Elliott Liggett 76c5488983 Changed IF/TPBF commands to be "unique priority" inserts. Added "more"
button for extended transceiver controls.
2021-11-05 17:12:19 -07:00
Elliott Liggett a9fb81d8f6 Added an IF Shift-like control for radios with Twin PBF. 2021-11-05 11:52:20 -07:00
Elliott Liggett cecaee397d Added support for IF Shift and Twin Pass-Band Filters. Currently
accessable only via the debug button.
2021-11-05 10:09:31 -07:00
Elliott Liggett 522557c6e8 Added IC-736 FM mode 2021-11-04 20:45:02 -07:00
Elliott Liggett c3bdcf2287 Merge remote-tracking branch 'origin/master' into rigs 2021-11-04 20:39:14 -07:00
Elliott Liggett 12d202cbcd Added code to force IC-736 to rigID 2021-11-04 20:17:50 -07:00
Phil Taylor 2f480e4b82 Use QT Audio by default 2021-11-01 20:39:12 +00:00
Phil Taylor 6f4cf6bbbe remove unneeded audio signal handler 2021-11-01 20:28:04 +00:00
Phil Taylor 0c7bc17382 Add portaudio support 2021-11-01 20:27:33 +00:00
Phil Taylor 43efadbeaa Make switching between audio apis easier (and tidy .pro file) 2021-11-01 12:44:23 +00:00
Phil Taylor 5b0a3620bd Use buffered audio for Linux (was just Mac only) 2021-11-01 11:17:25 +00:00
Phil Taylor ffdcada18c Adjust buffer size depending on latency setting 2021-11-01 09:18:01 +00:00
Phil Taylor 4e5f315f08 Stuff audio buffer directly rather than signal/slot 2021-10-31 23:53:20 +00:00
Roeland Jansen 37205a11da changelog 2021-10-24 18:09:11 +02:00
Roeland Jansen 53d47c16c0 Merge branch 'audio-enhance' 2021-10-24 18:08:04 +02:00
Phil Taylor bab77ebaba Don't block until audio buffer has space 2021-10-22 00:24:30 +01:00
Phil Taylor 2c1272de66 Bit of tidying 2021-10-22 00:24:15 +01:00
Roeland Jansen 511f2b5e98 changes in udp crashes in server side code 2021-10-20 14:54:44 +02:00
Roeland Jansen 52a4016379 Merge branch 'audio-enhance' 2021-10-20 14:49:42 +02:00
Phil Taylor 620d7890cd Tidy-up server shutdown 2021-10-20 12:47:16 +01:00
Phil Taylor 24a88794e6 Trying to find cause of lockup when client disappears 2021-10-20 12:13:18 +01:00
Roeland Jansen c4a9465fb3 pushed 1.2d; fixing some reliability issues w/ wsjtx/rigctld 2021-10-08 10:25:32 +02:00
Phil Taylor b7edb2cf96 Send TX/Freq changes multiple times with rigctld 2021-10-06 23:41:11 +01:00
Roeland Jansen 66912e13b2 changelog 2021-09-26 11:48:18 +02:00
Phil Taylor 6d0ad471c7 Remove duplicate setPriority() 2021-09-22 11:07:07 +01:00
Phil Taylor c712e87373 Fix typo 2021-09-22 11:02:09 +01:00
Phil Taylor 4cb16b105f Add keepalive for linux/mac pty 2021-09-22 10:59:03 +01:00
Phil Taylor 2c5f37d06c Fix alignment of rigname in taskbar 2021-09-22 10:50:07 +01:00
Phil Taylor 18eb9119be Only send RX antenna byte to rig when it has an RX antenna option in rigCaps 2021-09-22 10:39:35 +01:00
Roeland Jansen 21bc02cc25 bumped to 1.2c 2021-09-07 20:32:47 +02:00
Phil Taylor 8b06e9d048 Make rigctld state work for USB connected rigs 2021-09-07 18:04:43 +01:00
Roeland Jansen f7524c7fba fixed warning 2021-09-07 09:01:55 +02:00
Roeland Jansen b37713124b WHATSNEW, CHANGELOG 2021-09-07 08:11:51 +02:00
Roeland Jansen 9413d20906 bumped version to 1.2 beta 2021-09-07 07:55:17 +02:00
Roeland Jansen f1221c6f1b added 25 kHz step for tuning 2021-08-31 09:21:02 +02:00
Roeland Jansen c46eb65974 Merge branch 'audio-enhance' 2021-08-30 10:05:56 +02:00
Phil Taylor bf16dfe19a Experimental support for split mode in rigctld 2021-08-29 11:51:53 +01:00
Phil Taylor 57e68571af Ignore control levels that we don't currently support 2021-08-29 00:25:23 +01:00
Phil Taylor 67c80c2510 Add better detection of ci-v transceive disable 2021-08-29 00:16:31 +01:00
Phil Taylor 0647caa640 Various changes to shuttle, start adding UI 2021-08-28 23:27:18 +01:00
Phil Taylor 52070ddbc4 Merge branch 'master' into shuttle 2021-08-28 00:24:12 +01:00
Phil Taylor b7407fc108 Merge branch 'master' into QT6.2 2021-08-28 00:22:38 +01:00
Roeland Jansen 54d6850aa1 Merge branch 'audio-enhance' 2021-08-27 19:09:16 +02:00
Phil Taylor 97e5ff9ff8 Remove unneeded debugging 2021-08-27 18:07:45 +01:00
Phil Taylor 3a9f9db4a3 Add saving of meter2 state 2021-08-27 18:06:09 +01:00
Phil Taylor 5216b43230 Merge branch 'master' into audio-enhance 2021-08-27 17:18:12 +01:00
Roeland Jansen 8d96c97f3a bumped version to 1.2 alpha for testing 2021-08-27 11:45:45 +02:00
roeland jansen 366676c286 Merge branch 'fix' into 'master'
pttyhandler: add errno.h

See merge request eliggett/wfview!6
2021-08-26 07:13:40 +00:00
Davide Gerhard 71c12b508f
pttyhandler: add errno.h 2021-08-25 19:05:52 +02:00
Phil Taylor 7c9610283c Replace missing ; 2021-08-24 09:34:40 +01:00
Phil Taylor 47d9c52f87 Merge branch 'opus' 2021-08-24 09:24:25 +01:00
Phil Taylor 57b6f955c6 Set audio thread priority in the correct place! 2021-08-24 09:22:40 +01:00
Phil Taylor cffb2bf93a QT6.2 auto update audio comboboxes 2021-08-24 09:20:38 +01:00
Roeland Jansen acb976e68e Merge branch 'ui-enhance' 2021-08-24 07:51:30 +02:00
Phil Taylor 5b1ed2dc35 Set audio thread priority in the correct place! 2021-08-24 00:02:25 +01:00
Phil Taylor 1b3edbfec1 Set 64bit for default build 2021-08-24 00:00:49 +01:00
Phil Taylor af440fbf55 Look at supporting dynamic update of audio devices 2021-08-24 00:00:29 +01:00
Phil Taylor 886b597d56 Set audio thread priority in the correct place! 2021-08-23 23:59:40 +01:00
Elliott Liggett db6a20d3d0 Now with dual meters for everyone! 2021-08-23 14:40:36 -07:00
Phil Taylor 5e6bab9d57 Add RC28 PTT LED 2021-08-23 10:02:16 +01:00
Phil Taylor edef09c8bf Beginning to support QT6.2 2021-08-22 10:16:16 +01:00
Phil Taylor 4bbd06a988 More shuttle changes 2021-08-22 09:34:00 +01:00
Roeland Jansen ed1684a5a3 Merge branch 'ui-enhance' 2021-08-21 13:49:19 +02:00
Elliott Liggett 23ccee8a21 Clear Center readout as well. 2021-08-20 22:23:16 -07:00
Elliott Liggett d9a9a3ba2b Fixed issue where the "none" selection didn't work quite right. Also
fixed the T/R meter switching to clear out invalid readings.
2021-08-20 22:19:47 -07:00
Phil Taylor 58a6477f53 Set audio threads to be realtime priority 2021-08-19 16:34:04 +02:00
Phil Taylor a2d7ae0e56 Set audio threads to be realtime priority 2021-08-19 10:21:30 +01:00
Phil Taylor 65b4538968 Use hidapi statically and set lowest priority for thread 2021-08-19 10:21:09 +01:00
Phil Taylor 87dc468ae9 Merge branch 'master' into shuttle 2021-08-18 22:46:06 +01:00
Phil Taylor c2840f43d9 Update wfview.vcxproj 2021-08-18 12:11:23 +01:00
Phil Taylor 968835e58a Merge branch 'master' into opus 2021-08-18 12:11:14 +01:00
Elliott Liggett f44dd4bda2 Added IC-736 2021-08-17 14:00:37 -07:00
Phil Taylor 4b564aa8fc Merge branch 'opus' of https://gitlab.com/eliggett/wfview into opus 2021-08-17 21:27:59 +01:00
Phil Taylor b8b2892a1b Remove unneeded submodules 2021-08-17 17:54:41 +01:00
Elliott Liggett 390f9500dc Added more support for the IC-9100 2021-08-17 09:35:40 -07:00
Roeland Jansen 0b5a6cce1f dual meter support/WHATSNEW 2021-08-17 16:11:50 +02:00
Elliott Liggett 064d9cc2ce Current scale tic marks on both sides now! 2021-08-16 23:37:50 -07:00
Elliott Liggett 7f44af239a More meter work, fixed some scales and added labels. 2021-08-16 23:25:11 -07:00
Elliott Liggett a09e8c51b8 Better meter fonts 2021-08-16 21:51:45 -07:00
Roeland Jansen 493f2f60d9 WHATSNEW and INSTALL.md: added opus 2021-08-16 14:40:54 +02:00
Phil Taylor fc2d1e24e2 Fix for left over CIV client on server 2021-08-15 14:41:54 +01:00
Phil Taylor 04562a6ca5 Add a bit of logging for creating/destruction of opus 2021-08-15 11:36:08 +01:00
Phil Taylor c5c0046e3a Improve detection of unsupported codec. 2021-08-15 11:19:34 +01:00
Phil Taylor 758724f8af Fix for Opus TX audio 2021-08-14 20:08:11 +01:00
Phil Taylor 21c8b54819 txrate logging wrong 2021-08-14 19:02:04 +01:00
Phil Taylor e5effe6571 And another one 2021-08-14 17:22:20 +01:00
Phil Taylor 484da6e55d More warning removal! 2021-08-14 17:20:40 +01:00
Phil Taylor c7a2561a3f More commenting in rigctld.h 2021-08-14 17:18:35 +01:00
Phil Taylor dc299fc4f7 Is this going to fix 8 bit audio? 2021-08-14 17:15:59 +01:00
Phil Taylor f17e69b4be Comment unused structs from rigctld 2021-08-14 17:15:44 +01:00
Phil Taylor 9d07bbc281 All audio codecs now work in both directions! 2021-08-14 16:27:31 +01:00
Phil Taylor eb5dc0d095 Update audiohandler.cpp 2021-08-14 16:16:11 +01:00
Phil Taylor 9ae9e56399 more 8bit fixes! 2021-08-14 16:11:48 +01:00
Phil Taylor 2b8449d4d3 ulaw encoding test 2021-08-14 16:04:50 +01:00
Phil Taylor 02ba27b6b2 Update audiohandler.cpp 2021-08-14 13:16:39 +01:00
Phil Taylor ac74f8ba5c Update audiohandler.cpp 2021-08-14 13:05:18 +01:00
Phil Taylor 208ed9596c 8 bit encoding fix 2021-08-14 13:02:07 +01:00
Phil Taylor 218dc493e2 Another issue with 8 bit audio 2021-08-14 12:25:50 +01:00
Phil Taylor f84172d5ae Try again to remove debugging! 2021-08-14 12:17:43 +01:00
Phil Taylor e6750be84c Revert "Remove extra opus debugging"
This reverts commit da53f5371b.
2021-08-14 12:08:50 +01:00
Phil Taylor da53f5371b Remove extra opus debugging 2021-08-14 12:03:04 +01:00
Phil Taylor 2214ec7783 Move opus init 2021-08-14 10:29:22 +01:00
Phil Taylor 9ca727ac65 Add some debugging for decoder 2021-08-14 10:11:58 +01:00
Phil Taylor d2098996ac Use radio samplerate for opus 2021-08-14 10:06:17 +01:00
Phil Taylor f5913dc099 Remove big/little endian conversion 2021-08-14 01:01:50 +01:00
Phil Taylor d4023e8b36 More Opus fixes 2021-08-14 00:56:16 +01:00
Phil Taylor e80d12e477 Update audiohandler.cpp 2021-08-14 00:03:26 +01:00
Phil Taylor 88ec30bb49 Update audiohandler.cpp 2021-08-14 00:01:45 +01:00
Phil Taylor 95b10ce465 Update audiohandler.cpp 2021-08-13 23:35:42 +01:00
Phil Taylor aff0e6847c Update audiohandler.cpp 2021-08-13 20:52:18 +01:00
Phil Taylor 28b2a716d1 Update audiohandler.cpp 2021-08-13 20:41:42 +01:00
Phil Taylor b336d1836e Try to fix Opus 2-channel 2021-08-13 20:30:53 +01:00
Phil Taylor eb2f897a81 Merge branch 'master' into opus 2021-08-13 20:15:00 +01:00
Roeland Jansen eb637d2029 WHATSNEW? 2021-08-11 08:47:51 +02:00
Roeland Jansen 4a7dc5d99e changelog 2021-08-11 08:41:45 +02:00
Roeland Jansen e1dae9edd9 Merge branch 'audio-enhance' 2021-08-10 07:59:41 +02:00
Phil Taylor d755d30f83 Add constants to make parsing (hopefully) easier 2021-08-09 17:37:06 +01:00
Roeland Jansen cc002281ab Merge branch 'audio-enhance' 2021-08-09 10:50:49 +02:00
Phil Taylor 953f572673 Fake known functions 2021-08-08 21:09:10 +01:00
Phil Taylor 4d0153741c Fix float warning 2021-08-08 21:03:22 +01:00
Phil Taylor 979442de87 Remove calibration debugging 2021-08-08 17:17:12 +01:00
Phil Taylor 85271c398e Add proper s-meter calibration 2021-08-08 17:14:48 +01:00
Roeland Jansen dfc101eabe Merge branch 'audio-enhance' 2021-08-07 21:35:55 +02:00
Phil Taylor 3a2db789a2 Add ritctl model to rigCaps 2021-08-07 18:34:34 +01:00
Phil Taylor bbb45a01c7 Fix to make wsjt-x work again! 2021-08-07 17:31:55 +01:00
Phil Taylor 84261a49cc Add split/duplex support 2021-08-07 13:34:47 +01:00
Roeland Jansen 932089285d Merge branch 'audio-enhance' 2021-08-07 12:21:22 +02:00
Phil Taylor b2b438f003 Update rigctld.cpp 2021-08-07 11:20:36 +01:00
Roeland Jansen ce63ab1617 Merge branch 'audio-enhance' 2021-08-07 12:18:08 +02:00
Phil Taylor f86aa6e4f6 Correct lack of parentheses in conditionals 2021-08-07 11:16:55 +01:00
Roeland Jansen 69d2a374b6 Merge branch 'audio-enhance' 2021-08-07 11:33:00 +02:00
Phil Taylor 9ca39a0676 Fix typo 2021-08-07 10:04:16 +01:00
Phil Taylor 73e29cd0fd Remove some debug logging 2021-08-07 01:16:02 +01:00
Phil Taylor c4ed4d2de4 More rigctl features/fixes 2021-08-07 01:14:41 +01:00
Phil Taylor a945988671 Fix for get_powerstat 2021-08-06 12:50:56 +01:00
Phil Taylor 6b34d500f3 Update rigctld.cpp 2021-08-06 12:40:58 +01:00
Phil Taylor 797ed3bc5e Add some levels and other functions 2021-08-06 12:37:03 +01:00
Roeland Jansen 2cadd16de2 Merge branch 'audio-enhance' 2021-08-06 10:48:12 +02:00
Phil Taylor 04bd237eb4 Fix compile warnings 2021-08-06 09:47:32 +01:00
Roeland Jansen ec1ce2a3d3 Merge branch 'audio-enhance' 2021-08-06 10:39:25 +02:00
Phil Taylor a112ee43cb Add frequency ranges from rigcaps 2021-08-06 09:25:08 +01:00
Roeland Jansen e9df69f156 Merge branch 'audio-enhance' 2021-08-06 09:32:09 +02:00
Phil Taylor b8345bf77f Move rigctld settings in Ui 2021-08-05 14:45:19 +01:00
Phil Taylor 543b289c99 Fixes for setting freq/mode 2021-08-05 14:15:10 +01:00
Phil Taylor e091ed5254 Support for more rigctld commands 2021-08-05 13:52:06 +01:00
Phil Taylor 273132de89 More fixes to rigctld 2021-08-05 11:29:20 +01:00
Phil Taylor f36cefac3a Change the way rigctl response is built 2021-08-05 11:06:35 +01:00
Roeland Jansen 2a524fca1d Merge branch 'audio-enhance' 2021-08-05 09:08:02 +02:00
Phil Taylor 1e2a0db604 More rigctld fixes 2021-08-05 01:23:15 +01:00
Phil Taylor ee2cf70dc0 Add rigctld config to ui and fix some bugs 2021-08-04 20:49:32 +01:00
Roeland Jansen 3fc75320e4 Merge branch 'linstall' 2021-08-03 20:13:50 +02:00
Roeland Jansen bee4f03edb added derSuessman prefix code 2021-08-02 08:06:19 +02:00
Roeland Jansen 3be08137dd Merge branch 'audio-enhance' 2021-08-02 07:54:51 +02:00
Phil Taylor eddc5d42ba Fix broken 8bit audio 2021-08-01 18:34:32 +01:00
Roeland Jansen 680262b4d2 added derSuessmann additions to have a linux install prefix 2021-08-01 13:58:47 +02:00
Roeland Jansen 4727093578 added derSuessmann additions to have a linux install prefix 2021-08-01 13:55:44 +02:00
roeland jansen 6df36a05be Merge branch 'fedora_install' into 'master'
Fedora build/install notes

See merge request eliggett/wfview!4
2021-08-01 11:07:07 +00:00
Elliott Liggett 4e63a72106 Added a little extra logic, also some cross-platform help, to the custom
stylesheet loader.
2021-07-30 17:30:34 -07:00
Phil Taylor bc0d69ffb5 Merge branch 'master' into opus 2021-07-29 16:18:59 +01:00
Roeland Jansen 2ac1b8c0ac fix: set the style once 2021-07-29 11:28:45 +02:00
Roeland Jansen 7992d6f870 added /usr/local to search path for the stylesheet 2021-07-29 10:53:57 +02:00
Roeland Jansen 3f1fc957ac Merge branch 'ui-enhance' 2021-07-27 12:11:17 +02:00
Roeland Jansen 2403f5352a changelog 2021-07-26 19:50:40 +02:00
Elliott Liggett a777864a0b Fixed error in IC-7410 attenuator spec. 2021-07-26 09:03:09 -07:00
Phil Taylor c312277189 Merge branch 'master' into audio-enhance 2021-07-26 10:56:26 +01:00
Phil Taylor 8983b4e090 Merge branch 'ui-enhance' into audio-enhance 2021-07-26 10:56:04 +01:00
Roeland Jansen ea09647597 Merge branch 'audio-enhance' 2021-07-26 11:31:27 +02:00
Phil Taylor 93ec46e077 Fix for blank username/password in server 2021-07-26 10:27:39 +01:00
Roeland Jansen dd84be71c5 Merge branch 'ui-enhance' 2021-07-25 11:11:31 +02:00
Elliott Liggett 459f15733f Version string to "1.1" 2021-07-24 22:55:28 -07:00
Elliott Liggett 6c27f44ccc Meter now scales the meter bar to fit the avaliable depth. Text should
scale to have the correct aspect ratio. Fixed minor bug in reporting
connection type (always reported serial and then was replaced with
connection status).
2021-07-24 22:53:36 -07:00
Roeland Jansen b5cbc68a38 changelog 2021-07-24 14:38:29 +02:00
Roeland Jansen 944e1ae1cc small changes to INSTAll.md and addition of mint 20.2/openSUSE 15.3 2021-07-24 10:59:01 +02:00
Roeland Jansen 3b209286da Merge branch 'ui-enhance' 2021-07-20 20:56:11 +02:00
Elliott Liggett b512c3e306 Clear out meter values when type is switched. 2021-07-20 11:11:51 -07:00
Phil Taylor 59234f25f7 Allow user to turn off power-down confirmation msgbox 2021-07-20 14:45:44 +01:00
Phil Taylor 44b11ba623 Merge branch 'master' into audio-enhance 2021-07-20 14:30:32 +01:00
Roeland Jansen 5d78f52c97 Merge branch 'ui-enhance' 2021-07-20 08:51:00 +02:00
Elliott Liggett 4fb9177f2c Font sizes are... better... but not perfect. 2021-07-19 23:46:11 -07:00
Roeland Jansen 886ca86a90 Merge branch 'ui-enhance' 2021-07-20 08:07:28 +02:00
Elliott Liggett 274cc65dbf wfview now uses the meter's own balistics (average and peak code). This
makes it very easy to meter any parameter 0-255. Meter Type "meterNone"
or other will display data in "raw" format.
2021-07-19 16:56:04 -07:00
Elliott Liggett decdfe370b Added center tuning for IC-R8600, partially moved meter balistics
(average and peak) to the meter class.
2021-07-18 14:27:21 -07:00
Phil Taylor 1c9edb7cf9 Merge branch 'ui-enhance' into audio-enhance 2021-07-18 11:57:37 +01:00
Phil Taylor f3492ce3d2 Merge branch 'ui-enhance' into audio-enhance 2021-07-18 11:56:37 +01:00
Roeland Jansen b8ab1b966d Merge branch 'ui-enhance' 2021-07-18 12:45:50 +02:00
Elliott Liggett fd82de2647 Quick debug for the metering queue, just in case. 2021-07-18 00:03:04 -07:00
Elliott Liggett dc6b4884d6 unknown change confusion 2021-07-17 23:42:18 -07:00
Elliott Liggett a501ddf51e Merge branch 'ui-enhance' of gitlab.com:eliggett/wfview into ui-enhance 2021-07-17 23:40:50 -07:00
Elliott Liggett 027815f4c0 Preliminary secondary meter support. See Settings tab for selection.
Some scales incomplete.
2021-07-17 23:39:40 -07:00
Roeland Jansen a29b821bdb Merge branch 'ui-enhance' 2021-07-17 18:43:43 +02:00
Phil Taylor 98f29d2bde Replace function wrongly deleted by merge 2021-07-17 12:07:52 +01:00
Phil Taylor 62e3e2b8d8 Fix wrongly deleted definition 2021-07-17 12:04:48 +01:00
Phil Taylor 166e714c26 Merge branch 'ui-enhance' into audio-enhance 2021-07-17 12:02:04 +01:00
Phil Taylor 0764ad73e0 Merge branch 'ui-enhance' of https://gitlab.com/eliggett/wfview into ui-enhance 2021-07-17 12:01:01 +01:00
Phil Taylor 357716206a Merge branch 'ui-enhance' into audio-enhance 2021-07-17 11:58:31 +01:00
Phil Taylor df690e0fd1 Merge branch 'sequence' into audio-enhance 2021-07-17 11:49:44 +01:00
Elliott Liggett 8257a3540f Added SWR and ALC scales to the meter. 2021-07-17 00:37:27 -07:00
Elliott Liggett c9692f63a6 Fix error in scale of power meter 2021-07-16 23:23:29 -07:00
Elliott Liggett b6a4e06fe2 Power meter for transmit. Much work remains on this meter alone. 2021-07-16 17:45:07 -07:00
Phil Taylor 0440097f53 Add missing break 2021-07-16 20:14:59 +01:00
Phil Taylor e4dea63029 Get antenna status on start-up and slow poll for it. 2021-07-16 19:33:15 +01:00
Phil Taylor e40545cf77 Add RX antenna selection for rigs that support it 2021-07-16 17:08:55 +01:00
Roeland Jansen 6a6a45d079 Merge branch 'sequence' 2021-07-15 08:52:21 +02:00
Elliott Liggett 21b9be4f94 Preferences added for Anti-Alias and Interpolate. 2021-07-14 22:44:05 -07:00
Phil Taylor f191775acb Merge branch 'sequence' into audio-enhance 2021-07-14 12:00:02 +01:00
Roeland Jansen 050e449df7 Merge branch 'sequence' 2021-07-14 10:29:40 +02:00
Elliott Liggett 54f2dcd5b8 Added waterfall display options: anti-alias and interpolate. Not in
preferences yet. Debug button enables wf pan and zoom.
2021-07-13 22:42:55 -07:00
Roeland Jansen 8a49e0267d Merge branch 'sequence' 2021-07-12 18:47:53 +02:00
Phil Taylor d12906d7d3 Merge branch 'sequence' into audio-enhance 2021-07-12 09:15:17 +01:00
Roeland Jansen 2f329904f6 Merge branch 'audio-enhance' 2021-07-11 18:55:57 +02:00
Phil Taylor 99b1e7f407 Allow user to select whether to confirm exit or not 2021-07-11 17:30:02 +01:00
Elliott Liggett d54562469d Reset PTT timer for control-R keystroke. 2021-07-09 23:59:32 -07:00
Elliott Liggett 2e9c734b64 Added a fix to keep the local frequency in-sync with any recent commands
sent to the radio.
2021-07-09 18:13:11 -07:00
Elliott Liggett b6cac33ee9 Added more support for the IC-7600 in rigCaps. 2021-07-09 15:15:04 -07:00
Elliott Liggett e50b032716 Added time, date, and UTC offset commands. Currently initiated by the
debug button. There seems to be a bug in the 7300 where the UTC offset
has one hour subtracted, ie, -7 HRS becomes -8 HRS. The hex command
appears to be sent correctly.
2021-07-09 12:02:50 -07:00
Elliott Liggett 23869fdcd2 Changed wording about the need for Save Settings -- please verify, I may
have it wrong.
2021-07-08 15:31:35 -07:00
Elliott Liggett 0a9f7639e1 Merge remote-tracking branch 'origin/master' into sequence 2021-07-08 10:15:50 -07:00
Elliott Liggett ff5cebf475 Merge remote-tracking branch 'origin/audio-enhance' into sequence 2021-07-08 08:42:14 -07:00
Phil Taylor 445a4157b7 Fix merge error 2021-07-08 15:43:54 +01:00
Phil Taylor 20f3e70d2a Merge branch 'audio-enhance' into shuttle 2021-07-08 15:35:44 +01:00
Phil Taylor f4cdcccfec Only start audio when stream is ready 2021-07-06 10:06:30 +01:00
Phil Taylor 27e8577efe Only start audio when stream is ready 2021-07-06 10:04:35 +01:00
Phil Taylor eb81196238 Merge branch 'master' into shuttle 2021-06-30 09:22:44 +01:00
Phil Taylor 05d9c16eb9 Merge branch 'sequence' into opus 2021-06-26 19:09:58 +01:00
Phil Taylor b071e8d788 Revert "Check whether data is nullptr in doCmd"
This reverts commit c25040f793.
2021-06-26 19:09:41 +01:00
Phil Taylor 6d58034a41 Revert "Move nullptr check to modefilter"
This reverts commit 19f33d1ed7.
2021-06-26 19:09:24 +01:00
Phil Taylor 19f33d1ed7 Move nullptr check to modefilter 2021-06-26 10:58:54 +01:00
Phil Taylor c25040f793 Check whether data is nullptr in doCmd 2021-06-26 10:52:38 +01:00
Phil Taylor 51a2d10937 Remove unnecessary escape sequence 2021-06-26 10:13:35 +01:00
Phil Taylor 1b626b4417 Fix for fix of missing __PRETTY_FUNCTION__ 2021-06-26 10:12:39 +01:00
Phil Taylor fbb4f778c4 Add __PRETTY_FUNCTION__ for compilers that don't have it. 2021-06-26 10:05:00 +01:00
Phil Taylor 605b7686aa Merge branch 'sequence' into opus 2021-06-26 09:55:54 +01:00
Phil Taylor 4002d7f341 Merge remote-tracking branch 'origin/sequence' into opus 2021-06-26 09:55:06 +01:00
Phil Taylor 0258ae8bf9 Remove extra debugging for Opus and add warning where opus isn't available 2021-06-23 20:25:45 +01:00
Phil Taylor 8917ffabc2 Merge remote-tracking branch 'origin/sequence' into opus 2021-06-21 09:20:42 +01:00
Phil Taylor 4b88620a5e Merge remote-tracking branch 'origin/sequence' into opus 2021-06-21 09:08:09 +01:00
Phil Taylor d5a785c675 Merge remote-tracking branch 'origin/sequence' into opus 2021-06-20 10:52:59 +01:00
Phil Taylor 0329ea65b3 Update audiohandler.cpp 2021-06-19 14:09:27 +01:00
Phil Taylor 4e827b4507 Merge remote-tracking branch 'origin/sequence' into opus 2021-06-19 00:11:58 +01:00
Phil Taylor b9551edf36 More opus work 2021-06-19 00:11:25 +01:00
Phil Taylor 9323c2bab4 Merge remote-tracking branch 'origin/sequence' into opus 2021-06-18 23:48:03 +01:00
Phil Taylor 17f186354e Mono opus working ok but stereo still crashing? 2021-06-18 23:47:22 +01:00
Phil Taylor bbf981cc24 Trying to fix stereo opus stream 2021-06-17 09:55:09 +01:00
Phil Taylor 74382b29ee Enable FEC for Opus codec 2021-06-16 23:44:59 +01:00
Phil Taylor 7c0b2a51b1 Another attempt for Opus audio 2021-06-16 19:14:21 +01:00
Phil Taylor db1dbef168 Try converting to Big endian first 2021-06-16 19:00:56 +01:00
Phil Taylor d3db0484af Another opus fix 2021-06-16 10:38:54 +01:00
Phil Taylor 579d670a75 Another opus try 2021-06-16 10:35:45 +01:00
Phil Taylor 6a5e7692e6 Fixes for opus 2021-06-16 10:33:16 +01:00
Phil Taylor 55a38c55ea Fix opus include directory 2021-06-16 09:52:47 +01:00
Phil Taylor 869659ad54 Add opus encoding/decoding 2021-06-16 09:49:38 +01:00
Phil Taylor be979108e8 Hopefully fix the occasional 0xe1 packet from hitting the pty 2021-06-10 17:22:31 +01:00
Phil Taylor 725914d045 Merge branch 'audio-enhance' into shuttle 2021-06-10 12:18:30 +01:00
Phil Taylor 389ea9c831 fourth and (hopefully) final attempt 2021-06-10 09:41:56 +01:00
Phil Taylor 1f1e489cf3 Third attempt to get messages from server! 2021-06-10 09:35:29 +01:00
Phil Taylor 8fb894f076 Use correct location for statusupdate! 2021-06-10 09:30:24 +01:00
Phil Taylor 133fb1cf32 Indicate when TX is not available 2021-06-10 09:20:05 +01:00
Phil Taylor 24133a4f70 Show server connection status in taskbar (only for USB connected rigs) 2021-06-10 09:09:11 +01:00
Phil Taylor 7e40f7faf0 Allow sender or receiver to be 0xe1 in server 2021-06-09 16:31:09 +01:00
Phil Taylor b5676b7773 Always forward wfview traffic to wfview clients 2021-06-09 08:31:34 +01:00
Phil Taylor a0c6243528 Truncate wfview.log on open 2021-06-08 19:12:01 +01:00
Phil Taylor 62eef7f0f4 Merge branch 'audio-enhance' into shuttle 2021-06-08 18:07:51 +01:00
Elliott Liggett b2c4bbf7f8 Better baud rate management for LAN-connected radios. 2021-06-08 08:58:11 -07:00
Phil Taylor f9bc4e3122 Update wfview.vcxproj 2021-06-08 08:14:57 +01:00
Phil Taylor 28ba131135 Improve shuttle control 2021-06-08 08:04:41 +01:00
Phil Taylor 4704b0dc4d Start removal of unused variables 2021-06-08 08:03:00 +01:00
Phil Taylor 7603201886 Start adding support for RC28 2021-06-07 14:05:57 +01:00
Phil Taylor 871c7106b6 Check that we have at least 1 audio channel available. 2021-06-07 14:04:52 +01:00
Phil Taylor ec12e31163 Revert "Check that we have enough audio channels available."
This reverts commit 1cbf77ade0.
2021-06-07 14:03:18 +01:00
Phil Taylor 1cbf77ade0 Check that we have enough audio channels available. 2021-06-07 14:02:55 +01:00
Phil Taylor d877efd234 Improve audio cleanup 2021-06-07 12:31:58 +01:00
Phil Taylor 0366d5ccb4 Add extra debugging for UDP server CIV 2021-06-07 12:27:04 +01:00
Phil Taylor 3f23b0fdb4 Make only MacOS use buffered audio 2021-06-07 10:58:58 +01:00
Phil Taylor 942866ee65 Shuttle support for mac 2021-06-07 10:40:30 +01:00
Phil Taylor 4483a252b6 Improve mac audio 2021-06-07 10:40:04 +01:00
Phil Taylor 14f78c1b36 Various fixes to udpserver 2021-06-06 22:22:36 +01:00
Phil Taylor ccebdb6840 Make QTMultimedia default 2021-06-06 22:22:02 +01:00
Phil Taylor 8b975218d5 Fix to allow rtaudio to compile again 2021-06-06 22:21:27 +01:00
Phil Taylor e271c29c41 Add latency check to TX audio 2021-06-05 08:42:32 +01:00
Phil Taylor 70df0ecfd9 Fix incorrect use of latency setting 2021-06-05 08:26:58 +01:00
Phil Taylor ef3beecc64 Add conditional for linux/winows compile 2021-06-05 08:26:39 +01:00
M0VSE 4159e535fc Fix compile errors on Linux 2021-06-05 01:10:31 +01:00
Phil Taylor fbf28be5db Might work for linux? Needs libhidapi-dev 2021-06-05 00:26:00 +01:00
Phil Taylor 05b8fe5f7c First attempt at shuttleXpress support
Needs lots of work!
2021-06-05 00:23:16 +01:00
Phil Taylor 7b9a911079 Merge branch 'rtaudio' into shuttle 2021-06-04 14:43:27 +01:00
Phil Taylor 6f6bf3387f More changes 2021-06-04 13:08:14 +01:00
Phil Taylor 8a16b467dc Use timer to shuttle data 2021-06-04 11:14:01 +01:00
Phil Taylor 84a4e7c871 Changes for shuttle 2021-06-01 17:48:19 +01:00
Phil Taylor 8037dac05e Merge branch 'rtaudio' into shuttle 2021-06-01 00:29:10 +01:00
Phil Taylor acbbd40c37 playing around with shuttle connection 2021-05-27 08:49:35 +01:00
Steve Netting f8beed5531 added Fedora build/install notes 2021-05-26 16:21:32 +03:00
139 zmienionych plików z 48387 dodań i 8166 usunięć

8
.gitignore vendored
Wyświetl plik

@ -3,4 +3,10 @@
.qmake.stash
debug
release
ui_*
wfview-debug
wfserver-debug
wfview-release
wfserver-release
ui_*
portaudio_x86.dll
qcustomplot2.dll

6
.gitmodules vendored
Wyświetl plik

@ -1,6 +0,0 @@
[submodule "opus-tools"]
path = opus-tools
url = https://github.com/xiph/opus-tools.git
[submodule "rtaudio"]
path = rtaudio
url = https://github.com/thestk/rtaudio.git

16029
CHANGELOG

Plik diff jest za duży Load Diff

109
CI-V.md 100644
Wyświetl plik

@ -0,0 +1,109 @@
## this is a merged list of CI-V addresses, type of interface(s), rates and all.
It has been merged from many sources but the most important ones are these:
1) https://www.docksideradio.com/Icom%20Radio%20Hex%20Addresses.htm
2) http://www.plicht.de/ci-v/civ-bus-adressing/
3) https://www.icomjapan.com/support/manual/
first of all a list that appears not to be a known CI-V address in use:
| model | addr |
| ----- | ---- |
|? | 0x06 |
|? | 0x36 |
|? | 0x54 |
|? | 0x7E |
|? | 0x82 |
|? | 0x84 |
|? | 0x8A |
|? | 0x90 |
|? | 0x92 |
|? | 0x9E |
|? | 0xA0 |
|? | 0xA8 |
|? | 0xAA |
and here the list of known CI-V addresses
| model | addr | year | interface | rate |
| ------------ | ---- | ---- | -------------------------------------- | ---- |
| IC-1271 | 0x24 | 1987 | TTL | auto |
| IC-1275 | 0x18 | 1989 | TTL | auto |
| IC-271 | 0x20 | 1983 | TTL | auto |
| IC-275 | 0x10 | 1987 | TTL | auto |
| IC-375 | 0x12 | 198? | TTL | auto |
| IC-471 | 0x22 | 1984 | TTL | auto |
| IC-475 | 0x14 | 1987 | TTL | auto |
| IC-575 | 0x16 | 1988 | TTL | auto |
| IC-7000 | 0x70 | 2005 | TTL | auto |
| IC-703 | 0x68 | 2003 | TTL | auto |
| IC-705 | 0xA4 | 2020 | USB, Bluetooth, Wifi | auto |
| IC-706 | 0x48 | 1995 | TTL | auto |
| IC-706MkII | 0x4E | 1997 | TTL | auto |
| IC-706MkII-G | 0x58 | 1998 | TTL | auto |
| IC-707 | 0x3E | 1993 | TTL | auto |
| IC-7100 | 0x88 | 2012 | TTL | auto |
| IC-718 | 0x5E | 2001 | TTL | auto |
| IC-7200 | 0x76 | 2007 | TTL | auto |
| IC-725 | 0x28 | 1988 | TTL | 1200 |
| IC-726 | 0x30 | 1989 | TTL | auto |
| IC-728 | 0x38 | 1992 | TTL | 1200 |
| IC-729 | 0x3A | 1992 | TTL | 9600 |
| IC-7300 | 0x94 | 2016 | TTL, USB | auto |
| IC-735 | 0x04 | 1985 | TTL | 1200 |
| IC-736 | 0x40 | 1994 | TTL | 9600 |
| IC-737 | 0x3C | 1993 | TTL | 9600 |
| IC-738 | 0x44 | 1994 | TTL | 9600 |
| IC-7410 | 0x80 | 2011 | TTL, USB | auto |
| IC-746 | 0x56 | 1998 | TTL | auto |
| IC-746Pro | 0x66 | 2001 | TTL | auto |
| IC-751A | 0x1C | 1985 | TTL | 1200 |
| IC-756 | 0x50 | 1997 | TTL | auto |
| IC-756Pro | 0x5C | 2000 | TTL | auto |
| IC-756ProII | 0x64 | 2001 | TTL | auto |
| IC-756ProIII | 0x6E | 2004 | TTL | auto |
| IC-7600 | 0x7A | 2009 | TTL, USB | auto |
| IC-7610 | 0x98 | 2017 | TTL, USB, Ethernet | auto |
| IC-761 | 0x1E | 1987 | TTL | 1200 |
| IC-765 | 0x2C | 1989 | TTL | 1200 |
| IC-7700 | 0x74 | 2007 | TTL, RS-232C 9 pin, Ethernet | auto |
| IC-775 | 0x46 | 1995 | TTL | auto |
| IC-7800 | 0x6A | 2004 | TTL, RS-232C 9 pin, Ethernet | auto |
| IC-78 | 0x62 | 2000 | TTL | auto |
| IC-781 | 0x26 | 1987 | TTL | 1200 |
| IC-785x | 0x8E | 2015 | TTL, USB, Ethernet | auto |
| IC-820 | 0x42 | 1994 | TTL | auto |
| IC-821 | 0x4C | 1996 | TTL | auto |
| IC-905 | 0xAC | 2023 | USB, Ethernet | auto |
| IC-9100 | 0x7C | 2010 | TTL, USB | auto |
| IC-910 | 0x60 | 2001 | TTL | auto |
| IC-9700 | 0xA2 | 2019 | TTL, USB, Ethernet | auto |
| IC-970 | 0x2E | 1990 | TTL | auto |
| IC-R10 | 0x52 | 1996 | TTL | auto |
| IC-R20 | 0x6C | 2004 | TTL | auto |
| IC-R30 | 0x9C | 2018 | TTL, Bluetooth | auto |
| IC-R7000 | 0x08 | 1986 | TTL | auto |
| IC-R7100 | 0x34 | 1991 | TTL | auto |
| IC-R71 | 0x1A | 1984 | TTL | auto |
| IC-R72 | 0x32 | 1992 | TTL | auto |
| IC-R75 | 0x5A | 1999 | TTL, RS-232C 9 pin | auto |
| IC-R8500 | 0x4A | 1996 | TTL, RS-232C 25 pin | auto |
| IC-R8600 | 0x96 | 2017 | TTL, USB, Ethernet | auto |
| IC-R9000 | 0x2A | 1989 | TTL | auto |
| IC-R9500 | 0x72 | 2007 | TTL, RS-232C 9 pin, Ethernet | auto |
| IC-RX7 | 0x78 | 2007 | TTL | auto |
| ID-4100 | 0x9A | 2017 | TTL, Bluetooth | auto |
| ID-5100 | 0x8C | 2014 | TTL, Bluetooth | auto |
| ID-51 | 0x86 | 2012 | TTL | auto |
| ID-52 | 0xA6 | 2021 | TTL, Bluetooth | auto |

Wyświetl plik

@ -6,3 +6,12 @@ the following people currently contribute to this Project:
- Jim PA8E
- Phil M0VSE
- Roeland PA3MET
Also contributions by:
Daniele Forsi <dforsi@gmail.com>
Russ Woodman - K5TUX <k5tux@k5tux.us>
(and some others I will add too)

Wyświetl plik

@ -13,6 +13,12 @@ sudo apt-get install libqt5multimedia5
sudo apt-get install libqt5multimedia5-plugins
sudo apt-get install qtmultimedia5-dev
sudo apt-get install git
sudo apt-get install libopus-dev
sudo apt-get install libeigen3-dev
sudo apt-get install portaudio19-dev
sudo apt-get install librtaudio-dev
sudo apt-get install libhidapi-dev libqt5gamepad5-dev
sudo apt-get install libudev-dev
~~~
Now you need to install qcustomplot. There are two versions that are commonly found in linux distros: 1.3 and 2.0. Either will work fine. If you are not sure which version your linux install comes with, simply run both commands. One will work and the other will fail, and that's fine!
@ -40,15 +46,16 @@ git clone https://gitlab.com/eliggett/wfview.git
~~~
### 3. Create a build directory, compile, and install:
If you want to change the default install path from `/usr/local` to a different prefix (e.g. `/opt`), you must call `qmake ../wfview/wfview.pro PREFIX=/opt`
~~~
mkdir build
cd build
qmake ../wfview/wfview.pro
make -j
sudo ./install.sh
sudo make install
~~~
### 4. You can now launch wfview, either from the terminal or from your desktop environment. If you encounter issues using the serial port, run the following command:
~~~
@ -65,17 +72,17 @@ sudo usermod -aG dialout $USER
~~~
### opensuse/sles/tumbleweed install ###
### opensuse/sles/tumbleweed install
---
install wfview on suse 15.x sles 15.x or tumbleweed; this was done on a clean install/updated OS.
install wfview on suse 15.3 & up, sles 15.x or tumbleweed; this was done on a clean install/updated OS.
we need to add packages to be able to build the stuff.
- sudo zypper in --type pattern devel_basis
- sudo zypper in libQt5Widgets-devel libqt5-qtbase-common-devel libqt5-qtserialport-devel libQt5SerialPort5 qcustomplot-devel libqcustomplot2 libQt5PrintSupport-devel libqt5-qtmultimedia-devel
- sudo zypper in libQt5Widgets-devel libqt5-qtbase-common-devel libqt5-qtserialport-devel libQt5SerialPort5 qcustomplot-devel libqcustomplot2 libQt5PrintSupport-devel libqt5-qtmultimedia-devel lv2-devel libopus-devel eigen3-devel libQt5Xml-devel portaudio-devel rtaudio-devel libqt5-qtgamepad-devel libQt5Gamepad5
now get and install qt5:
optional (mainly for development specifics): get and install qt5:
- wget http://download.qt.io/official_releases/online_installers/qt-unified-linux-x64-online.run
- chmod +x qt-unified-linux-x64-online.run
@ -89,6 +96,30 @@ when done, create the place where to build:
in this case, use your homedir:
- mkdir -p ~/src/build && cd src
- git clone https://gitlab.com/eliggett/wfview.git
- cd build
- qmake-qt5 ../wfview/wfview.pro (wfserver.pro if you build the server version)
- make -j
- sudo make install
wfview is now installed in /usr/local/bin
---
### Fedora install ###
---
Tested under Fedora 33/34.
Install qt5 dependencies:
- sudo dnf install qt5-qtbase-common qt5-qtbase qt5-qtbase-gui qt5-qtserialport qt5-qtmultimedia mingw64-qt5-qmake qt5-qtbase-devel qt5-qtserialport-devel qt5-qtmultimedia-devel libopus-dev
Install qcustomplot:
- sudo dnf install qcustomplot qcustomplot-devel
When done, create a build area, clone the repo, build and install:
- mkdir -p ~/src/build && cd src
- git clone https://gitlab.com/eliggett/wfview.git
- cd build
@ -98,4 +129,34 @@ in this case, use your homedir:
wfview is now installed in /usr/local/bin
Fedora 36:
2023-04-11/Knud OZ1DGN
Precondition:
F36 KDE plasma desktop
wfview 1.61 prebuild binary
Install following packages:
sudo dnf install qcustomplot-qt5 qt5-qtmultimedia qt5-qtserialport rtaudio portaudio hidapi qt5-qtgamepad
sudo ln -s /usr/lib64/libqcustomplot-qt5.so.2 /usr/lib64/libqcustomplot.so.2
Move /usr/share/wfview to /usr/local/share:
sudo mv /usr/share/wfview/stylesheets/* /usr/local/share/wfview
# How to configure your RC-28 knob under Linux
To use RC-28 knob you need to add udev rules, please execute as root:
~~~
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="0c26", ATTRS{idProduct}=="001e", MODE="0666"' >> /etc/udev/rules.d/99-ham-wfview.rules
udevadm control --reload-rules && udevadm trigger
~~~
---

Wyświetl plik

@ -1,4 +1,4 @@
# How to install wfview without building yourself on selected linux versions
# How to install wfview without building yourself on selected linux versions
@ -22,10 +22,12 @@ Debian 11 (Debian 10 is outdated)
Fedora 33
Fedora 34
mint 20.1 (and up?)
openSUSE 15.x
openSUSE Tumbleweed
openSUSE 15.2 (outdated/deprecated)
openSUSE 15.3/15.4)
openSUSE Tumbleweed(s)
SLES 15.x
Ubuntu 20.04.2 and up (?)
Ubuntu 20.04.2
mint 20.2 (see notes at the end)
~~~
@ -69,12 +71,29 @@ note: if the above symlink fails, use the following line to fix the library link
sudo ln -s /lib/x86_64-linux-gnu/libqcustomplot.so.2.0.1 /lib/x86_64-linux-gnu/libqcustomplot.so.2
~~~
### openSUSE/Tumbleweed/SLES:
### Mint 20.2
~~~
SEE THE NOTES AT THE END. You need wfview153 binary here
sudo apt install libqcustomplot2.0 libqt5multimedia5 libqt5serialport5
sudo ln -s /usr/lib64/libqcustomplot-qt5.so.2 /usr/lib64/libqcustomplot.so.2
wfview
note: if the above symlink fails, use the following line to fix the library link:
sudo ln -s /lib/x86_64-linux-gnu/libqcustomplot.so.2.0.1 /lib/x86_64-linux-gnu/libqcustomplot.so.2
~~~
### openSUSE/Tumbleweed/SLES based on 15.3/15.4:
~~~
sudo zypper in libqcustomplot2 libQt5SerialPort5
wfview
~~~
### UBUNTU:
~~~
sudo apt install libqcustomplot2.0 libqt5multimedia5 libqt5serialport5
@ -89,4 +108,12 @@ sudo ln -s /lib/x86_64-linux-gnu/libqcustomplot.so.2.0.1 /lib/x86_64-linux-gnu/l
### notes:
~~~
openSUSE 15.2 is deprecated; old binary has been removed
~~~

Wyświetl plik

@ -14,7 +14,7 @@ Other models to be tested/added (including the IC-705)..
website - [WFVIEW](https://wfview.org/) wfview.org
wfview supports viewing the spectrum display waterfall and most normal radio controls. Using wfview, the radio can be operated using the mouse, or just the keyboard (great for those with visual impairments), or even a touch screen display. The gorgous waterfall spectrum can be displayed on a monitor of any size, and can even projected onto a wall for a presentation. Even a VNC session can make use of wfview for interesting remote rig posibilities. wfview runs on humble hardware, ranging from the $35 Raspberry Pi, to laptops, to desktops. wfview is designed to run on GNU Linux, but can probably be adapted to run on other operating systems. In fact we do have working example in windows as well.
wfview supports viewing the spectrum display waterfall and most normal radio controls. Using wfview, the radio can be operated using the mouse, or just the keyboard (great for those with visual impairments), or even a touch screen display. The gorgous waterfall spectrum can be displayed on a monitor of any size, and can even projected onto a wall for a presentation. Even a VNC session can make use of wfview for interesting remote rig possibilities. wfview runs on humble hardware, ranging from the $35 Raspberry Pi, to laptops, to desktops. wfview is designed to run on GNU Linux, but can probably be adapted to run on other operating systems. In fact we do have working example in windows as well.
@ -29,16 +29,16 @@ wfview is copyright 2017-2020 Elliott H. Liggett. All rights reserved. wfview so
2. Double-click anywhere on the bandscope or waterfall to tune the radio.
3. Entry of frequency is permitted under the "Frequency" tab. Buttons are provided for touch-screen control
4. Bandscope parameters (span and mode) are adjustable.
5. Full [keyboard](https://gitlab.com/eliggett/wfview/-/wikis/Keystrokes) and mouse control. Operate in whichever way you like. Most radio functions can be operated from a numberic keypad! This also enables those with visual impairments to use the IC-7300.
5. Full [keyboard](https://gitlab.com/eliggett/wfview/-/wikis/Keystrokes) and mouse control. Operate in whichever way you like. Most radio functions can be operated from a numeric keypad! This also enables those with visual impairments to use the IC-7300.
6. 100 user memories stored in plain text on the computer
7. Stylable GUI using CSS
8. pseudo-terminal device, which allows for secondary program to control the radio while wfview is running
9. works for radios that support the ethernet interface with compareable waterfall speeds as on the radio itself.
9. works for radios that support the ethernet interface with comparable waterfall speeds as on the radio itself.
### Build Requirements:
1. gcc / g++ / make
2. qmake
3. qt5 (proably the package named "qt5-default")
3. qt5 (probably the package named "qt5-default")
4. libqt5serialport5-dev
5. libqcustomplot-dev

Wyświetl plik

@ -0,0 +1,16 @@
this file contains known limits and things that maybe needs fixing..
7851
repeater controls:
- quick split does not work correct?
- split does not work correct?
- M <--> S "change" works
- M => S "M = S" works
- autotrack "track" works but is slow?

Wyświetl plik

@ -42,7 +42,7 @@ on/off switch for the scope/waterfall
wf theme
Currently fixed selections how the scope and waterfall look like
with colors. At som epoint we may add the ability to accept the
with colors. At some point we may add the ability to accept the
RGB values like the rig does.

Wyświetl plik

@ -1,16 +1,15 @@
The following highlights are in this dot-release:
The following highlights are in this 1.6x-release since v1.60:
added IC7700, 718, 7100. (more testing needed)
fixes and improvements to audio
ability to choose between rtaudio and qtmultimedia (default) as compile time option
fixes and lots of improvements at the usb-server end
waterfall length can be adjusted now
no need to restart to change CIV address
seamless changing rigs without restart
started support for older rigs like the 718
wf display disappears when there is no wf capable rig
IC R8600 support improved
for older rigs added a polling timing box to keep stuff keeping smooth
Local af gain now has anti-log audio pot taper.
+1.60 released
+1.61 many small fixes for several platforms
+1.62 cw side tone added
performance fix for 9700
+1.63 started adding IC-905 (obviously untested)
started multi-usb
Notes:
- We know about high CPU usage on RPi.
- try the audiostack you like the most/what works for you

Wyświetl plik

@ -12,22 +12,30 @@ aboutbox::aboutbox(QWidget *parent) :
ui->logoBtn->setIcon(QIcon(":resources/wfview.png"));
ui->logoBtn->setStyleSheet("Text-align:left");
ui->topText->setText("wfview version 1.1a");
ui->topText->setText("wfview version " + QString(WFVIEW_VERSION));
QString head = QString("<html><head></head><body>");
QString copyright = QString("Copyright 2017-2021 Elliott H. Liggett, W6EL. All rights reserved. wfview source code is <a href=\"https://gitlab.com/eliggett/wfview/-/blob/master/LICENSE\">licensed</a> under the GNU GPLv3.");
QString nacode = QString("<br/><br/>Networking, audio, rigctl server, and much more written by Phil Taylor, M0VSE");
QString doctest = QString("<br/><br/>Testing, documentation, bug fixes, and development mentorship from<br/>Roeland Jansen, PA3MET, and Jim Nijkamp, PA8E.");
QString copyright = QString("Copyright 2017-2023 Elliott H. Liggett, W6EL and Phil E. Taylor, M0VSE. All rights reserved.<br/>wfview source code is <a href=\"https://gitlab.com/eliggett/wfview/-/blob/master/LICENSE\">licensed</a> under the GNU GPLv3.");
QString scm = QString("<br/><br/>Source code and issues managed by Roeland Jansen, PA3MET");
QString doctest = QString("<br/><br/>Testing and development mentorship from Jim Nijkamp, PA8E.");
QString dedication = QString("<br/><br/>This version of wfview is dedicated to the ones we lost.");
#if defined(Q_OS_LINUX)
QString ssCredit = QString("<br/><br/>Stylesheet <a href=\"https://github.com/ColinDuquesnoy/QDarkStyleSheet/tree/master/qdarkstyle\" style=\"color: cyan;\">qdarkstyle</a> used under MIT license, stored in /usr/share/wfview/stylesheets/.");
#else
QString ssCredit = QString("<br/><br/>Stylesheet <a href=\"https://github.com/ColinDuquesnoy/QDarkStyleSheet/tree/master/qdarkstyle\" style=\"color: cyan;\">qdarkstyle</a> used under MIT license.");
#endif
QString website = QString("<br/><br/>Please visit <a href=\"https://wfview.org/\" style=\"color: cyan;\">https://wfview.org/</a> for the latest information.");
QString donate = QString("<br/><br/>Join us on <a href=\"https://www.patreon.com/wfview\">Patreon</a> for a behind-the-scenes look at wfview development, nightly builds, and to support the software you love.");
QString docs = QString("<br/><br/>Be sure to check the <a href=\"https://wfview.org/wfview-user-manual/\" style=\"color: cyan;\">User Manual</a> and <a href=\"https://forum.wfview.org/\" style=\"color: cyan;\">the Forum</a> if you have any questions.");
QString support = QString("<br/><br/>For support, please visit <a href=\"https://forum.wfview.org/\">the official wfview support forum</a>.");
QString gitcodelink = QString("<a href=\"https://gitlab.com/eliggett/wfview/-/tree/%1\" style=\"color: cyan;\">").arg(GITSHORT);
QString contact = QString("<br/>email W6EL: kilocharlie8@gmail.com");
QString contact = QString("<br/>email W6EL: kilocharlie8 at gmail.com");
QString buildInfo = QString("<br/><br/>Build " + gitcodelink + QString(GITSHORT) + "</a> on " + QString(__DATE__) + " at " + __TIME__ + " by " + UNAME + "@" + HOST);
QString end = QString("</body></html>");
@ -77,8 +85,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.");
// String it all together:
QString aboutText = head + copyright + "\n" + nacode + "\n" + doctest + wfviewcommunityack;
aboutText.append(website + "\n"+ docs + support + contact +"\n");
QString aboutText = head + copyright + "\n" + "\n" + scm + "\n" + doctest + dedication + wfviewcommunityack;
aboutText.append(website + "\n" + donate + "\n"+ docs + support + contact +"\n");
aboutText.append("\n" + ssCredit + "\n" + rsCredit + "\n");
#if defined(RTAUDIO)

360
audioconverter.cpp 100644
Wyświetl plik

@ -0,0 +1,360 @@
#include "audioconverter.h"
#include "logcategories.h"
#include "ulaw.h"
audioConverter::audioConverter(QObject* parent) : QObject(parent)
{
}
bool audioConverter::init(QAudioFormat inFormat, codecType inCodec, QAudioFormat outFormat, codecType outCodec, quint8 opusComplexity, quint8 resampleQuality)
{
this->inFormat = inFormat;
this->inCodec = inCodec;
this->outFormat = outFormat;
this->outCodec = outCodec;
this->opusComplexity = opusComplexity;
this->resampleQuality = resampleQuality;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qInfo(logAudioConverter) << "Starting audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
if (inFormat.byteOrder() != outFormat.byteOrder()) {
qInfo(logAudioConverter) << "Byteorder mismatch in:" << inFormat.byteOrder() << "out:" << outFormat.byteOrder();
}
#else
qInfo(logAudioConverter) << "Starting audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleFormat() <<
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleFormat();
#endif
if (inCodec == OPUS)
{
// Create instance of opus decoder
int opus_err = 0;
opusDecoder = opus_decoder_create(inFormat.sampleRate(), inFormat.channelCount(), &opus_err);
qInfo(logAudioConverter()) << "Creating opus decoder: " << opus_strerror(opus_err);
}
if (outCodec == OPUS)
{
// Create instance of opus encoder
int opus_err = 0;
opusEncoder = opus_encoder_create(outFormat.sampleRate(), outFormat.channelCount(), OPUS_APPLICATION_AUDIO, &opus_err);
//opus_encoder_ctl(opusEncoder, OPUS_SET_LSB_DEPTH(16));
//opus_encoder_ctl(opusEncoder, OPUS_SET_INBAND_FEC(1));
//opus_encoder_ctl(opusEncoder, OPUS_SET_DTX(1));
//opus_encoder_ctl(opusEncoder, OPUS_SET_PACKET_LOSS_PERC(5));
opus_encoder_ctl(opusEncoder, OPUS_SET_COMPLEXITY(opusComplexity)); // Reduce complexity to maybe lower CPU?
qInfo(logAudioConverter()) << "Creating opus encoder: " << opus_strerror(opus_err);
}
if (inFormat.sampleRate() != outFormat.sampleRate())
{
int resampleError = 0;
unsigned int ratioNum;
unsigned int ratioDen;
// Sample rate conversion required.
resampler = wf_resampler_init(outFormat.channelCount(), inFormat.sampleRate(), outFormat.sampleRate(), resampleQuality, &resampleError);
wf_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
resampleRatio = static_cast<double>(ratioDen) / ratioNum;
qInfo(logAudioConverter()) << "wf_resampler_init() returned: " << resampleError << " resampleRatio: " << resampleRatio;
}
return true;
}
audioConverter::~audioConverter()
{
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qInfo(logAudioConverter) << "Closing audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
#else
qInfo(logAudioConverter) << "Closing audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleFormat() <<
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleFormat();
#endif
if (opusEncoder != Q_NULLPTR) {
qInfo(logAudioConverter()) << "Destroying opus encoder";
opus_encoder_destroy(opusEncoder);
}
if (opusDecoder != Q_NULLPTR) {
qInfo(logAudioConverter()) << "Destroying opus decoder";
opus_decoder_destroy(opusDecoder);
}
if (resampler != Q_NULLPTR) {
speex_resampler_destroy(resampler);
qDebug(logAudioConverter()) << "Resampler closed";
}
}
bool audioConverter::convert(audioPacket audio)
{
// If inFormat and outFormat are identical, just emit the data back (removed as it doesn't then process amplitude)
if (audio.data.size() > 0)
{
if (inCodec == OPUS)
{
unsigned char* in = (unsigned char*)audio.data.data();
//Decode the frame.
int nSamples = opus_packet_get_nb_samples(in, audio.data.size(), inFormat.sampleRate());
if (nSamples == -1) {
// No opus data yet?
return false;
}
QByteArray outPacket(nSamples * sizeof(float) * inFormat.channelCount(), (char)0xff); // Preset the output buffer size.
float* out = (float*)outPacket.data();
int ret = opus_decode_float(opusDecoder, in, audio.data.size(), out, nSamples, 0);
if (ret != nSamples)
{
qDebug(logAudio()) << "opus_decode_float: returned:" << ret << "samples, expected:" << nSamples;
}
audio.data.clear();
audio.data = outPacket; // Replace incoming data with converted.
}
else if (inCodec == PCMU)
{
// Current packet is "technically" 8bit so need to create a new buffer that is 16bit
QByteArray outPacket((int)audio.data.length() * 2, (char)0xff);
qint16* out = (qint16*)outPacket.data();
for (int f = 0; f < audio.data.length(); f++)
{
*out++ = ulaw_decode[(quint8)audio.data[f]];
}
audio.data.clear();
audio.data = outPacket; // Replace incoming data with converted.
// Make sure that sample size/type is set correctly
}
Eigen::VectorXf samplesF;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 32)
#else
if (inFormat.sampleFormat() == QAudioFormat::Int32)
#endif
{
Eigen::Ref<VectorXint32> samplesI = Eigen::Map<VectorXint32>(reinterpret_cast<qint32*>(audio.data.data()), audio.data.size() / int(sizeof(qint32)));
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint32>::max());
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
else if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 16)
#else
else if (inFormat.sampleFormat() == QAudioFormat::Int16)
#endif
{
Eigen::Ref<VectorXint16> samplesI = Eigen::Map<VectorXint16>(reinterpret_cast<qint16*>(audio.data.data()), audio.data.size() / int(sizeof(qint16)));
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint16>::max());
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
else if (inFormat.sampleType() == QAudioFormat::UnSignedInt && inFormat.sampleSize() == 8)
#else
else if (inFormat.sampleFormat() == QAudioFormat::UInt8)
#endif
{
Eigen::Ref<VectorXuint8> samplesI = Eigen::Map<VectorXuint8>(reinterpret_cast<quint8*>(audio.data.data()), audio.data.size() / int(sizeof(quint8)));
samplesF = samplesI.cast<float>() / float(std::numeric_limits<quint8>::max());;
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
else if (inFormat.sampleType() == QAudioFormat::Float)
#else
else if (inFormat.sampleFormat() == QAudioFormat::Float)
#endif
{
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(audio.data.data()), audio.data.size() / int(sizeof(float)));
}
else
{
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qInfo(logAudio()) << "Unsupported Input Sample Type:" << inFormat.sampleType() << "Size:" << inFormat.sampleSize();
#else
qInfo(logAudio()) << "Unsupported Input Sample Format:" << inFormat.sampleFormat();
#endif
}
if (samplesF.size() > 0)
{
audio.amplitudePeak = samplesF.array().abs().maxCoeff();
//audio.amplitudeRMS = samplesF.array().abs().mean(); // zero for tx audio
//audio.amplitudeRMS = samplesF.norm() / sqrt(samplesF.size()); // too high values. Zero for tx audio.
//audio.amplitudeRMS = samplesF.squaredNorm(); // tx not zero. Values higher than peak sometimes
//audio.amplitudeRMS = samplesF.norm(); // too small values. also too small on TX
//audio.amplitudeRMS = samplesF.blueNorm(); // scale same as norm, too small.
// Set the volume
samplesF *= audio.volume;
/*
samplesF is now an Eigen Vector of the current samples in float format
The next step is to convert to the correct number of channels in outFormat.channelCount()
*/
if (inFormat.channelCount() == 2 && outFormat.channelCount() == 1) {
// If we need to drop one of the audio channels, do it now
Eigen::VectorXf samplesTemp(samplesF.size() / 2);
samplesTemp = Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesF.data(), samplesF.size() / 2);
samplesF = samplesTemp;
}
else if (inFormat.channelCount() == 1 && outFormat.channelCount() == 2) {
// Convert mono to stereo if required
Eigen::VectorXf samplesTemp(samplesF.size() * 2);
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data(), samplesF.size()) = samplesF;
Eigen::Map<Eigen::VectorXf, 0, Eigen::InnerStride<2> >(samplesTemp.data() + 1, samplesF.size()) = samplesF;
samplesF = samplesTemp;
}
/*
Next step is to resample (if needed)
*/
if (resampler != Q_NULLPTR && resampleRatio != 1.0)
{
quint32 outFrames = ((samplesF.size() / outFormat.channelCount()) * resampleRatio);
quint32 inFrames = (samplesF.size() / outFormat.channelCount());
QByteArray outPacket(outFrames * outFormat.channelCount() * sizeof(float), (char)0xff); // Preset the output buffer size.
const float* in = (float*)samplesF.data();
float* out = (float*)outPacket.data();
int err = 0;
if (outFormat.channelCount() == 1) {
err = wf_resampler_process_float(resampler, 0, in, &inFrames, out, &outFrames);
}
else {
err = wf_resampler_process_interleaved_float(resampler, in, &inFrames, out, &outFrames);
}
if (err) {
qInfo(logAudioConverter()) << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
}
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(outPacket.data()), outPacket.size() / int(sizeof(float)));
}
/*
If output is Opus so encode it now, don't do any more conversion on the output of Opus.
*/
if (outCodec == OPUS)
{
float* in = (float*)samplesF.data();
QByteArray outPacket(1275, (char)0xff); // Preset the output buffer size to MAXIMUM possible Opus frame size
unsigned char* out = (unsigned char*)outPacket.data();
int nbBytes = opus_encode_float(opusEncoder, in, (samplesF.size() / outFormat.channelCount()), out, outPacket.length());
if (nbBytes < 0)
{
qInfo(logAudioConverter()) << "Opus encode failed:" << opus_strerror(nbBytes) << "Num Samples:" << samplesF.size();
return false;
}
else {
outPacket.resize(nbBytes);
audio.data.clear();
audio.data = outPacket; // Copy output packet back to input buffer.
//samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(outPacket.data()), outPacket.size() / int(sizeof(float)));
}
}
else {
/*
Now convert back into the output format required
*/
audio.data.clear();
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
if (outFormat.sampleType() == QAudioFormat::UnSignedInt && outFormat.sampleSize() == 8)
#else
if (outFormat.sampleFormat() == QAudioFormat::UInt8)
#endif
{
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint8>::max());
samplesITemp.array() += 127;
VectorXuint8 samplesI = samplesITemp.cast<quint8>();
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(quint8)));
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
else if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 16)
#else
else if (outFormat.sampleFormat() == QAudioFormat::Int16)
#endif
{
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint16>::max());
VectorXint16 samplesI = samplesITemp.cast<qint16>();
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint16)));
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
else if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 32)
#else
else if (outFormat.sampleFormat() == QAudioFormat::Int32)
#endif
{
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint32>::max());
VectorXint32 samplesI = samplesITemp.cast<qint32>();
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32)));
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
else if (outFormat.sampleType() == QAudioFormat::Float)
#else
else if (outFormat.sampleFormat() == QAudioFormat::Float)
#endif
{
audio.data = QByteArray(reinterpret_cast<char*>(samplesF.data()), int(samplesF.size()) * int(sizeof(float)));
}
else {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qInfo(logAudio()) << "Unsupported Output Sample Type:" << outFormat.sampleType() << "Size:" << outFormat.sampleSize();
#else
qInfo(logAudio()) << "Unsupported Output Sample Type:" << outFormat.sampleFormat();
#endif
}
/*
As we currently don't have a float based uLaw encoder, this must be done
after all other conversion has taken place.
*/
if (outCodec == PCMU)
{
QByteArray outPacket((int)audio.data.length() / 2, (char)0xff);
qint16* in = (qint16*)audio.data.data();
for (int f = 0; f < outPacket.length(); f++)
{
qint16 sample = *in++;
int sign = (sample >> 8) & 0x80;
if (sign)
sample = (short)-sample;
if (sample > cClip)
sample = cClip;
sample = (short)(sample + cBias);
int exponent = (int)MuLawCompressTable[(sample >> 7) & 0xFF];
int mantissa = (sample >> (exponent + 3)) & 0x0F;
int compressedByte = ~(sign | (exponent << 4) | mantissa);
outPacket[f] = (quint8)compressedByte;
}
audio.data.clear();
audio.data = outPacket; // Copy output packet back to input buffer.
}
}
}
else
{
qDebug(logAudioConverter) << "Detected empty packet";
}
}
emit converted(audio);
return true;
}

172
audioconverter.h 100644
Wyświetl plik

@ -0,0 +1,172 @@
#ifndef AUDIOCONVERTER_H
#define AUDIOCONVERTER_H
#include <QObject>
#include <QByteArray>
#include <QTime>
#include <QMap>
#include <QDebug>
#include <QAudioFormat>
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <QAudioOutput>
#else
#include <QMediaDevices>
#include <QAudioDevice>
#include <QAudioSource>
#include <QAudioSink>
#endif
/* Opus and Eigen */
#ifdef Q_OS_WIN
#include "opus.h"
#include <Eigen/Eigen>
#else
#include "opus/opus.h"
#include <eigen3/Eigen/Eigen>
#endif
#include "wfviewtypes.h"
#include "resampler/speex_resampler.h"
#include "packettypes.h"
struct audioPacket {
quint32 seq;
QTime time;
quint16 sent;
QByteArray data;
quint8 guid[GUIDLEN];
float amplitudePeak;
float amplitudeRMS;
qreal volume = 1.0;
};
struct audioSetup {
audioType type;
QString name;
quint16 latency;
quint8 codec;
bool ulaw = false;
bool isinput;
quint32 sampleRate;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
QAudioDeviceInfo port;
#else
QAudioDevice port;
#endif
int portInt;
quint8 resampleQuality;
unsigned char localAFgain;
quint16 blockSize = 20; // Each 'block' of audio is 20ms long by default.
quint8 guid[GUIDLEN];
};
class audioConverter : public QObject
{
Q_OBJECT
public:
explicit audioConverter(QObject* parent = nullptr);;
~audioConverter();
public slots:
bool init(QAudioFormat inFormat, codecType inCodec, QAudioFormat outFormat, codecType outCodec, quint8 opusComplexity, quint8 resampleQuality);
bool convert(audioPacket audio);
signals:
void converted(audioPacket audio);
protected:
QAudioFormat inFormat;
QAudioFormat outFormat;
OpusEncoder* opusEncoder = Q_NULLPTR;
OpusDecoder* opusDecoder = Q_NULLPTR;
SpeexResamplerState* resampler = Q_NULLPTR;
quint8 opusComplexity;
quint8 resampleQuality = 4;
double resampleRatio=1.0; // Default resample ratio is 1:1
quint32 lastAudioSequence;
codecType inCodec;
codecType outCodec;
};
// Various audio handling functions declared inline
typedef Eigen::Matrix<quint8, Eigen::Dynamic, 1> VectorXuint8;
typedef Eigen::Matrix<qint8, Eigen::Dynamic, 1> VectorXint8;
typedef Eigen::Matrix<qint16, Eigen::Dynamic, 1> VectorXint16;
typedef Eigen::Matrix<qint32, Eigen::Dynamic, 1> VectorXint32;
static inline QAudioFormat toQAudioFormat(quint8 codec, quint32 sampleRate)
{
QAudioFormat format;
/*
0x01 uLaw 1ch 8bit
0x02 PCM 1ch 8bit
0x04 PCM 1ch 16bit
0x08 PCM 2ch 8bit
0x10 PCM 2ch 16bit
0x20 uLaw 2ch 8bit
0x40 Opus 1ch
0x80 Opus 2ch
*/
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
format.setByteOrder(QAudioFormat::LittleEndian);
format.setCodec("audio/pcm");
#endif
format.setSampleRate(sampleRate);
if (codec == 0x01 || codec == 0x20) {
/* Set sample to be what is expected by the encoder and the output of the decoder */
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
format.setSampleSize(16);
format.setSampleType(QAudioFormat::SignedInt);
format.setCodec("audio/PCMU");
#else
format.setSampleFormat(QAudioFormat::Int16);
#endif
}
if (codec == 0x02 || codec == 0x08) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
format.setSampleSize(8);
format.setSampleType(QAudioFormat::UnSignedInt);
#else
format.setSampleFormat(QAudioFormat::UInt8);
#endif
}
if (codec == 0x08 || codec == 0x10 || codec == 0x20 || codec == 0x80) {
format.setChannelCount(2);
} else {
format.setChannelCount(1);
}
if (codec == 0x04 || codec == 0x10) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
format.setSampleSize(16);
format.setSampleType(QAudioFormat::SignedInt);
#else
format.setSampleFormat(QAudioFormat::Int16);
#endif
}
if (codec == 0x40 || codec == 0x80) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
format.setSampleSize(32);
format.setSampleType(QAudioFormat::Float);
format.setCodec("audio/opus");
#else
format.setSampleFormat(QAudioFormat::Float);
#endif
}
return format;
}
#endif

453
audiodevices.cpp 100644
Wyświetl plik

@ -0,0 +1,453 @@
/*
wfview class to enumerate audio devices and assist with matching saved devices
Written by Phil Taylor M0VSE Nov 2022.
*/
#include "audiodevices.h"
#include "logcategories.h"
audioDevices::audioDevices(audioType type, QFontMetrics fm, QObject* parent) :
QObject(parent),
system(type),
fm(fm)
{
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
connect(&mediaDevices, &QMediaDevices::audioInputsChanged, this, &audioDevices::enumerate);
connect(&mediaDevices, &QMediaDevices::audioOutputsChanged, this, &audioDevices::enumerate);
#endif
}
void audioDevices::enumerate()
{
numInputDevices = 0;
numOutputDevices = 0;
numCharsIn = 0;
numCharsOut = 0;
inputs.clear();
outputs.clear();
switch (system)
{
case qtAudio:
{
Pa_Terminate();
qInfo(logAudio()) << "Audio device(s) found (*=default)";
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
foreach(const QAudioDeviceInfo & deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
#else
const auto audioInputs = mediaDevices.audioInputs();
for (const QAudioDevice& deviceInfo : audioInputs)
#endif
{
bool isDefault = false;
if (numInputDevices == 0) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
defaultInputDeviceName = QString(deviceInfo.deviceName());
#else
defaultInputDeviceName = QString(deviceInfo.description());
#endif
}
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
if (deviceInfo.realm() == audioApi || audioApi == "") {
#endif
/* Append Input Device Here */
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
if (deviceInfo.deviceName() == defaultInputDeviceName) {
#else
if (deviceInfo.description() == defaultInputDeviceName) {
#endif
isDefault = true;
}
#if ((QT_VERSION >= QT_VERSION_CHECK(5,15,0)) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
inputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, deviceInfo.realm(), isDefault));
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultInputDeviceName ? "*" : " ") <<
"(" << numInputDevices <<" " << deviceInfo.realm() << ") Input Device : " <<
deviceInfo.deviceName();
#elif (QT_VERSION < QT_VERSION_CHECK(5,15,0))
inputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, "", isDefault));
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultInputDeviceName ? "*" : " ") <<
"(" << numInputDevices << ") Input Device : " << deviceInfo.deviceName();
#else
inputs.append(new audioDevice(deviceInfo.description(), deviceInfo, "", isDefault));
qInfo(logAudio()) << (deviceInfo.description() == defaultInputDeviceName ? "*" : " ") <<
"(" << numInputDevices << ") Input Device : " << deviceInfo.description();
#endif
#ifndef BUILD_WFSERVER
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
if (fm.boundingRect(deviceInfo.deviceName()).width() > numCharsIn)
numCharsIn = fm.boundingRect(deviceInfo.deviceName()).width();
#else
if (fm.boundingRect(deviceInfo.description()).width() > numCharsIn)
numCharsIn = fm.boundingRect(deviceInfo.description()).width();
#endif
#endif
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
}
#endif
numInputDevices++;
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
foreach(const QAudioDeviceInfo & deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
#else
const auto audioOutputs = mediaDevices.audioOutputs();
for (const QAudioDevice& deviceInfo : audioOutputs)
#endif
{
bool isDefault = false;
if (numOutputDevices == 0)
{
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
defaultOutputDeviceName = QString(deviceInfo.deviceName());
#else
defaultOutputDeviceName = QString(deviceInfo.description());
#endif
}
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
if (deviceInfo.realm() == "wasapi") {
#endif
/* Append Output Device Here */
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
if (deviceInfo.deviceName() == defaultOutputDeviceName) {
#else
if (deviceInfo.description() == defaultOutputDeviceName) {
#endif
isDefault = true;
}
#if ((QT_VERSION >= QT_VERSION_CHECK(5,15,0)) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
outputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, deviceInfo.realm() , isDefault));
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultOutputDeviceName ? "*" : " ") <<
"(" << numOutputDevices << " " << deviceInfo.realm() << ") Output Device : " <<
deviceInfo.deviceName();
#elif (QT_VERSION < QT_VERSION_CHECK(5,15,0))
outputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, "", isDefault));
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultOutputDeviceName ? "*" : " ") <<
"(" << numOutputDevices << ") Output Device : " << deviceInfo.deviceName();
#else
outputs.append(new audioDevice(deviceInfo.description(), deviceInfo, "", isDefault));
qInfo(logAudio()) << (deviceInfo.description() == defaultOutputDeviceName ? "*" : " ") <<
"(" << numOutputDevices << ") Output Device : " << deviceInfo.description();
#endif
#ifndef BUILD_WFSERVER
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
if (fm.boundingRect(deviceInfo.deviceName()).width() > numCharsOut)
numCharsOut = fm.boundingRect(deviceInfo.deviceName()).width();
#else
if (fm.boundingRect(deviceInfo.description()).width() > numCharsOut)
numCharsOut = fm.boundingRect(deviceInfo.description()).width();
#endif
#endif
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
}
#endif
numOutputDevices++;
}
break;
}
case portAudio:
{
PaError err;
err = Pa_Initialize();
if (err != paNoError)
{
qInfo(logAudio()) << "ERROR: Cannot initialize Portaudio";
return;
}
qInfo(logAudio()) << "PortAudio version: " << Pa_GetVersionInfo()->versionText;
int numDevices = Pa_GetDeviceCount();
qInfo(logAudio()) << "Pa_CountDevices returned" << numDevices << "audio device(s) (*=default)";
const PaDeviceInfo* info;
for (int i = 0; i < numDevices; i++)
{
info = Pa_GetDeviceInfo(i);
if (info->maxInputChannels > 0) {
bool isDefault = false;
numInputDevices++;
qInfo(logAudio()) << (i == Pa_GetDefaultInputDevice() ? "*" : " ") << "(" << i << ") Input Device : " << QString(info->name);
if (i == Pa_GetDefaultInputDevice()) {
defaultInputDeviceName = info->name;
isDefault = true;
}
inputs.append(new audioDevice(QString(info->name), i,isDefault));
#ifndef BUILD_WFSERVER
if (fm.boundingRect(QString(info->name)).width() > numCharsIn)
numCharsIn = fm.boundingRect(QString(info->name)).width();
#endif
}
if (info->maxOutputChannels > 0) {
bool isDefault = false;
numOutputDevices++;
qInfo(logAudio()) << (i == Pa_GetDefaultOutputDevice() ? "*" : " ") << "(" << i << ") Output Device : " << QString(info->name);
if (i == Pa_GetDefaultOutputDevice()) {
defaultOutputDeviceName = info->name;
isDefault = true;
}
outputs.append(new audioDevice(QString(info->name), i,isDefault));
#ifndef BUILD_WFSERVER
if (fm.boundingRect(QString(info->name)).width() > numCharsOut)
numCharsOut = fm.boundingRect(QString(info->name)).width();
#endif
}
}
break;
}
case rtAudio:
{
Pa_Terminate();
#if defined(Q_OS_LINUX)
RtAudio* audio = new RtAudio(RtAudio::Api::LINUX_ALSA);
#elif defined(Q_OS_WIN)
RtAudio* audio = new RtAudio(RtAudio::Api::WINDOWS_WASAPI);
#elif defined(Q_OS_MACX)
RtAudio* audio = new RtAudio(RtAudio::Api::MACOSX_CORE);
#endif
// Enumerate audio devices, need to do before settings are loaded.
std::map<int, std::string> apiMap;
apiMap[RtAudio::MACOSX_CORE] = "OS-X Core Audio";
apiMap[RtAudio::WINDOWS_ASIO] = "Windows ASIO";
apiMap[RtAudio::WINDOWS_DS] = "Windows DirectSound";
apiMap[RtAudio::WINDOWS_WASAPI] = "Windows WASAPI";
apiMap[RtAudio::UNIX_JACK] = "Jack Client";
apiMap[RtAudio::LINUX_ALSA] = "Linux ALSA";
apiMap[RtAudio::LINUX_PULSE] = "Linux PulseAudio";
apiMap[RtAudio::LINUX_OSS] = "Linux OSS";
apiMap[RtAudio::RTAUDIO_DUMMY] = "RtAudio Dummy";
std::vector< RtAudio::Api > apis;
RtAudio::getCompiledApi(apis);
qInfo(logAudio()) << "RtAudio Version " << QString::fromStdString(RtAudio::getVersion());
qInfo(logAudio()) << "Compiled APIs:";
for (unsigned int i = 0; i < apis.size(); i++) {
qInfo(logAudio()) << " " << QString::fromStdString(apiMap[apis[i]]);
}
RtAudio::DeviceInfo info;
qInfo(logAudio()) << "Current API: " << QString::fromStdString(apiMap[audio->getCurrentApi()]);
unsigned int devicecount = audio->getDeviceCount();
#if (RTAUDIO_VERSION_MAJOR > 5)
std::vector<unsigned int> devices = audio->getDeviceIds();
#endif
qInfo(logAudio()) << "Found:" << devicecount << " audio device(s) (*=default)";
for (unsigned int i = 1; i < devicecount; i++) {
#if (RTAUDIO_VERSION_MAJOR > 5)
info = audio->getDeviceInfo(devices[i]);
#else
info = audio->getDeviceInfo(i);
#endif
if (info.inputChannels > 0) {
bool isDefault = false;
qInfo(logAudio()) << (info.isDefaultInput ? "*" : " ") << "(" << i << ") Input Device : " << QString::fromStdString(info.name);
numInputDevices++;
if (info.isDefaultInput) {
defaultInputDeviceName = QString::fromStdString(info.name);
isDefault = true;
}
#if (RTAUDIO_VERSION_MAJOR > 5)
inputs.append(new audioDevice(QString::fromStdString(info.name), devices[i], isDefault));
#else
inputs.append(new audioDevice(QString::fromStdString(info.name), i, isDefault));
#endif
#ifndef BUILD_WFSERVER
if (fm.boundingRect(QString::fromStdString(info.name)).width() > numCharsIn)
numCharsIn = fm.boundingRect(QString::fromStdString(info.name)).width();
#endif
}
if (info.outputChannels > 0) {
bool isDefault = false;
qInfo(logAudio()) << (info.isDefaultOutput ? "*" : " ") << "(" << i << ") Output Device : " << QString::fromStdString(info.name);
numOutputDevices++;
if (info.isDefaultOutput) {
defaultOutputDeviceName = QString::fromStdString(info.name);
isDefault = true;
}
#if (RTAUDIO_VERSION_MAJOR > 5)
outputs.append(new audioDevice(QString::fromStdString(info.name), devices[i], isDefault));
#else
outputs.append(new audioDevice(QString::fromStdString(info.name), i, isDefault));
#endif
#ifndef BUILD_WFSERVER
if (fm.boundingRect(QString::fromStdString(info.name)).width() > numCharsOut)
numCharsOut = fm.boundingRect(QString::fromStdString(info.name)).width();
#endif
}
}
delete audio;
break;
}
}
emit updated();
}
audioDevices::~audioDevices()
{
outputs.clear();
inputs.clear();
}
QStringList audioDevices::getInputs()
{
QStringList list;
for (int f = 0; f < inputs.size(); f++) {
list.append(inputs[f]->name);
}
return list;
}
QStringList audioDevices::getOutputs()
{
QStringList list;
for (int f = 0; f < outputs.size(); f++) {
list.append(outputs[f]->name);
}
return list;
}
int audioDevices::findInput(QString type, QString name)
{
int ret = -1;
int def = -1;
int usb = -1;
QString msg;
QTextStream s(&msg);
for (int f = 0; f < inputs.size(); f++)
{
//qInfo(logAudio()) << "Found device" << inputs[f].name;
if (inputs[f]->name.startsWith(name)) {
s << type << " Audio input device " << name << " found! ";
ret = f;
}
if (inputs[f]->isDefault == true)
{
def = f;
}
if (inputs[f]->name.toUpper().contains("USB")) {
// This is a USB device...
usb = f;
}
}
if (ret == -1)
{
s << type << " Audio input device " << name << " Not found: ";
if (inputs.size() == 1) {
s << "Selecting first device " << inputs[0]->name;
ret = 0;
}
else if (usb > -1 && type != "Client")
{
s << " Selecting found USB device " << inputs[usb]->name;
ret = usb;
}
else if (def > -1)
{
s << " Selecting default device " << inputs[def]->name;
ret = def;
}
else {
s << " and no default device found, aborting!";
}
}
qInfo(logAudio()) << msg;
return ret;
}
int audioDevices::findOutput(QString type, QString name)
{
int ret = -1;
int def = -1;
int usb = -1;
QString msg;
QTextStream s(&msg);
for (int f = 0; f < outputs.size(); f++)
{
//qInfo(logAudio()) << "Found device" << outputs[f].name;
if (outputs[f]->name.startsWith(name)) {
ret = f;
s << type << " Audio output device " << name << " found! ";
}
if (outputs[f]->isDefault == true)
{
def = f;
}
if (outputs[f]->name.toUpper().contains("USB")) {
// This is a USB device...
usb = f;
}
}
if (ret == -1)
{
s << type << " Audio output device " << name << " Not found: ";
if (outputs.size() == 1) {
s << " Selecting first device " << outputs[0]->name;
ret = 0;
}
else if (usb > -1 && type != "Client")
{
s << " Selecting found USB device " << outputs[usb]->name;
ret = usb;
}
else if (def > -1)
{
s << " Selecting default device " << outputs[def]->name;
ret = def;
}
else {
s << " and no default device found, aborting!";
}
}
qInfo(logAudio()) << msg;
return ret;
}

106
audiodevices.h 100644
Wyświetl plik

@ -0,0 +1,106 @@
#ifndef AUDIODEVICES_H
#define AUDIODEVICES_H
#include <QObject>
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
#include <QAudioDeviceInfo>
#else
#include <QMediaDevices>
#include <QAudioDevice>
#include <QString>
#endif
#include <QFontMetrics>
#include <portaudio.h>
#ifndef Q_OS_LINUX
#include "RtAudio.h"
#else
#include "rtaudio/RtAudio.h"
#endif
#include "wfviewtypes.h"
struct audioDevice {
audioDevice(QString name, int deviceInt, bool isDefault) : name(name), deviceInt(deviceInt), isDefault(isDefault) {};
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
audioDevice(QString name, const QAudioDeviceInfo deviceInfo, QString realm, bool isDefault) : name(name), deviceInfo(deviceInfo), realm(realm), isDefault(isDefault) {};
#else
audioDevice(QString name, QAudioDevice deviceInfo, QString realm, bool isDefault) : name(name), deviceInfo(deviceInfo), realm(realm), isDefault(isDefault) {};
#endif
QString name;
int deviceInt;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
const QAudioDeviceInfo deviceInfo;
#else
QAudioDevice deviceInfo;
#endif
QString realm;
bool isDefault;
};
class audioDevices : public QObject
{
Q_OBJECT
public:
explicit audioDevices(audioType type, QFontMetrics fm, QObject* parent = nullptr);
~audioDevices();
void setAudioType(audioType type) { system = type; };
audioType getAudioType() { return system; };
int getNumCharsIn() { return numCharsIn; };
int getNumCharsOut() { return numCharsOut; };
QString getInputName(int num) { return inputs[num]->name; };
QString getOutputName(int num) { return outputs[num]->name; };
int getInputDeviceInt(int num) { return inputs[num]->deviceInt; };
int getOutputDeviceInt(int num) { return outputs[num]->deviceInt; };
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
const QAudioDeviceInfo getInputDeviceInfo(int num) { return inputs[num]->deviceInfo; };
const QAudioDeviceInfo getOutputDeviceInfo(int num) { return outputs[num]->deviceInfo; };
#else
const QAudioDevice getInputDeviceInfo(int num) { return inputs[num]->deviceInfo; };
const QAudioDevice getOutputDeviceInfo(int num) { return outputs[num]->deviceInfo; };
#endif
void enumerate();
QStringList getInputs();
QStringList getOutputs();
int findInput(QString type, QString name);
int findOutput(QString type, QString name);
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
QMediaDevices mediaDevices;
#endif
public slots:
signals:
void updated();
protected:
private:
audioType system;
QFontMetrics fm;
QString defaultInputDeviceName;
QString defaultOutputDeviceName;
int numInputDevices;
int numOutputDevices;
QList<audioDevice*> inputs;
QList<audioDevice*> outputs;
int numCharsIn = 0;
int numCharsOut = 0;
QString audioApi = "wasapi";
};
#endif

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,186 +1,146 @@
#ifndef AUDIOHANDLER_H
#define AUDIOHANDLER_H
/* QT Headers */
#include <QObject>
#include <QByteArray>
#include <QMutex>
#include <QtEndian>
#include <QtMath>
#if defined(RTAUDIO)
#include "rtaudio/RtAudio.h"
#elif defined (PORTAUDIO)
#include "portaudio.h"
#error "PORTAUDIO is not currently supported"
#else
#include <QAudioOutput>
#include <QAudioFormat>
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <QIODevice>
#endif
typedef signed short MY_TYPE;
#define FORMAT RTAUDIO_SINT16
#define SCALE 32767.0
#define LOG100 4.60517018599
#include <QThread>
#include <QTimer>
#include <QTime>
#include <QMap>
#include "resampler/speex_resampler.h"
#include "ring/ring.h"
#include <QDebug>
#include <QTimer>
/* QT Audio Headers */
#include <QAudioOutput>
#include <QAudioFormat>
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <QAudioOutput>
#else
#include <QMediaDevices>
#include <QAudioDevice>
#include <QAudioSource>
#include <QAudioSink>
#endif
#include <QIODevice>
/* wfview Packet types */
#include "packettypes.h"
/* Logarithmic taper for volume control */
#include "audiotaper.h"
#include <QDebug>
//#define BUFFER_SIZE (32*1024)
/* Audio converter class*/
#include "audioconverter.h"
#define INTERNAL_SAMPLE_RATE 48000
#define MULAW_BIAS 33
#define MULAW_MAX 0x1fff
struct audioPacket {
quint32 seq;
QTime time;
quint16 sent;
QByteArray data;
};
struct audioSetup {
QString name;
quint8 bits;
quint8 radioChan;
quint16 samplerate;
quint16 latency;
quint8 codec;
bool ulaw;
bool isinput;
#if defined(RTAUDIO)
int port;
#elif defined(PORTAUDIO)
#else
QAudioDeviceInfo port;
#endif
quint8 resampleQuality;
unsigned char localAFgain;
};
// For QtMultimedia, use a native QIODevice
#if !defined(PORTAUDIO) && !defined(RTAUDIO)
class audioHandler : public QIODevice
#else
//class audioHandler : public QIODevice
class audioHandler : public QObject
#endif
{
Q_OBJECT
public:
audioHandler(QObject* parent = 0);
~audioHandler();
audioHandler(QObject* parent = nullptr);
virtual ~audioHandler();
int getLatency();
virtual int getLatency();
#if !defined (RTAUDIO) && !defined(PORTAUDIO)
bool setDevice(QAudioDeviceInfo deviceInfo);
virtual void start();
virtual void stop();
void start();
void flush();
void stop();
qint64 bytesAvailable() const;
bool isSequential() const;
#endif
void getNextAudioChunk(QByteArray &data);
virtual quint16 getAmplitude();
public slots:
bool init(audioSetup setup);
void changeLatency(const quint16 newSize);
void setVolume(unsigned char volume);
void incomingAudio(const audioPacket data);
virtual bool init(audioSetup setup);
virtual void changeLatency(const quint16 newSize);
virtual void setVolume(unsigned char volume);
virtual void incomingAudio(const audioPacket data);
virtual void convertedInput(audioPacket audio);
virtual void convertedOutput(audioPacket audio);
virtual void getNextAudioChunk();
private slots:
#if !defined (RTAUDIO) && !defined(PORTAUDIO)
void notified();
void stateChanged(QAudio::State state);
#endif
virtual void stateChanged(QAudio::State state);
virtual void clearUnderrun();
signals:
void audioMessage(QString message);
void sendLatency(quint16 newSize);
void haveAudioData(const QByteArray& data);
void haveAudioData(const audioPacket& data);
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS,quint16 latency,quint16 current,bool under,bool over);
void setupConverter(QAudioFormat in, codecType codecIn, QAudioFormat out, codecType codecOut, quint8 opus, quint8 resamp);
void sendToConverter(audioPacket audio);
private:
#if defined(RTAUDIO)
int readData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status);
//qint64 readData(char* data, qint64 nBytes);
//qint64 writeData(const char* data, qint64 nBytes);
static int staticRead(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
return static_cast<audioHandler*>(userData)->readData(outputBuffer, inputBuffer, nFrames, streamTime, status);
}
int writeData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status);
static int staticWrite(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
return static_cast<audioHandler*>(userData)->writeData(outputBuffer, inputBuffer, nFrames, streamTime, status);
}
#elif defined(PORTAUDIO)
#else
qint64 readData(char* data, qint64 nBytes);
qint64 writeData(const char* data, qint64 nBytes);
#endif
void reinit();
bool isUnderrun = false;
bool isOverrun = false;
bool isInitialized=false;
bool isReady = false;
bool audioBuffered = false;
#if defined(RTAUDIO)
RtAudio* audio = Q_NULLPTR;
int audioDevice = 0;
RtAudio::StreamParameters aParams;
RtAudio::StreamOptions options;
RtAudio::DeviceInfo info;
#elif defined(PORTAUDIO)
#else
QAudioOutput* audioOutput=Q_NULLPTR;
QAudioInput* audioInput=Q_NULLPTR;
QAudioFormat format;
QIODevice* audioDevice=Q_NULLPTR;
QAudioFormat radioFormat;
QAudioFormat nativeFormat;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
QAudioOutput* audioOutput = Q_NULLPTR;
QAudioInput* audioInput = Q_NULLPTR;
QAudioDeviceInfo deviceInfo;
#else
QAudioSink* audioOutput = Q_NULLPTR;
QAudioSource* audioInput = Q_NULLPTR;
QAudioDevice deviceInfo;
#endif
SpeexResamplerState* resampler = Q_NULLPTR;
bool isUlaw;
audioConverter* converter=Q_NULLPTR;
QThread* converterThread = Q_NULLPTR;
QTime lastReceived;
//r8b::CFixedBuffer<double>* resampBufs;
//r8b::CPtrKeeper<r8b::CDSPResampler24*>* resamps;
quint16 audioLatency;
bool isInput; // Used to determine whether input or output audio
unsigned int chunkSize;
bool chunkAvailable;
quint32 lastSeq;
quint32 lastSentSeq=0;
qint64 elapsedMs = 0;
int delayedPackets=0;
quint16 radioSampleRate;
quint16 nativeSampleRate=0;
quint8 radioSampleBits;
quint8 radioChannels;
QMap<quint32, audioPacket>audioBuffer;
unsigned int ratioNum;
unsigned int ratioDen;
wilt::Ring<audioPacket> *ringBuf=Q_NULLPTR;
double resampleRatio;
volatile bool ready = false;
audioPacket tempBuf;
quint16 currentLatency;
qreal volume=1.0;
int devChannels;
float amplitude=0.0;
qreal volume = 1.0;
audioSetup setup;
OpusEncoder* encoder = Q_NULLPTR;
OpusDecoder* decoder = Q_NULLPTR;
QTimer* underTimer;
codecType codec;
};
#endif // AUDIOHANDLER_H

Wyświetl plik

@ -173,7 +173,7 @@
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Load the calibration data fromthe indicated slot in the preference file. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Load the calibration data from the indicated slot in the preference file. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Load</string>

314
cluster.cpp 100644
Wyświetl plik

@ -0,0 +1,314 @@
#include "cluster.h"
#include "logcategories.h"
dxClusterClient::dxClusterClient(QObject* parent):
QObject(parent)
{
qInfo(logCluster()) << "starting dxClusterClient()";
}
dxClusterClient::~dxClusterClient()
{
qInfo(logCluster()) << "closing dxClusterClient()";
enableUdp(false);
enableTcp(false);
#ifdef USESQL
database db;
db.close();
#else
QMap<QString, spotData*>::iterator spot = allSpots.begin();
while (spot != allSpots.end())
{
delete spot.value(); // Stop memory leak?
spot = allSpots.erase(spot);
}
#endif
}
void dxClusterClient::enableUdp(bool enable)
{
udpEnable = enable;
if (enable)
{
if (udpSocket == Q_NULLPTR)
{
udpSocket = new QUdpSocket(this);
bool result = udpSocket->bind(QHostAddress::AnyIPv4, udpPort);
qInfo(logCluster()) << "Starting udpSocket() on:" << udpPort << "Result:" << result;
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(udpDataReceived()), Qt::QueuedConnection);
}
}
else {
if (udpSocket != Q_NULLPTR)
{
qInfo(logCluster()) << "Stopping udpSocket() on:" << udpPort;
udpSocket->disconnect();
delete udpSocket;
udpSocket = Q_NULLPTR;
}
}
}
void dxClusterClient::enableTcp(bool enable)
{
tcpEnable = enable;
if (enable)
{
tcpRegex = QRegularExpression("^DX de ([a-z-|A-Z|0-9|#|/]+):\\s+([0-9|.]+)\\s+([a-z|A-Z|0-9|/]+)+\\s+(.*)\\s+(\\d{4}Z)");
if (tcpSocket == Q_NULLPTR)
{
tcpSocket = new QTcpSocket(this);
tcpSocket->connectToHost(tcpServerName, tcpPort);
qInfo(logCluster()) << "Starting tcpSocket() on:" << tcpPort;
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(tcpDataReceived()), Qt::QueuedConnection);
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(tcpDisconnected()));
tcpCleanupTimer = new QTimer(this);
tcpCleanupTimer->setInterval(1000 * 10); // Run once a minute
connect(tcpCleanupTimer, SIGNAL(timeout()), this, SLOT(tcpCleanup()));
tcpCleanupTimer->start();
authenticated = false;
}
}
else {
if (tcpSocket != Q_NULLPTR)
{
sendTcpData(QString("bye\n"));
qInfo(logCluster()) << "Disconnecting tcpSocket() on:" << tcpPort;
if (tcpCleanupTimer != Q_NULLPTR)
{
tcpCleanupTimer->stop();
delete tcpCleanupTimer;
tcpCleanupTimer = Q_NULLPTR;
}
tcpSocket->disconnect();
delete tcpSocket;
tcpSocket = Q_NULLPTR;
}
}
}
void dxClusterClient::udpDataReceived()
{
QHostAddress sender;
quint16 port;
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
if (udpSpotReader.setContent(datagram))
{
QDomElement spot = udpSpotReader.firstChildElement("spot");
if (spot.nodeName() == "spot")
{
// This is a spot?
QString action = spot.firstChildElement("action").text();
if (action == "add") {
spotData* data = new spotData();
data->dxcall = spot.firstChildElement("dxcall").text();
data->frequency = spot.firstChildElement("frequency").text().toDouble() / 1000.0;
data->spottercall = spot.firstChildElement("spottercall").text();
data->timestamp = QDateTime::fromString(spot.firstChildElement("timestamp").text(),"yyyy-MM-dd hh:mm:ss");
data->mode = spot.firstChildElement("mode").text();
data->comment = spot.firstChildElement("comment").text();
#ifdef USESQL
database db = database();
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,mode,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6','%7')\n")
.arg("UDP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->mode).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
db.query(query);
#else
bool found = false;
QMap<QString, spotData*>::iterator spot = allSpots.find(data->dxcall);
while (spot != allSpots.end() && spot.key() == data->dxcall && spot.value()->frequency == data->frequency) {
found = true;
++spot;
}
if (found == false) {
allSpots.insert(data->dxcall, data);
}
#endif
emit sendOutput(QString("<spot><action>add</action><dxcall>%1</dxcall><spottercall>%2</spottercall><frequency>%3</frequency><comment>%4</comment></spot>\n")
.arg(data->dxcall).arg(data->spottercall).arg(data->frequency).arg(data->comment));
}
else if (action == "delete")
{
QString dxcall = spot.firstChildElement("dxcall").text();
double frequency = spot.firstChildElement("frequency").text().toDouble() / 1000.0;
#ifdef USESQL
database db = database();
QString query=QString("DELETE from spots where dxcall='%1' AND frequency=%2").arg(dxcall).arg(frequency);
db.query(query);
qInfo(logCluster()) << query;
#else
QMap<QString, spotData*>::iterator spot = allSpots.find(dxcall);
while (spot != allSpots.end() && spot.key() == dxcall && spot.value()->frequency == frequency)
{
delete spot.value(); // Stop memory leak?
spot = allSpots.erase(spot);
}
#endif
emit sendOutput(QString("<spot><action>delete</action><dxcall>%1</dxcall<frequency>%3</frequency></spot>\n")
.arg(dxcall).arg(frequency));
}
updateSpots();
}
}
}
void dxClusterClient::tcpDataReceived()
{
QString data = QString(tcpSocket->readAll());
emit sendOutput(data);
if (!authenticated) {
if (data.contains("login:") || data.contains("call:") || data.contains("callsign:")) {
sendTcpData(QString("%1\n").arg(tcpUserName));
return;
}
if (data.contains("password:")) {
sendTcpData(QString("%1\n").arg(tcpPassword));
return;
}
if (data.contains("Hello")) {
authenticated = true;
enableSkimmerSpots(skimmerSpots);
}
}
else {
QRegularExpressionMatchIterator i = tcpRegex.globalMatch(data);
while (i.hasNext()) {
QRegularExpressionMatch match = i.next();
if (match.hasMatch()) {
spotData* data = new spotData();
data->spottercall = match.captured(1);
data->frequency = match.captured(2).toDouble() / 1000.0;
data->dxcall = match.captured(3);
data->comment = match.captured(4).trimmed();
data->timestamp = QDateTime::currentDateTimeUtc();
#ifdef USESQL
database db = database();
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6')\n")
.arg("TCP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
db.query(query);
#else
bool found = false;
QMap<QString, spotData*>::iterator spot = allSpots.find(data->dxcall);
while (spot != allSpots.end() && spot.key() == data->dxcall && spot.value()->frequency == data->frequency) {
found = true;
++spot;
}
if (found == false) {
allSpots.insert(data->dxcall, data);
}
#endif
}
}
updateSpots();
}
}
void dxClusterClient::sendTcpData(QString data)
{
qInfo(logCluster()) << "Sending:" << data;
if (tcpSocket != Q_NULLPTR && tcpSocket->isValid() && tcpSocket->isOpen())
{
tcpSocket->write(data.toLatin1());
}
else
{
qInfo(logCluster()) << "socket not open!";
}
}
void dxClusterClient::tcpCleanup()
{
#ifdef USESQL
database db = database();
db.query(QString("DELETE FROM spots where timestamp < datetime('now', '-%1 minutes')").arg(tcpTimeout));
#else
QMap<QString, spotData*>::iterator spot = allSpots.begin();;
while (spot != allSpots.end()) {
if (spot.value()->timestamp.addSecs(tcpTimeout * 60) < QDateTime::currentDateTimeUtc())
{
delete spot.value(); // Stop memory leak?
spot = allSpots.erase(spot);
}
else
{
++spot;
}
}
#endif
}
void dxClusterClient::tcpDisconnected() {
qWarning(logCluster()) << "TCP Cluster server disconnected...";
// Need to start a timer and attempt reconnect.
}
void dxClusterClient::freqRange(double low, double high)
{
lowFreq = low;
highFreq = high;
//qInfo(logCluster) << "New range" << low << "-" << high;
updateSpots();
}
void dxClusterClient::updateSpots()
{
QList<spotData> spots;
#ifdef USESQL
// Set the required frequency range.
QString queryText = QString("SELECT * FROM spots WHERE frequency > %1 AND frequency < %2").arg(lowFreq).arg(highFreq);
//QString queryText = QString("SELECT * FROM spots");
database db;
auto query = db.query(queryText);
while (query.next()) {
// Step through all current spots within range
spotData s = spotData();
s.dxcall = query.value(query.record().indexOf("dxcall")).toString();
s.frequency = query.value(query.record().indexOf("frequency")).toDouble();
spots.append(s);
}
#else
QMap<QString, spotData*>::iterator spot = allSpots.begin();;
while (spot != allSpots.end()) {
if (spot.value()->frequency > lowFreq && spot.value()->frequency < highFreq)
{
spots.append(**spot);
}
++spot;
}
#endif
emit sendSpots(spots);
}
void dxClusterClient::enableSkimmerSpots(bool enable)
{
skimmerSpots = enable;
if (authenticated) {
if (skimmerSpots) {
sendTcpData(QString("Set Dx Filter Skimmer\n"));
}
else
{
sendTcpData(QString("Set Dx Filter Not Skimmer\n"));
}
}
}

106
cluster.h 100644
Wyświetl plik

@ -0,0 +1,106 @@
#ifndef CLUSTER_H
#define CLUSTER_H
#include <QObject>
#include <QDebug>
#include <QUdpSocket>
#include <QTcpSocket>
#include <QDomDocument>
#include <QMutex>
#include <QMutexLocker>
#include <QDateTime>
#include <QRegularExpression>
#include <QTimer>
#ifdef USESQL
#include <QSqlDatabase>
#include <QSqlQuery>
#endif
#include <qcustomplot.h>
#ifdef USESQL
#include "database.h"
#endif
struct spotData {
QString dxcall;
double frequency;
QString spottercall;
QDateTime timestamp;
QString mode;
QString comment;
QCPItemText* text = Q_NULLPTR;
bool current = false;
};
struct clusterSettings {
QString server;
int port=7300;
QString userName;
QString password;
int timeout=30;
bool isdefault;
};
class dxClusterClient : public QObject
{
Q_OBJECT
public:
explicit dxClusterClient(QObject* parent = nullptr);
virtual ~dxClusterClient();
signals:
void addSpot(spotData* spot);
void deleteSpot(QString dxcall);
void deleteOldSpots(int minutes);
void sendOutput(QString text);
void sendSpots(QList<spotData> spots);
public slots:
void udpDataReceived();
void tcpDataReceived();
void tcpDisconnected();
void enableUdp(bool enable);
void enableTcp(bool enable);
void setUdpPort(int p) { udpPort = p; }
void setTcpServerName(QString s) { tcpServerName = s; }
void setTcpPort(int p) { tcpPort = p; }
void setTcpUserName(QString s) { tcpUserName = s; }
void setTcpPassword(QString s) { tcpPassword = s; }
void setTcpTimeout(int p) { tcpTimeout = p; }
void tcpCleanup();
void freqRange(double low, double high);
void enableSkimmerSpots(bool enable);
private:
void sendTcpData(QString data);
bool databaseOpen();
void updateSpots();
bool udpEnable;
bool tcpEnable;
QUdpSocket* udpSocket=Q_NULLPTR;
QTcpSocket* tcpSocket=Q_NULLPTR;
int udpPort;
QString tcpServerName;
int tcpPort;
QString tcpUserName;
QString tcpPassword;
int tcpTimeout;
QDomDocument udpSpotReader;
QRegularExpression tcpRegex;
QMutex mutex;
bool authenticated=false;
QTimer* tcpCleanupTimer=Q_NULLPTR;
#ifdef USESQL
QSqlDatabase db;
#endif
double lowFreq;
double highFreq;
QMap<QString,spotData*> allSpots;
bool skimmerSpots = false;
};
#endif

44
colorprefs.h 100644
Wyświetl plik

@ -0,0 +1,44 @@
#ifndef COLORPREFS_H
#define COLORPREFS_H
#include <QColor>
#include <QString>
struct colorPrefsType{
int presetNum = -1;
QString *presetName = Q_NULLPTR;
// Spectrum line plot:
QColor gridColor;
QColor axisColor;
QColor textColor;
QColor spectrumLine;
QColor spectrumFill;
QColor underlayLine;
QColor underlayFill;
QColor plotBackground;
QColor tuningLine;
QColor passband;
QColor pbt;
// Waterfall:
QColor wfBackground;
QColor wfGrid;
QColor wfAxis;
QColor wfText;
// Meters:
QColor meterLevel;
QColor meterAverage;
QColor meterPeakLevel;
QColor meterPeakScale;
QColor meterLowerLine;
QColor meterLowText;
// Assorted
QColor clusterSpots;
};
#endif // COLORPREFS_H

Wyświetl plik

@ -3,41 +3,34 @@
#include <QDebug>
// Copytight 2017-2020 Elliott H. Liggett
// Copyright 2017-2020 Elliott H. Liggett
commHandler::commHandler()
commHandler::commHandler(QObject* parent) : QObject(parent)
{
//constructor
// grab baud rate and other comm port details
// if they need to be changed later, please
// destroy this and create a new one.
port = new QSerialPort();
// TODO: The following should become arguments and/or functions
// Add signal/slot everywhere for comm port setup.
// Consider how to "re-setup" and how to save the state for next time.
baudrate = 115200;
stopbits = 1;
portName = "/dev/ttyUSB0";
this->PTTviaRTS = false;
setupComm(); // basic parameters
openPort();
//qInfo(logSerial()) << "Serial buffer size: " << port->readBufferSize();
//port->setReadBufferSize(1024); // manually. 256 never saw any return from the radio. why...
//qInfo(logSerial()) << "Serial buffer size: " << port->readBufferSize();
connect(port, SIGNAL(readyRead()), this, SLOT(receiveDataIn()));
init();
}
commHandler::commHandler(QString portName, quint32 baudRate)
commHandler::commHandler(QString portName, quint32 baudRate, quint8 wfFormat, QObject* parent) : QObject(parent)
{
//constructor
// grab baud rate and other comm port details
// if they need to be changed later, please
// destroy this and create a new one.
port = new QSerialPort();
if (wfFormat == 1) { // Single waterfall packet
combineWf = true;
qDebug(logSerial()) << "*********** Combine Waterfall Mode Enabled!";
}
// TODO: The following should become arguments and/or functions
// Add signal/slot everywhere for comm port setup.
@ -45,7 +38,20 @@ commHandler::commHandler(QString portName, quint32 baudRate)
baudrate = baudRate;
stopbits = 1;
this->portName = portName;
this->PTTviaRTS = false;
init();
}
void commHandler::init()
{
if (port != Q_NULLPTR) {
delete port;
port = Q_NULLPTR;
isConnected = false;
}
port = new QSerialPort();
setupComm(); // basic parameters
openPort();
// qInfo(logSerial()) << "Serial buffer size: " << port->readBufferSize();
@ -53,12 +59,21 @@ commHandler::commHandler(QString portName, quint32 baudRate)
//qInfo(logSerial()) << "Serial buffer size: " << port->readBufferSize();
connect(port, SIGNAL(readyRead()), this, SLOT(receiveDataIn()));
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
connect(port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
#else
connect(port, SIGNAL(errorOccurred(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
#endif
lastDataReceived = QTime::currentTime();
}
commHandler::~commHandler()
{
this->closePort();
qInfo(logSerial()) << "Closing serial port: " << port->portName();
if (isConnected) {
this->closePort();
}
delete port;
}
void commHandler::setupComm()
@ -76,12 +91,65 @@ void commHandler::receiveDataFromUserToRig(const QByteArray &data)
void commHandler::sendDataOut(const QByteArray &writeData)
{
// Recycle port to attempt reconnection.
if (lastDataReceived.msecsTo(QTime::currentTime()) > 2000) {
qDebug(logSerial()) << "Serial port error? Attempting reconnect...";
lastDataReceived = QTime::currentTime();
QTimer::singleShot(500, this, SLOT(init()));
return;
}
mutex.lock();
qint64 bytesWritten;
bytesWritten = port->write(writeData);
previousSent = writeData;
if(PTTviaRTS)
{
// Size: 1 2 3 4 5 6 7 8
//index: 0 1 2 3 4 5 6 7
//Query: FE FE TO FROM 0x1C 0x00 0xFD
//PTT On: FE FE TO FROM 0x1C 0x00 0x01 0xFD
//PTT Off: FE FE TO FROM 0x1C 0x00 0x00 0xFD
if(writeData.endsWith(QByteArrayLiteral("\x1C\x00\xFD")))
{
// Query
//qDebug(logSerial()) << "Looks like PTT Query";
bool pttOn = this->rtsStatus();
QByteArray pttreturncmd = QByteArray("\xFE\xFE");
pttreturncmd.append(writeData.at(3));
pttreturncmd.append(writeData.at(2));
pttreturncmd.append(QByteArray("\x1C\x00", 2));
pttreturncmd.append((char)pttOn);
pttreturncmd.append("\xFD");
//qDebug(logSerial()) << "Sending fake PTT query result: " << (bool)pttOn;
printHex(pttreturncmd, false, true);
emit haveDataFromPort(pttreturncmd);
mutex.unlock();
return;
} else if(writeData.endsWith(QByteArrayLiteral("\x1C\x00\x01\xFD")))
{
// PTT ON
//qDebug(logSerial()) << "Looks like PTT ON";
setRTS(true);
mutex.unlock();
return;
} else if(writeData.endsWith(QByteArrayLiteral("\x1C\x00\x00\xFD")))
{
// PTT OFF
//qDebug(logSerial()) << "Looks like PTT OFF";
setRTS(false);
mutex.unlock();
return;
}
}
bytesWritten = port->write(writeData);
if(bytesWritten != (qint64)writeData.size())
{
qDebug(logSerial()) << "bytesWritten: " << bytesWritten << " length of byte array: " << writeData.length()\
@ -100,9 +168,19 @@ void commHandler::receiveDataIn()
// because we know what constitutes a valid "frame" of data.
// new code:
lastDataReceived = QTime::currentTime();
port->startTransaction();
inPortData = port->readAll();
if (inPortData.startsWith("\xFC\xFC\xFC\xFC\xFC"))
{
// Colission detected by remote end, re-send previous command.
qInfo(logSerial()) << "Collision detected by remote, resending previous command";
port->commitTransaction();
sendDataOut(previousSent);
return;
}
if(inPortData.size() == 1)
{
// Generally for baud <= 9600
@ -118,8 +196,7 @@ void commHandler::receiveDataIn()
}
}
if(inPortData.startsWith("\xFE\xFE"))
if (inPortData.startsWith("\xFE\xFE"))
{
if(inPortData.contains("\xFC"))
{
@ -132,17 +209,73 @@ void commHandler::receiveDataIn()
{
// good!
port->commitTransaction();
//payloadIn = data.right(data.length() - 4);
// Do we need to combine waterfall into single packet?
int combined = 0;
if (combineWf) {
int pos = inPortData.indexOf(QByteArrayLiteral("\x27\x00\x00"));
int fdPos = inPortData.mid(pos).indexOf(QByteArrayLiteral("\xfd"));
//printHex(inPortData, false, true);
while (pos > -1 && fdPos > -1) {
combined++;
spectrumDivisionNumber = inPortData[pos + 3] & 0x0f;
spectrumDivisionNumber += ((inPortData[pos + 3] & 0xf0) >> 4) * 10;
if (spectrumDivisionNumber == 1) {
// This is the first waveform data.
spectrumDivisionMax = 0;
spectrumDivisionMax = inPortData[pos + 4] & 0x0f;
spectrumDivisionMax += ((inPortData[pos + 4] & 0xf0) >> 4) * 10;
spectrumData.clear();
spectrumData = inPortData.mid(pos - 4, fdPos+4); // Don't include terminating FD
spectrumData[8] = spectrumData[7]; // Make max = current;
//qDebug() << "New Spectrum seq:" << spectrumDivisionNumber << "pos = " << pos << "len" << fdPos;
}
else if (spectrumDivisionNumber > lastSpectrum && spectrumDivisionNumber <= spectrumDivisionMax) {
spectrumData.insert(spectrumData.length(), inPortData.mid(pos + 5, fdPos-5));
//qInfo() << "Added spectrum seq:" << spectrumDivisionNumber << "len" << fdPos-5<< "Spec" << spectrumData.length();
//printHex(inPortData.mid((pos+4),fdPos - (pos+5)), false, true);
}
else {
qDebug() << "Invalid Spectrum Division received" << spectrumDivisionNumber << "last Spectrum" << lastSpectrum;
}
lastSpectrum = spectrumDivisionNumber;
if (spectrumDivisionNumber == spectrumDivisionMax) {
//qDebug() << "Got Spectrum! length=" << spectrumData.length();
spectrumData.append("\xfd"); // Need to add FD on the end.
//printHex(spectrumData, false, true);
emit haveDataFromPort(spectrumData);
lastSpectrum = 0;
}
inPortData = inPortData.remove(pos-4, fdPos+5);
pos = inPortData.indexOf(QByteArrayLiteral("\x27\x00\x00"));
fdPos = inPortData.mid(pos).indexOf(QByteArrayLiteral("\xfd"));
}
// If we still have data left, let the main function deal with it, any spectrum data has been removed
if (inPortData.length() == 0)
{
return;
}
// qDebug() << "Got extra data!";
//printHex(inPortData, false, true);
}
//
emit haveDataFromPort(inPortData);
if(rolledBack)
{
// qInfo(logSerial()) << "Rolled back and was successfull. Length: " << inPortData.length();
// qInfo(logSerial()) << "Rolled back and was successful. Length: " << inPortData.length();
//printHex(inPortData, false, true);
rolledBack = false;
}
} else {
// did not receive the entire thing so roll back:
// qInfo(logSerial()) << "Rolling back transaction. End not detected. Lenth: " << inPortData.length();
// qInfo(logSerial()) << "Rolling back transaction. End not detected. Length: " << inPortData.length();
//printHex(inPortData, false, true);
port->rollbackTransaction();
rolledBack = true;
@ -162,10 +295,28 @@ void commHandler::receiveDataIn()
}
}
void commHandler::setRTS(bool rtsOn)
{
bool success = port->setRequestToSend(rtsOn);
if(!success)
{
qInfo(logSerial()) << "Error, could not set RTS on port " << portName;
}
}
bool commHandler::rtsStatus()
{
return port->isRequestToSend();
}
void commHandler::setUseRTSforPTT(bool PTTviaRTS)
{
this->PTTviaRTS = PTTviaRTS;
}
void commHandler::openPort()
{
bool success;
// port->open();
success = port->open(QIODevice::ReadWrite);
if(success)
{
@ -178,7 +329,7 @@ void commHandler::openPort()
qInfo(logSerial()) << "Could not open serial port " << portName << " , please restart.";
isConnected = false;
serialError = true;
emit haveSerialPortError(portName, "Could not open port. Please restart.");
emit havePortError(errorType(true, portName, "Could not open port. Please restart."));
return;
}
}
@ -188,7 +339,7 @@ void commHandler::closePort()
if(port)
{
port->close();
delete port;
//delete port;
}
isConnected = false;
}
@ -234,3 +385,17 @@ void commHandler::printHex(const QByteArray &pdata, bool printVert, bool printHo
}
void commHandler::handleError(QSerialPort::SerialPortError err)
{
switch (err) {
case QSerialPort::NoError:
break;
default:
if (lastDataReceived.msecsTo(QTime::currentTime()) > 2000) {
qDebug(logSerial()) << "Serial port" << port->portName() << "Error, attempting disconnect/reconnect";
lastDataReceived = QTime::currentTime();
QTimer::singleShot(500, this, SLOT(init()));
}
break;
}
}

Wyświetl plik

@ -6,6 +6,10 @@
#include <QMutex>
#include <QDataStream>
#include <QtSerialPort/QSerialPort>
#include <QTime>
#include <QTimer>
#include "wfviewtypes.h"
// This class abstracts the comm port in a useful way and connects to
// the command creator and command parser.
@ -15,12 +19,19 @@ class commHandler : public QObject
Q_OBJECT
public:
commHandler();
commHandler(QString portName, quint32 baudRate);
commHandler(QObject* parent = nullptr);
commHandler(QString portName, quint32 baudRate, quint8 wfFormat,QObject* parent = nullptr);
bool serialError;
bool rtsStatus();
~commHandler();
public slots:
void setUseRTSforPTT(bool useRTS);
void setRTS(bool rtsOn);
void handleError(QSerialPort::SerialPortError error);
void init();
private slots:
void receiveDataIn(); // from physical port
void receiveDataFromUserToRig(const QByteArray &data);
@ -30,7 +41,7 @@ signals:
void haveTextMessage(QString message); // status, debug only
void sendDataOutToPort(const QByteArray &writeData); // not used
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
void haveSerialPortError(const QString port, const QString error);
void havePortError(errorType err);
void haveStatusUpdate(const QString text);
private:
@ -38,6 +49,7 @@ private:
void openPort();
void closePort();
void sendDataOut(const QByteArray &writeData); // out to radio
void debugMe();
void hexPrint();
@ -45,6 +57,7 @@ private:
//QDataStream stream;
QByteArray outPortData;
QByteArray inPortData;
QByteArray previousSent;
//QDataStream outStream;
//QDataStream inStream;
@ -52,7 +65,7 @@ private:
unsigned char buffer[256];
QString portName;
QSerialPort *port;
QSerialPort *port=Q_NULLPTR;
qint32 baudrate;
unsigned char stopbits;
bool rolledBack;
@ -63,10 +76,20 @@ private:
bool havePt;
QString ptDevSlave;
bool PTTviaRTS = false;
bool isConnected; // port opened
mutable QMutex mutex;
void printHex(const QByteArray &pdata, bool printVert, bool printHoriz);
bool combineWf = false;
QByteArray spectrumData;
quint8 spectrumDivisionNumber;
quint8 spectrumDivisionMax;
quint8 spectrumCenterOrFixed;
quint8 spectrumInformation;
quint8 spectrumOutOfRange;
quint8 lastSpectrum = 0;
QTime lastDataReceived;
};
#endif // COMMHANDLER_H

996
controllersetup.cpp 100644
Wyświetl plik

@ -0,0 +1,996 @@
#include "controllersetup.h"
#include "ui_controllersetup.h"
#include "logcategories.h"
controllerSetup::controllerSetup(QWidget* parent) :
QDialog(parent),
ui(new Ui::controllerSetup)
{
ui->setupUi(this);
ui->tabWidget->clear();
ui->tabWidget->hide();
noControllersText = new QLabel("No USB controller found");
noControllersText->setStyleSheet("QLabel { color : gray; }");
ui->hboxLayout->addWidget(noControllersText);
this->resize(this->sizeHint());
}
controllerSetup::~controllerSetup()
{
qInfo(logUsbControl()) << "Deleting controllerSetup() window";
delete noControllersText;
delete updateDialog;
delete ui; // Will delete all content in all tabs
tabs.clear();
// Step through ALL buttons and knobs setting their text to NULL (just in case)
for (auto b = buttons->begin(); b != buttons->end(); b++)
{
b->text=Q_NULLPTR;
b->bgRect=Q_NULLPTR;
}
for (auto k= knobs->begin(); k != knobs->end(); k++)
{
k->text=Q_NULLPTR;
}
}
void controllerSetup::hideEvent(QHideEvent *event)
{
Q_UNUSED(event)
qDebug(logUsbControl()) << "Controller window hideEvent()";
updateDialog->hide();
}
void controllerSetup::on_tabWidget_currentChanged(int index)
{
// We may get the indexChanged event before the tabWidget has been initialized
if (ui->tabWidget->widget(index) != Q_NULLPTR) {
QString path = ui->tabWidget->widget(index)->objectName();
auto tab = tabs.find(path);
if (tab != tabs.end())
{
this->resize(this->sizeHint());
}
}
if (updateDialog != Q_NULLPTR)
{
updateDialog->hide();
}
}
void controllerSetup::init(usbDevMap* dev, QVector<BUTTON>* but, QVector<KNOB>* kb, QVector<COMMAND>* cmd, QMutex* mut)
{
// Store pointers to all current settings
devices = dev;
buttons = but;
knobs = kb;
commands = cmd;
mutex = mut;
updateDialog = new QDialog(this);
// Not sure if I like it Frameless or not?
updateDialog->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
QGridLayout* udLayout = new QGridLayout(updateDialog);
onLabel = new QLabel("On");
udLayout->addWidget(onLabel,0,0);
onEvent = new QComboBox();
udLayout->addWidget(onEvent,0,1);
onLabel->setBuddy(onEvent);
offLabel = new QLabel("Off");
udLayout->addWidget(offLabel,1,0);
offEvent = new QComboBox();
udLayout->addWidget(offEvent,1,1);
offLabel->setBuddy(offEvent);
knobLabel = new QLabel("Knob");
udLayout->addWidget(knobLabel,2,0);
knobEvent = new QComboBox();
udLayout->addWidget(knobEvent,2,1);
knobLabel->setBuddy(knobEvent);
ledNumber = new QSpinBox();
ledNumber->setPrefix("LED: ");
ledNumber->setMinimum(0);
udLayout->addWidget(ledNumber,3,1);
buttonLatch = new QCheckBox();
buttonLatch->setText("Toggle");
udLayout->addWidget(buttonLatch,4,0);
QHBoxLayout* colorLayout = new QHBoxLayout();
udLayout->addLayout(colorLayout,4,1);
buttonOnColor = new QPushButton("Color");
colorLayout->addWidget(buttonOnColor);
buttonOffColor = new QPushButton("Pressed");
colorLayout->addWidget(buttonOffColor);
buttonIcon = new QPushButton("Icon");
udLayout->addWidget(buttonIcon,5,0);
iconLabel = new QLabel("<None>");
udLayout->addWidget(iconLabel,5,1);
udLayout->setAlignment(iconLabel,Qt::AlignCenter);
udLayout->setSizeConstraint(QLayout::SetFixedSize);
updateDialog->hide();
onEvent->clear();
offEvent->clear();
knobEvent->clear();
for (COMMAND& c : *commands) {
if (c.cmdType == commandButton || c.cmdType == commandAny) {
if (c.command == cmdSeparator) {
onEvent->insertSeparator(onEvent->count());
offEvent->insertSeparator(offEvent->count());
} else {
onEvent->addItem(c.text, c.index);
offEvent->addItem(c.text, c.index);
}
}
if (c.cmdType == commandKnob || c.cmdType == commandAny) {
if (c.command == cmdSeparator) {
knobEvent->insertSeparator(knobEvent->count());
} else {
knobEvent->addItem(c.text, c.index);
}
}
}
connect(offEvent, SIGNAL(currentIndexChanged(int)), this, SLOT(offEventIndexChanged(int)));
connect(onEvent, SIGNAL(currentIndexChanged(int)), this, SLOT(onEventIndexChanged(int)));
connect(knobEvent, SIGNAL(currentIndexChanged(int)), this, SLOT(knobEventIndexChanged(int)));
connect(buttonOnColor, SIGNAL(clicked()), this, SLOT(buttonOnColorClicked()));
connect(buttonOffColor, SIGNAL(clicked()), this, SLOT(buttonOffColorClicked()));
connect(buttonIcon, SIGNAL(clicked()), this, SLOT(buttonIconClicked()));
connect(buttonLatch, SIGNAL(stateChanged(int)), this, SLOT(latchStateChanged(int)));
connect(ledNumber, SIGNAL(valueChanged(int)), this, SLOT(ledNumberChanged(int)));
}
void controllerSetup::showMenu(controllerScene* scene, QPoint p)
{
Q_UNUSED (scene) // We might want it in the future?
// Receive mouse event from the scene
qDebug() << "Looking for knob or button at Point x=" << p.x() << " y=" << p.y();
QPoint gp = this->mapToGlobal(p);
// Did the user click on a button?
auto but = std::find_if(buttons->begin(), buttons->end(), [p, this](BUTTON& b)
{ return (b.parent != Q_NULLPTR && b.pos.contains(p) && b.page == b.parent->currentPage && ui->tabWidget->currentWidget()->objectName() == b.path ); });
if (but != buttons->end())
{
currentButton = &(*but);
currentKnob = Q_NULLPTR;
qDebug() << "Button" << currentButton->num << "On Event" << currentButton->onCommand->text << "Off Event" << currentButton->offCommand->text;
updateDialog->setWindowTitle(QString("Update button %0").arg(but->num));
onEvent->blockSignals(true);
onEvent->setCurrentIndex(onEvent->findData(currentButton->onCommand->index));
onEvent->show();
onLabel->show();
onEvent->blockSignals(false);
offEvent->blockSignals(true);
offEvent->setCurrentIndex(offEvent->findData(currentButton->offCommand->index));
offEvent->show();
offLabel->show();
offEvent->blockSignals(false);
knobEvent->hide();
knobLabel->hide();
buttonLatch->blockSignals(true);
buttonLatch->setChecked(currentButton->toggle);
buttonLatch->blockSignals(false);
buttonLatch->show();
ledNumber->blockSignals(true);
ledNumber->setMaximum(currentButton->parent->type.leds);
ledNumber->setValue(currentButton->led);
ledNumber->blockSignals(false);
switch (currentButton->parent->type.model)
{
case RC28:
case eCoderPlus:
ledNumber->show();
buttonOnColor->hide();
buttonOffColor->hide();
buttonIcon->hide();
iconLabel->hide();
break;
case StreamDeckMini:
case StreamDeckMiniV2:
case StreamDeckOriginal:
case StreamDeckOriginalV2:
case StreamDeckOriginalMK2:
case StreamDeckXL:
case StreamDeckXLV2:
case StreamDeckPlus:
buttonOnColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOn.name(QColor::HexArgb)));
buttonOffColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOff.name(QColor::HexArgb)));
buttonOnColor->show();
buttonOffColor->show();
buttonIcon->show();
iconLabel->setText(currentButton->iconName);
iconLabel->show();
break;
default:
buttonOnColor->hide();
buttonOffColor->hide();
buttonIcon->hide();
iconLabel->hide();
ledNumber->hide();
break;
}
updateDialog->show();
updateDialog->move(gp);
updateDialog->adjustSize();
updateDialog->raise();
} else {
// It wasn't a button so was it a knob?
auto kb = std::find_if(knobs->begin(), knobs->end(), [p, this](KNOB& k)
{ return (k.parent != Q_NULLPTR && k.pos.contains(p) && k.page == k.parent->currentPage && ui->tabWidget->currentWidget()->objectName() == k.path ); });
if (kb != knobs->end())
{
currentKnob = &(*kb);
currentButton = Q_NULLPTR;
qDebug() << "Knob" << currentKnob->num << "Event" << currentKnob->command->text;
updateDialog->setWindowTitle(QString("Update knob %0").arg(kb->num));
knobEvent->blockSignals(true);
knobEvent->setCurrentIndex(knobEvent->findData(currentKnob->command->index));
knobEvent->show();
knobLabel->show();
knobEvent->blockSignals(false);
onEvent->hide();
offEvent->hide();
onLabel->hide();
offLabel->hide();
buttonLatch->hide();
buttonOnColor->hide();
buttonOffColor->hide();
buttonIcon->hide();
iconLabel->hide();
ledNumber->hide();
updateDialog->show();
updateDialog->move(gp);
updateDialog->adjustSize();
updateDialog->raise();
}
else
{
// It wasn't either so hide the updateDialog();
updateDialog->hide();
currentButton = Q_NULLPTR;
currentKnob = Q_NULLPTR;
}
}
}
void controllerSetup::onEventIndexChanged(int index) {
Q_UNUSED(index);
// If command is changed, delete current command and deep copy the new command
if (currentButton != Q_NULLPTR && onEvent->currentData().toInt() < commands->size()) {
QMutexLocker locker(mutex);
currentButton->onCommand = &commands->at(onEvent->currentData().toInt());
currentButton->text->setPlainText(currentButton->onCommand->text);
currentButton->text->setPos(currentButton->pos.center().x() - currentButton->text->boundingRect().width() / 2,
(currentButton->pos.center().y() - currentButton->text->boundingRect().height() / 2));
// Signal that any button programming on the device should be completed.
if (currentButton->icon == Q_NULLPTR) {
emit sendRequest(currentButton->parent,usbFeatureType::featureButton,currentButton->num,currentButton->onCommand->text,Q_NULLPTR,&currentButton->backgroundOn);
}
}
}
void controllerSetup::offEventIndexChanged(int index) {
Q_UNUSED(index);
// If command is changed, delete current command and deep copy the new command
if (currentButton != Q_NULLPTR && offEvent->currentData().toInt() < commands->size()) {
QMutexLocker locker(mutex);
currentButton->offCommand = &commands->at(offEvent->currentData().toInt());
}
}
void controllerSetup::ledNumberChanged(int index) {
if (currentButton != Q_NULLPTR) {
QMutexLocker locker(mutex);
currentButton->led = index;
}
}
void controllerSetup::knobEventIndexChanged(int index) {
Q_UNUSED(index);
// If command is changed, delete current command and deep copy the new command
if (currentKnob != Q_NULLPTR && knobEvent->currentData().toInt() < commands->size()) {
QMutexLocker locker(mutex);
currentKnob->command = &commands->at(knobEvent->currentData().toInt());
currentKnob->text->setPlainText(currentKnob->command->text);
currentKnob->text->setPos(currentKnob->pos.center().x() - currentKnob->text->boundingRect().width() / 2,
(currentKnob->pos.center().y() - currentKnob->text->boundingRect().height() / 2));
}
}
void controllerSetup::buttonOnColorClicked()
{
QColorDialog::ColorDialogOptions options;
options.setFlag(QColorDialog::ShowAlphaChannel, false);
options.setFlag(QColorDialog::DontUseNativeDialog, false);
QColor selColor = QColorDialog::getColor(currentButton->backgroundOn, this, "Select Color to use for unpressed button", options);
if(selColor.isValid() && currentButton != Q_NULLPTR)
{
QMutexLocker locker(mutex);
currentButton->backgroundOn = selColor;
if (currentButton->graphics && currentButton->bgRect != Q_NULLPTR)
{
currentButton->bgRect->setBrush(currentButton->backgroundOn);
}
buttonOnColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOn.name(QColor::HexArgb)));
emit sendRequest(currentButton->parent,usbFeatureType::featureButton,currentButton->num,currentButton->onCommand->text,currentButton->icon,&currentButton->backgroundOn);
}
}
void controllerSetup::buttonOffColorClicked()
{
QColorDialog::ColorDialogOptions options;
options.setFlag(QColorDialog::ShowAlphaChannel, false);
options.setFlag(QColorDialog::DontUseNativeDialog, false);
QColor selColor = QColorDialog::getColor(currentButton->backgroundOff, this, "Select Color to use for pressed button", options);
if(selColor.isValid() && currentButton != Q_NULLPTR)
{
QMutexLocker locker(mutex);
currentButton->backgroundOff = selColor;
buttonOffColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOff.name(QColor::HexArgb)));
}
}
void controllerSetup::buttonIconClicked()
{
QString file = QFileDialog::getOpenFileName(this,"Select Icon Filename",".","Images (*png *.jpg)");
if (!file.isEmpty()) {
QFileInfo info = QFileInfo(file);
currentButton->iconName = info.fileName();
iconLabel->setText(currentButton->iconName);
QImage image;
image.load(file);
if (currentButton->icon != Q_NULLPTR)
delete currentButton->icon;
currentButton->icon = new QImage(image.scaled(currentButton->parent->type.iconSize,currentButton->parent->type.iconSize));
} else {
if (currentButton->icon != Q_NULLPTR)
{
currentButton->iconName = "";
delete currentButton->icon;
currentButton->icon = Q_NULLPTR;
}
}
iconLabel->setText(currentButton->iconName);
emit sendRequest(currentButton->parent,usbFeatureType::featureButton,currentButton->num,currentButton->onCommand->text,currentButton->icon, &currentButton->backgroundOn);
}
void controllerSetup::latchStateChanged(int state)
{
if (currentButton != Q_NULLPTR) {
QMutexLocker locker(mutex);
currentButton->toggle=(int)state;
}
}
void controllerSetup::removeDevice(USBDEVICE* dev)
{
QMutexLocker locker(mutex);
/* We need to manually delete everything that has been created for this tab */
auto tab = tabs.find(dev->path);
if (tab == tabs.end())
{
qWarning(logUsbControl()) << "Cannot find tabContent for deleted tab" << dev->path;
return;
}
for (auto b = buttons->begin();b != buttons->end(); b++)
{
if (b->parent == dev && b->page == dev->currentPage)
{
if (b->text != Q_NULLPTR) {
tab.value()->scene->removeItem(b->text);
delete b->text;
b->text = Q_NULLPTR;
}
b->offCommand = Q_NULLPTR;
b->onCommand = Q_NULLPTR;
if (b->icon != Q_NULLPTR) {
delete b->icon;
b->icon=Q_NULLPTR;
}
if (b->bgRect != Q_NULLPTR) {
tab.value()->scene->removeItem(b->bgRect);
delete b->bgRect;
b->bgRect = Q_NULLPTR;
}
}
}
for (auto k = knobs->begin();k != knobs->end(); k++)
{
if (k->parent == dev && k->page == dev->currentPage)
{
if (k->text != Q_NULLPTR) {
tab.value()->scene->removeItem(k->text);
delete k->text;
k->text = Q_NULLPTR;
k->command = Q_NULLPTR;
}
}
}
qDebug(logUsbControl()) << "Removing tab content" << dev->product;
if (tab.value()->bgImage != Q_NULLPTR) {
tab.value()->scene->removeItem(tab.value()->bgImage);
delete tab.value()->bgImage;
}
delete tab.value()->scene;
// Find the tab within the tabWidget
for (int i = 0; i < ui->tabWidget->count(); i++) {
auto widget = ui->tabWidget->widget(i);
if (widget->objectName() == dev->path) {
ui->tabWidget->removeTab(i);
break;
}
}
delete tab.value();
tabs.remove(dev->path);
// Hide the tabWidget if no tabs exist
if (ui->tabWidget->count() == 0)
{
ui->tabWidget->hide();
noControllersText->show();
this->adjustSize();
}
}
void controllerSetup::newDevice(USBDEVICE* dev)
{
QMutexLocker locker(mutex);
for (int i=0; i<ui->tabWidget->count();i++) {
if (ui->tabWidget->widget(i)->objectName() == dev->path)
{
qInfo(logUsbControl()) <<"Tab for " << dev->product << "("<< dev->path << ") Already exists!";
return;
}
}
auto tab = tabs.find(dev->path);
if (tab != tabs.end())
{
qInfo(logUsbControl()) <<"Tab content for " << dev->product << "("<< dev->path << ") Already exists!";
return;
}
qDebug(logUsbControl()) << "Adding new tab for" << dev->product;
noControllersText->hide();
tabContent* c = new tabContent();
c->tab = new QWidget();
c->widget = new QWidget();
c->tab->setObjectName(dev->path);
ui->tabWidget->addTab(c->tab,dev->product);
// Create the different layouts required
c->mainLayout = new QVBoxLayout(c->tab);
c->layout = new QVBoxLayout();
c->topLayout = new QHBoxLayout();
c->sensLayout = new QHBoxLayout();
c->grid = new QGridLayout();
c->mainLayout->addLayout(c->topLayout);
c->mainLayout->addWidget(c->widget);
c->widget->setLayout(c->layout);
c->disabled = new QCheckBox("Disable");
c->topLayout->addWidget(c->disabled);
connect(c->disabled, qOverload<bool>(&QCheckBox::clicked),
[dev,this,c](bool checked) { this->disableClicked(dev,checked,c->widget); });
c->disabled->setChecked(dev->disabled);
c->message = new QLabel();
if (dev->connected) {
c->message->setStyleSheet("QLabel { color : green; }");
c->message->setText("Connected");
} else {
c->message->setStyleSheet("QLabel { color : red; }");
c->message->setText("Not Connected");
}
c->topLayout->addWidget(c->message);
c->message->setAlignment(Qt::AlignRight);
c->view = new QGraphicsView();
c->layout->addWidget(c->view);
c->layout->addLayout(c->sensLayout);
c->sensLabel = new QLabel("Sensitivity");
c->sensLayout->addWidget(c->sensLabel);
c->sens = new QSlider(Qt::Horizontal);
c->sens->setMinimum(1);
c->sens->setMaximum(21);
c->sens->setInvertedAppearance(true);
c->sensLayout->addWidget(c->sens);
c->sens->setValue(dev->sensitivity);
connect(c->sens, &QSlider::valueChanged,
[dev,this](int val) { this->sensitivityMoved(dev,val); });
c->sensLayout->addStretch(0);
c->pageLabel = new QLabel("Page:");
c->sensLayout->addWidget(c->pageLabel);
c->page = new QSpinBox();
c->page->setValue(1);
c->page->setMinimum(1);
c->page->setMaximum(dev->pages);
c->page->setToolTip("Select current page to edit");
c->sensLayout->addWidget(c->page);
dev->pageSpin = c->page;
c->image = new QImage();
switch (dev->type.model) {
case shuttleXpress:
c->image->load(":/resources/shuttlexpress.png");
break;
case shuttlePro2:
c->image->load(":/resources/shuttlepro.png");
break;
case RC28:
c->image->load(":/resources/rc28.png");
break;
case xBoxGamepad:
c->image->load(":/resources/xbox.png");
break;
case eCoderPlus:
c->image->load(":/resources/ecoder.png");
break;
case QuickKeys:
c->image->load(":/resources/quickkeys.png");
break;
case StreamDeckOriginal:
case StreamDeckOriginalV2:
case StreamDeckOriginalMK2:
c->image->load(":/resources/streamdeck.png");
break;
case StreamDeckMini:
case StreamDeckMiniV2:
c->image->load(":/resources/streamdeckmini.png");
break;
case StreamDeckXL:
case StreamDeckXLV2:
c->image->load(":/resources/streamdeckxl.png");
break;
case StreamDeckPlus:
c->image->load(":/resources/streamdeckplus.png");
break;
case StreamDeckPedal:
c->image->load(":/resources/streamdeckpedal.png");
break;
default:
this->adjustSize();
break;
}
c->bgImage = new QGraphicsPixmapItem(QPixmap::fromImage(*c->image));
c->view->setMinimumSize(c->bgImage->boundingRect().width() + 2, c->bgImage->boundingRect().height() + 2);
ui->tabWidget->show();
c->scene = new controllerScene();
c->view->setScene(c->scene);
connect(c->scene, SIGNAL(showMenu(controllerScene*,QPoint)), this, SLOT(showMenu(controllerScene*,QPoint)));
c->scene->addItem(c->bgImage);
c->layout->addLayout(c->grid);
c->brightLabel = new QLabel("Brightness");
c->grid->addWidget(c->brightLabel,0,0);
c->brightness = new QComboBox();
c->brightness->addItem("Off");
c->brightness->addItem("Low");
c->brightness->addItem("Medium");
c->brightness->addItem("High");
c->brightness->setCurrentIndex(dev->brightness);
c->grid->addWidget(c->brightness,1,0);
connect(c->brightness, qOverload<int>(&QComboBox::currentIndexChanged),
[dev,this](int index) { this->brightnessChanged(dev,index); });
c->speedLabel = new QLabel("Speed");
c->grid->addWidget(c->speedLabel,0,1);
c->speed = new QComboBox();
c->speed->addItem("Fastest");
c->speed->addItem("Faster");
c->speed->addItem("Normal");
c->speed->addItem("Slower");
c->speed->addItem("Slowest");
c->speed->setCurrentIndex(dev->speed);
c->grid->addWidget(c->speed,1,1);
connect(c->speed, qOverload<int>(&QComboBox::currentIndexChanged),
[dev,this](int index) { this->speedChanged(dev,index); });
c->orientLabel = new QLabel("Orientation");
c->grid->addWidget(c->orientLabel,0,2);
c->orientation = new QComboBox();
c->orientation->addItem("Rotate 0");
c->orientation->addItem("Rotate 90");
c->orientation->addItem("Rotate 180");
c->orientation->addItem("Rotate 270");
c->orientation->setCurrentIndex(dev->orientation);
c->grid->addWidget(c->orientation,1,2);
connect(c->orientation, qOverload<int>(&QComboBox::currentIndexChanged),
[dev,this](int index) { this->orientationChanged(dev,index); });
c->color = new QPushButton("Color");
c->color->setStyleSheet(QString("background-color: %1").arg(dev->color.name(QColor::HexArgb)));
c->grid->addWidget(c->color,1,3);
connect(c->color, &QPushButton::clicked,
[dev,c,this]() { this->colorPicker(dev,c->color,dev->color); });
c->timeoutLabel = new QLabel("Timeout");
c->grid->addWidget(c->timeoutLabel,0,4);
c->timeout = new QSpinBox();
c->timeout->setValue(dev->timeout);
c->grid->addWidget(c->timeout,1,4);
connect(c->timeout, qOverload<int>(&QSpinBox::valueChanged),
[dev,this](int index) { this->timeoutChanged(dev,index); });
c->pagesLabel = new QLabel("Num Pages");
c->grid->addWidget(c->pagesLabel,0,5);
c->pages = new QSpinBox();
c->pages->setValue(dev->pages);
c->pages->setMinimum(1);
c->grid->addWidget(c->pages,1,5);
connect(c->pages, qOverload<int>(&QSpinBox::valueChanged),
[dev,this](int index) { this->pagesChanged(dev,index); });
for (int i=0;i<6;i++)
c->grid->setColumnStretch(i,1);
c->helpText = new QLabel();
c->helpText->setText("<p><b>Button configuration:</b> Right-click on each button to configure it.</p>");
c->helpText->setAlignment(Qt::AlignCenter);
c->layout->addWidget(c->helpText);
c->view->setSceneRect(c->scene->itemsBoundingRect());
this->adjustSize();
numTabs++;
tabs.insert(dev->path,c);
dev->uiCreated = true;
// Finally update the device with the default values
emit sendRequest(dev,usbFeatureType::featureSensitivity,dev->sensitivity);
emit sendRequest(dev,usbFeatureType::featureBrightness,dev->brightness);
emit sendRequest(dev,usbFeatureType::featureOrientation,dev->orientation);
emit sendRequest(dev,usbFeatureType::featureSpeed,dev->speed);
emit sendRequest(dev,usbFeatureType::featureTimeout,dev->timeout);
emit sendRequest(dev,usbFeatureType::featureColor,0,"", Q_NULLPTR, &dev->color);
// Attach pageChanged() here so we have access to all necessary vars
connect(c->page, qOverload<int>(&QSpinBox::valueChanged),
[dev, this](int index) { this->pageChanged(dev, index); });
// Hide all controls that are not relevant to this controller
// We rely on being able to fallthrough case
#if defined __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
switch (dev->type.model) {
case QuickKeys:
break;
case StreamDeckPedal:
c->sensLabel->setVisible(false);
c->sens->setVisible(false);
case shuttleXpress:
case shuttlePro2:
case RC28:
case xBoxGamepad:
case eCoderPlus:
c->brightLabel->setVisible(false);
c->speedLabel->setVisible(false);
c->timeoutLabel->setVisible(false);
c->orientLabel->setVisible(false);
c->brightness->setVisible(false);
c->speed->setVisible(false);
c->timeout->setVisible(false);
c->orientation->setVisible(false);
c->color->setVisible(false);
break;
case StreamDeckOriginal:
case StreamDeckOriginalV2:
case StreamDeckOriginalMK2:
case StreamDeckMini:
case StreamDeckMiniV2:
case StreamDeckXL:
case StreamDeckXLV2:
c->sensLabel->setVisible(false);
c->sens->setVisible(false); // No knobs!
case StreamDeckPlus:
c->speedLabel->setVisible(false);
c->timeoutLabel->setVisible(false);
c->orientLabel->setVisible(false);
c->speed->setVisible(false);
c->timeout->setVisible(false);
c->orientation->setVisible(false);
break;
default:
break;
}
// Don't allow fallthrough elsewhere in the file.
#if defined __GNUC__
#pragma GCC diagnostic pop
#endif
// pageChanged will update the buttons/knobs for the tab (using qTimer ensures mutex is unlocked first)
QTimer::singleShot(0, this, [=]() { pageChanged(dev,1); });
}
void controllerSetup::sensitivityMoved(USBDEVICE* dev, int val)
{
qInfo(logUsbControl()) << "Setting sensitivity" << val <<"for device" << dev->product;
emit sendRequest(dev,usbFeatureType::featureSensitivity,val);
}
void controllerSetup::brightnessChanged(USBDEVICE* dev, int index)
{
emit sendRequest(dev,usbFeatureType::featureBrightness,index);
}
void controllerSetup::orientationChanged(USBDEVICE* dev, int index)
{
emit sendRequest(dev,usbFeatureType::featureOrientation,index);
}
void controllerSetup::speedChanged(USBDEVICE* dev, int index)
{
emit sendRequest(dev,usbFeatureType::featureSpeed,index);
}
void controllerSetup::colorPicker(USBDEVICE* dev, QPushButton* btn, QColor current)
{
QColorDialog::ColorDialogOptions options;
options.setFlag(QColorDialog::ShowAlphaChannel, false);
options.setFlag(QColorDialog::DontUseNativeDialog, false);
QColor selColor = QColorDialog::getColor(current, this, "Select Color", options);
if(selColor.isValid())
{
btn->setStyleSheet(QString("background-color: %1").arg(selColor.name(QColor::HexArgb)));
emit sendRequest(dev,usbFeatureType::featureColor,0, "", Q_NULLPTR, &selColor);
}
}
void controllerSetup::timeoutChanged(USBDEVICE* dev, int val)
{
emit sendRequest(dev,usbFeatureType::featureTimeout,val);
emit sendRequest(dev,usbFeatureType::featureOverlay,val,QString("Sleep timeout set to %0 minutes").arg(val));
}
void controllerSetup::pagesChanged(USBDEVICE* dev, int val)
{
emit programPages(dev,val);
dev->pageSpin->setMaximum(val); // Update pageSpin
}
void controllerSetup::pageChanged(USBDEVICE* dev, int val)
{
QMutexLocker locker(mutex);
auto tab = tabs.find(dev->path);
if (tab == tabs.end())
{
qWarning(logUsbControl()) << "Cannot find tabContent while changing page" << dev->path;
return;
}
if (val > dev->pages)
val=1;
if (val < 1)
val = dev->pages;
updateDialog->hide(); // Hide the dialog if the page changes.
dev->currentPage=val;
// Need to block signals so this isn't called recursively.
dev->pageSpin->blockSignals(true);
dev->pageSpin->setValue(val);
dev->pageSpin->blockSignals(false);
// (re)set button text
for (auto b = buttons->begin();b != buttons->end(); b++)
{
if (b->parent == dev)
{
// Make sure we delete any other pages content and then update to latest.
if (b->text != Q_NULLPTR) {
tab.value()->scene->removeItem(b->text);
delete b->text;
b->text = Q_NULLPTR;
}
if (b->graphics && b->bgRect != Q_NULLPTR) {
tab.value()->scene->removeItem(b->bgRect);
delete b->bgRect;
b->bgRect = Q_NULLPTR;
}
if (b->page == dev->currentPage)
{
if (b->graphics)
{
b->bgRect = new QGraphicsRectItem(b->pos);
b->bgRect->setBrush(b->backgroundOn);
tab.value()->scene->addItem(b->bgRect);
}
b->text = new QGraphicsTextItem(b->onCommand->text);
b->text->setDefaultTextColor(b->textColour);
tab.value()->scene->addItem(b->text);
b->text->setPos(b->pos.center().x() - b->text->boundingRect().width() / 2,
(b->pos.center().y() - b->text->boundingRect().height() / 2));
emit sendRequest(dev,usbFeatureType::featureButton,b->num,b->onCommand->text,b->icon,&b->backgroundOn);
}
}
}
// Set knob text
for (auto k = knobs->begin();k != knobs->end(); k++)
{
if (k->parent == dev) {
if (k->text != Q_NULLPTR) {
tab.value()->scene->removeItem(k->text);
delete k->text;
k->text = Q_NULLPTR;
}
if (k->page == dev->currentPage)
{
k->text = new QGraphicsTextItem(k->command->text);
k->text->setDefaultTextColor(k->textColour);
tab.value()->scene->addItem(k->text);
k->text->setPos(k->pos.center().x() - k->text->boundingRect().width() / 2,
(k->pos.center().y() - k->text->boundingRect().height() / 2));
}
}
}
}
void controllerSetup::disableClicked(USBDEVICE* dev, bool clicked, QWidget* widget)
{
// Disable checkbox has been clicked
emit programDisable(dev, clicked);
widget->setEnabled(!clicked);
}
void controllerSetup::setConnected(USBDEVICE* dev)
{
QMutexLocker locker(mutex);
auto tab = tabs.find(dev->path);
if (tab != tabs.end())
{
if (dev->connected)
{
tab.value()->message->setStyleSheet("QLabel { color : green; }");
tab.value()->message->setText("Connected");
} else {
tab.value()->message->setStyleSheet("QLabel { color : red; }");
tab.value()->message->setText("Not Connected");
}
}
}
void controllerSetup::on_backupButton_clicked()
{
QString file = QFileDialog::getSaveFileName(this,"Select Backup Filename",".","Backup Files (*.ini)");
if (!file.isEmpty()) {
auto devIt = devices->find(ui->tabWidget->currentWidget()->objectName());
if (devIt==devices->end())
{
qWarning(logUsbControl) << "on_restoreButton_clicked() Cannot find existing controller, aborting!";
}
else
{
emit backup(&devIt.value(), file);
}
}
}
void controllerSetup::on_restoreButton_clicked()
{
QMutexLocker locker(mutex);
QString file = QFileDialog::getOpenFileName(this,"Select Backup Filename",".","Backup Files (*.ini)");
if (!file.isEmpty()) {
QString path = ui->tabWidget->currentWidget()->objectName();
auto devIt = devices->find(path);
if (devIt==devices->end())
{
qWarning(logUsbControl) << "on_restoreButton_clicked() Cannot find existing controller, aborting!";
return;
}
auto dev = &devIt.value();
QSettings* settings = new QSettings(file, QSettings::Format::IniFormat);
QString version = settings->value("Version", "").toString();
settings->beginGroup("Controller");
QString model = settings->value("Model","").toString();
delete settings;
if (model != dev->product) {
QMessageBox msgBox;
msgBox.setText("Stored controller does not match");
msgBox.setInformativeText(QString("Backup: %0 \nCurrent: %1\n\nThis will probably not work!").arg(model,dev->product));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
int ret= msgBox.exec();
if (ret == QMessageBox::Cancel) {
return;
}
}
if (version != QString(WFVIEW_VERSION))
{
QMessageBox msgBox;
msgBox.setText("Version mismatch");
msgBox.setInformativeText(QString("Backup was from a different version of wfview\nBackup: %0 \nCurrent: %1\n\nPlease verify compatibility").arg(version, QString(WFVIEW_VERSION)));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
int ret= msgBox.exec();
if (ret == QMessageBox::Cancel) {
return;
}
}
emit restore(dev, file);
}
}

223
controllersetup.h 100644
Wyświetl plik

@ -0,0 +1,223 @@
#ifndef CONTROLLERSETUP_H
#define CONTROLLERSETUP_H
#include <QDialog>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsTextItem>
#include <QGraphicsPixmapItem>
#include <QGraphicsRectItem>
#include <QPoint>
#include <QGraphicsSceneMouseEvent>
#include <QVector>
#include <QRect>
#include <QComboBox>
#include <QLabel>
#include <QGraphicsProxyWidget>
#include <QAbstractItemView>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QPushButton>
#include <QScopedPointer>
#include <QCheckBox>
#include <QFileDialog>
#include <QMessageBox>
#include <QLayoutItem>
#include <QDebug>
#include <QObject>
#include <QColorDialog>
#include <QWidget>
#include <QSpinBox>
#include <QCheckBox>
#include "usbcontroller.h"
class controllerScene : public QGraphicsScene
{
Q_OBJECT
QGraphicsLineItem* item = Q_NULLPTR;
signals:
void showMenu(controllerScene* scene, QPoint p);
void buttonAction(bool pressed, QPoint p);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent* event) {
if (event->button() == Qt::RightButton)
{
emit showMenu(this, event->scenePos().toPoint());
}
else if (event->button() == Qt::LeftButton)
{
// Simulate a button press
emit buttonAction(true,event->scenePos().toPoint());
}
else
{
QGraphicsScene::mousePressEvent(event);
}
}
void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
if (event->button() == Qt::LeftButton)
{
// Simulate a button release
emit buttonAction(false,event->scenePos().toPoint());
}
else
{
QGraphicsScene::mouseReleaseEvent(event);
}
}
};
struct tabContent {
QWidget* tab;
QVBoxLayout* mainLayout;
QHBoxLayout* topLayout;
QWidget* widget;
QVBoxLayout* layout;
QCheckBox* disabled;
QLabel* message;
QGraphicsView* view;
QLabel* pageLabel;
QSpinBox* page;
QHBoxLayout* sensLayout;
QLabel* sensLabel;
QSlider* sens;
QImage* image;
QGraphicsItem* bgImage = Q_NULLPTR;
controllerScene* scene = Q_NULLPTR;
QGridLayout* grid;
QLabel* brightLabel;
QComboBox* brightness;
QLabel* speedLabel;
QComboBox* speed;
QLabel* orientLabel;
QComboBox* orientation;
QLabel* colorLabel;
QPushButton* color;
QLabel* timeoutLabel;
QSpinBox* timeout;
QLabel* pagesLabel;
QSpinBox* pages;
QLabel* helpText;
};
namespace Ui {
class controllerSetup;
}
class controllerSetup : public QDialog
{
Q_OBJECT
public:
explicit controllerSetup(QWidget* parent = 0);
~controllerSetup();
signals:
void started();
void sendRequest(USBDEVICE* dev, usbFeatureType request, int val=0, QString text="", QImage* img=Q_NULLPTR, QColor* color=Q_NULLPTR);
void programDisable(USBDEVICE* dev, bool disable);
void programPages(USBDEVICE* dev, int pages);
void backup(USBDEVICE* dev, QString path);
void restore(USBDEVICE *dev, QString path);
public slots:
void init(usbDevMap* dev, QVector<BUTTON>* but, QVector<KNOB>* kb, QVector<COMMAND>* cmd, QMutex* mut);
void newDevice(USBDEVICE* dev);
void removeDevice(USBDEVICE* dev);
void showMenu(controllerScene *scene,QPoint p);
void onEventIndexChanged(int index);
void offEventIndexChanged(int index);
void knobEventIndexChanged(int index);
void ledNumberChanged(int index);
void sensitivityMoved(USBDEVICE* dev, int val);
void brightnessChanged(USBDEVICE* dev, int index);
void orientationChanged(USBDEVICE* dev, int index);
void speedChanged(USBDEVICE* dev, int index);
void colorPicker(USBDEVICE* dev, QPushButton* btn, QColor color);
void buttonOnColorClicked();
void buttonOffColorClicked();
void buttonIconClicked();
void latchStateChanged(int state);
void timeoutChanged(USBDEVICE* dev, int val);
void pageChanged(USBDEVICE* dev, int val);
void pagesChanged(USBDEVICE* dev, int val);
void disableClicked(USBDEVICE* dev, bool clicked, QWidget* widget);
void setConnected(USBDEVICE* dev);
void hideEvent(QHideEvent *event);
void on_tabWidget_currentChanged(int index);
void on_backupButton_clicked();
void on_restoreButton_clicked();
private:
usbDeviceType type = usbNone;
Ui::controllerSetup* ui;
QGraphicsTextItem* textItem;
QLabel* imgLabel;
unsigned char currentDevice = 0;
QVector<BUTTON>* buttons;
QVector<KNOB>* knobs;
QVector<COMMAND>* commands;
usbDevMap* devices;
BUTTON* currentButton = Q_NULLPTR;
KNOB* currentKnob = Q_NULLPTR;
// Update Dialog
QDialog * updateDialog = Q_NULLPTR;
QComboBox* onEvent;
QComboBox* offEvent;
QComboBox* knobEvent;
QLabel* onLabel;
QLabel* offLabel;
QLabel* knobLabel;
QPushButton* buttonOnColor;
QPushButton* buttonOffColor;
QCheckBox *buttonLatch;
QPushButton* buttonIcon;
QLabel* iconLabel;
QSpinBox* ledNumber;
QString deviceName;
QMutex* mutex;
QColor initialColor = Qt::white;
QLabel* noControllersText;
int numTabs=0;
QMap<QString,tabContent*> tabs;
// Below are used for each tab:
/*
QList<QWidget *> tabs;
QList<QVBoxLayout *> layouts;
QList<QWidget *> widgets;
QList<QGraphicsView *> graphicsViews;
QList<QGraphicsScene*> scenes;
QList<QGraphicsItem*> bgImages;
QList<QSlider *>sensitivitys;
// Just used for QuickKeys device
QList<QComboBox *>brightCombos;
QList<QComboBox *>speedCombos;
QList<QComboBox *>orientCombos;
QList<QPushButton *>colorButtons;
QList<QSpinBox *>timeoutSpins;
*/
};
#endif

134
controllersetup.ui 100644
Wyświetl plik

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>controllerSetup</class>
<widget class="QDialog" name="controllerSetup">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>788</width>
<height>646</height>
</rect>
</property>
<property name="windowTitle">
<string>Controller setup</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 2</string>
</attribute>
</widget>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="backupButton">
<property name="text">
<string>Backup</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="restoreButton">
<property name="text">
<string>Restore</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>131</width>
<height>31</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>okButton</sender>
<signal>clicked()</signal>
<receiver>controllerSetup</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>278</x>
<y>253</y>
</hint>
<hint type="destinationlabel">
<x>96</x>
<y>254</y>
</hint>
</hints>
</connection>
<connection>
<sender>cancelButton</sender>
<signal>clicked()</signal>
<receiver>controllerSetup</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>369</x>
<y>253</y>
</hint>
<hint type="destinationlabel">
<x>179</x>
<y>282</y>
</hint>
</hints>
</connection>
</connections>
</ui>

493
cwsender.cpp 100644
Wyświetl plik

@ -0,0 +1,493 @@
#include "cwsender.h"
#include "ui_cwsender.h"
#include "logcategories.h"
cwSender::cwSender(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::cwSender)
{
ui->setupUi(this);
this->setWindowTitle("CW Sender");
ui->textToSendEdit->setFocus();
QFont f = QFont("Monospace");
f.setStyleHint(QFont::TypeWriter);
ui->textToSendEdit->setFont(f);
ui->transcriptText->setFont(f);
ui->textToSendEdit->setFocus();
ui->statusbar->setToolTipDuration(3000);
this->setToolTipDuration(3000);
connect(ui->textToSendEdit->lineEdit(), &QLineEdit::textEdited, this, &cwSender::textChanged);
}
cwSender::~cwSender()
{
qDebug(logCW()) << "Running CW Sender destructor.";
if (toneThread != Q_NULLPTR) {
toneThread->quit();
toneThread->wait();
toneThread = Q_NULLPTR;
tone = Q_NULLPTR;
/* Finally disconnect all connections */
for (auto conn: connections)
{
disconnect(conn);
}
connections.clear();
}
delete ui;
}
void cwSender::showEvent(QShowEvent *event)
{
(void)event;
emit getCWSettings();
QMainWindow::showEvent(event);
}
void cwSender::handleKeySpeed(unsigned char wpm)
{
if (wpm != ui->wpmSpin->value() && (wpm >= ui->wpmSpin->minimum()) && (wpm <= ui->wpmSpin->maximum()))
{
ui->wpmSpin->blockSignals(true);
QMetaObject::invokeMethod(ui->wpmSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, wpm));
ui->wpmSpin->blockSignals(false);
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
QMetaObject::invokeMethod(tone, [=]() {
tone->setSpeed(wpm);
}, Qt::QueuedConnection);
#else
emit setKeySpeed(ratio);
#endif
}
}
void cwSender::handleDashRatio(unsigned char ratio)
{
double calc = double(ratio/10);
if (calc != ui->dashSpin->value() && (calc >= ui->dashSpin->minimum()) && (ratio <= ui->dashSpin->maximum()))
{
ui->dashSpin->blockSignals(true);
QMetaObject::invokeMethod(ui->dashSpin, "setValue", Qt::QueuedConnection, Q_ARG(double, calc));
ui->dashSpin->blockSignals(false);
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
QMetaObject::invokeMethod(tone, [=]() {
tone->setRatio(ratio);
}, Qt::QueuedConnection);
#else
emit setDashRatio(ratio);
#endif
}
}
void cwSender::handlePitch(unsigned char pitch) {
int cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0;
if (cwPitch != ui->pitchSpin->value() && cwPitch >= ui->pitchSpin->minimum() && cwPitch <= ui->pitchSpin->maximum())
{
ui->pitchSpin->blockSignals(true);
QMetaObject::invokeMethod(ui->pitchSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, cwPitch));
ui->pitchSpin->blockSignals(false);
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
QMetaObject::invokeMethod(tone, [=]() {
tone->setFrequency(pitch);
}, Qt::QueuedConnection);
#else
emit setPitch(tone);
#endif
}
}
void cwSender::handleBreakInMode(unsigned char b)
{
if(b < 3)
{
ui->breakinCombo->blockSignals(true);
ui->breakinCombo->setCurrentIndex(b);
ui->breakinCombo->blockSignals(false);
}
}
void cwSender::handleCurrentModeUpdate(mode_kind mode)
{
this->currentMode = mode;
if( (currentMode==modeCW) || (currentMode==modeCW_R) )
{
} else {
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
}
}
void cwSender::textChanged(QString text)
{
if (ui->sendImmediateChk->isChecked() && text.size() && text.back() == ' ')
{
int toSend = text.mid(0, 30).size();
if (toSend > 0) {
ui->textToSendEdit->clearEditText();
ui->transcriptText->moveCursor(QTextCursor::End);
ui->transcriptText->insertPlainText(text.mid(0, 30).toUpper());
ui->transcriptText->moveCursor(QTextCursor::End);
emit sendCW(text.mid(0, 30));
}
if( (currentMode != modeCW) && (currentMode != modeCW_R) )
{
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
}
}
}
void cwSender::on_sendBtn_clicked()
{
if( (ui->textToSendEdit->currentText().length() > 0) &&
(ui->textToSendEdit->currentText().length() <= 30) )
{
QString text = ui->textToSendEdit->currentText();
ui->transcriptText->moveCursor(QTextCursor::End);
ui->transcriptText->insertPlainText(ui->textToSendEdit->currentText().toUpper()+"\n");
ui->transcriptText->moveCursor(QTextCursor::End);
if (!ui->sendImmediateChk->isChecked())
{
ui->textToSendEdit->addItem(ui->textToSendEdit->currentText());
if (ui->textToSendEdit->count() > 5) {
ui->textToSendEdit->removeItem(0);
}
ui->textToSendEdit->setCurrentIndex(-1);
} else {
ui->textToSendEdit->clearEditText();
ui->textToSendEdit->clear();
}
ui->textToSendEdit->setFocus();
ui->statusbar->showMessage("Sending CW", 3000);
emit sendCW(text);
}
if( (currentMode != modeCW) && (currentMode != modeCW_R) )
{
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
}
}
void cwSender::on_stopBtn_clicked()
{
emit stopCW();
ui->textToSendEdit->setFocus();
ui->statusbar->showMessage("Stopping CW transmission.", 3000);
}
//void cwSender::on_textToSendEdit_returnPressed()
//{
// on_sendBtn_clicked();
//}
void cwSender::on_breakinCombo_activated(int brkmode)
{
// 0 = off, 1 = semi, 2 = full
emit setBreakInMode((unsigned char)brkmode);
ui->textToSendEdit->setFocus();
}
void cwSender::on_wpmSpin_valueChanged(int wpm)
{
emit setKeySpeed((unsigned char)wpm);
}
void cwSender::on_dashSpin_valueChanged(double ratio)
{
emit setDashRatio((unsigned char)double(ratio * 10));
}
void cwSender::on_pitchSpin_valueChanged(int arg1)
{
// quint16 cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0;
unsigned char pitch = 0;
pitch = ceil((arg1 - 300) * (255.0 / 600.0));
emit setPitch(pitch);
}
void cwSender::on_macro1btn_clicked()
{
processMacroButton(1, ui->macro1btn);
}
void cwSender::on_macro2btn_clicked()
{
processMacroButton(2, ui->macro2btn);
}
void cwSender::on_macro3btn_clicked()
{
processMacroButton(3, ui->macro3btn);
}
void cwSender::on_macro4btn_clicked()
{
processMacroButton(4, ui->macro4btn);
}
void cwSender::on_macro5btn_clicked()
{
processMacroButton(5, ui->macro5btn);
}
void cwSender::on_macro6btn_clicked()
{
processMacroButton(6, ui->macro6btn);
}
void cwSender::on_macro7btn_clicked()
{
processMacroButton(7, ui->macro7btn);
}
void cwSender::on_macro8btn_clicked()
{
processMacroButton(8, ui->macro8btn);
}
void cwSender::on_macro9btn_clicked()
{
processMacroButton(9, ui->macro9btn);
}
void cwSender::on_macro10btn_clicked()
{
processMacroButton(10, ui->macro10btn);
}
void cwSender::on_sidetoneEnableChk_clicked(bool clicked)
{
ui->sidetoneLevelSlider->setEnabled(clicked);
if (clicked && toneThread == Q_NULLPTR)
{
toneThread = new QThread(this);
toneThread->setObjectName("sidetone()");
tone = new cwSidetone(sidetoneLevel, ui->wpmSpin->value(),ui->pitchSpin->value(),ui->dashSpin->value(),this);
tone->moveToThread(toneThread);
toneThread->start();
connections.append(connect(toneThread, &QThread::finished,
[=]() { tone->deleteLater(); }));
connections.append(connect(this, &cwSender::sendCW,
[=](const QString& text) { tone->send(text); ui->sidetoneEnableChk->setEnabled(false); }));
connections.append(connect(this, &cwSender::setKeySpeed,
[=](const unsigned char& wpm) { tone->setSpeed(wpm); }));
connections.append(connect(this, &cwSender::setDashRatio,
[=](const unsigned char& ratio) { tone->setRatio(ratio); }));
connections.append(connect(this, &cwSender::setPitch,
[=](const unsigned char& pitch) { tone->setFrequency(pitch); }));
connections.append(connect(this, &cwSender::setLevel,
[=](const unsigned char& level) { tone->setLevel(level); }));
connections.append(connect(this, &cwSender::stopCW,
[=]() { tone->stopSending(); }));
connections.append(connect(tone, &cwSidetone::finished,
[=]() { ui->sidetoneEnableChk->setEnabled(true); }));
} else if (!clicked && toneThread != Q_NULLPTR) {
/* disconnect all connections */
toneThread->quit();
toneThread->wait();
toneThread = Q_NULLPTR;
tone = Q_NULLPTR;
for (auto conn: connections)
{
disconnect(conn);
}
connections.clear();
}
}
void cwSender::on_sidetoneLevelSlider_valueChanged(int val)
{
sidetoneLevel = val;
emit setLevel(val);
}
void cwSender::processMacroButton(int buttonNumber, QPushButton *btn)
{
if(ui->macroEditChk->isChecked())
{
editMacroButton(buttonNumber, btn);
} else {
runMacroButton(buttonNumber);
}
ui->textToSendEdit->setFocus();
}
void cwSender::runMacroButton(int buttonNumber)
{
if(macroText[buttonNumber].isEmpty())
return;
QString outText;
if(macroText[buttonNumber].contains("%1"))
{
outText = macroText[buttonNumber].arg(sequenceNumber, 3, 10, QChar('0'));
sequenceNumber++;
ui->sequenceSpin->blockSignals(true);
QMetaObject::invokeMethod(ui->sequenceSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, sequenceNumber));
ui->sequenceSpin->blockSignals(false);
} else {
outText = macroText[buttonNumber];
}
if (ui->cutNumbersChk->isChecked())
{
outText.replace("0", "T");
outText.replace("9", "N");
}
ui->transcriptText->moveCursor(QTextCursor::End);
ui->transcriptText->insertPlainText(outText.toUpper()+"\n");
ui->transcriptText->moveCursor(QTextCursor::End);
for (int i = 0; i < outText.size(); i = i + 30) {
emit sendCW(outText.mid(i,30));
}
ui->textToSendEdit->setFocus();
if( (currentMode==modeCW) || (currentMode==modeCW_R) )
{
ui->statusbar->showMessage(QString("Sending CW macro %1").arg(buttonNumber));
} else {
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.");
}
}
void cwSender::editMacroButton(int buttonNumber, QPushButton* btn)
{
bool ok;
QString promptFirst = QString("Please enter the text for macro %1,\n"
"up to 60 characters.\n").arg(buttonNumber);
QString promptSecond = QString("You may use \"%1\" to insert a sequence number.");
QString prompt = promptFirst+promptSecond;
QString newMacroText = QInputDialog::getText(this, "Macro Edit",
prompt,
QLineEdit::Normal, macroText[buttonNumber], &ok).toUpper();
if(!ok)
return;
if (newMacroText.length() > 60)
{
QMessageBox msgBox;
msgBox.setText(QString("The text entered was too long \n"
"(max length is 60 characters).\n"
"Your input was %1 characters.").arg(newMacroText.length()));
msgBox.exec();
this->raise();
return;
}
macroText[buttonNumber] = newMacroText;
setMacroButtonText(newMacroText, btn);
}
void cwSender::setMacroButtonText(QString btnText, QPushButton *btn)
{
if(btn==Q_NULLPTR)
return;
if(btnText.isEmpty())
return;
QString shortBtnName;
if(btnText.length() <= 8)
{
shortBtnName = btnText;
} else {
shortBtnName = btnText.left(7);
shortBtnName.append("");
}
btn->setText(shortBtnName);
}
void cwSender::on_sequenceSpin_valueChanged(int newSeq)
{
sequenceNumber = newSeq;
ui->textToSendEdit->setFocus();
}
bool cwSender::getCutNumbers()
{
return ui->cutNumbersChk->isChecked();
}
bool cwSender::getSendImmediate()
{
return ui->sendImmediateChk->isChecked();
}
bool cwSender::getSidetoneEnable()
{
return ui->sidetoneEnableChk->isChecked();
}
int cwSender::getSidetoneLevel()
{
return ui->sidetoneLevelSlider->value();
}
void cwSender::setCutNumbers(bool val)
{
ui->cutNumbersChk->setChecked(val);
}
void cwSender::setSendImmediate(bool val)
{
ui->sendImmediateChk->setChecked(val);
}
void cwSender::setSidetoneEnable(bool val)
{
ui->sidetoneEnableChk->setChecked(val);
on_sidetoneEnableChk_clicked(val);
}
void cwSender::setSidetoneLevel(int val)
{
QMetaObject::invokeMethod(ui->sidetoneLevelSlider, "setValue", Qt::QueuedConnection, Q_ARG(int, val));
}
QStringList cwSender::getMacroText()
{
// This is for preference saving:
QStringList mlist;
for(int i=1; i < 11; i++)
{
mlist << macroText[i];
}
return mlist;
}
void cwSender::setMacroText(QStringList macros)
{
if(macros.length() != 10)
{
qCritical(logCW()) << "Macro list must be exactly 10. Rejecting macro text load.";
return;
}
for(int i=0; i < 10; i++)
{
macroText[i+1] = macros.at(i);
}
setMacroButtonText(macroText[1], ui->macro1btn);
setMacroButtonText(macroText[2], ui->macro2btn);
setMacroButtonText(macroText[3], ui->macro3btn);
setMacroButtonText(macroText[4], ui->macro4btn);
setMacroButtonText(macroText[5], ui->macro5btn);
setMacroButtonText(macroText[6], ui->macro6btn);
setMacroButtonText(macroText[7], ui->macro7btn);
setMacroButtonText(macroText[8], ui->macro8btn);
setMacroButtonText(macroText[9], ui->macro9btn);
setMacroButtonText(macroText[10], ui->macro10btn);
}

119
cwsender.h 100644
Wyświetl plik

@ -0,0 +1,119 @@
#ifndef CWSENDER_H
#define CWSENDER_H
#include <QMainWindow>
#include <QString>
#include <QFont>
#include <QInputDialog>
#include <QMessageBox>
#include <QThread>
#include <QList>
#include <math.h>
#include "cwsidetone.h"
#include "wfviewtypes.h"
namespace Ui {
class cwSender;
}
class cwSender : public QMainWindow
{
Q_OBJECT
public:
explicit cwSender(QWidget *parent = 0);
~cwSender();
QStringList getMacroText();
void setMacroText(QStringList macros);
void setCutNumbers(bool val);
void setSendImmediate(bool val);
void setSidetoneEnable(bool val);
void setSidetoneLevel(int val);
bool getCutNumbers();
bool getSendImmediate();
bool getSidetoneEnable();
int getSidetoneLevel();
signals:
void sendCW(QString cwMessage);
void stopCW();
void setKeySpeed(unsigned char wpm);
void setDashRatio(unsigned char ratio);
void setPitch(unsigned char pitch);
void setLevel(int level);
void setBreakInMode(unsigned char b);
void getCWSettings();
void sidetone(QString text);
void pitchChanged(int val);
void dashChanged(int val);
void wpmChanged(int val);
public slots:
void handleKeySpeed(unsigned char wpm);
void handleDashRatio(unsigned char ratio);
void handlePitch(unsigned char pitch);
void handleBreakInMode(unsigned char b);
void handleCurrentModeUpdate(mode_kind mode);
private slots:
void on_sendBtn_clicked();
void showEvent(QShowEvent* event);
void on_stopBtn_clicked();
//void on_textToSendEdit_returnPressed();
void textChanged(QString text);
void on_breakinCombo_activated(int index);
void on_wpmSpin_valueChanged(int arg1);
void on_dashSpin_valueChanged(double arg1);
void on_pitchSpin_valueChanged(int arg1);
void on_macro1btn_clicked();
void on_macro2btn_clicked();
void on_macro3btn_clicked();
void on_macro4btn_clicked();
void on_macro5btn_clicked();
void on_macro6btn_clicked();
void on_macro7btn_clicked();
void on_macro8btn_clicked();
void on_macro9btn_clicked();
void on_macro10btn_clicked();
void on_sequenceSpin_valueChanged(int arg1);
void on_sidetoneEnableChk_clicked(bool clicked);
void on_sidetoneLevelSlider_valueChanged(int val);
private:
Ui::cwSender *ui;
QString macroText[11];
int sequenceNumber = 1;
int lastSentPos = 0;
mode_kind currentMode;
int sidetoneLevel=0;
void processMacroButton(int buttonNumber, QPushButton *btn);
void runMacroButton(int buttonNumber);
void editMacroButton(int buttonNumber, QPushButton *btn);
void setMacroButtonText(QString btnText, QPushButton *btn);
cwSidetone* tone=Q_NULLPTR;
QThread* toneThread = Q_NULLPTR;
bool sidetoneWasEnabled=false;
QList<QMetaObject::Connection> connections;
};
#endif // CWSENDER_H

468
cwsender.ui 100644
Wyświetl plik

@ -0,0 +1,468 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>cwSender</class>
<widget class="QMainWindow" name="cwSender">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>835</width>
<height>451</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="toolTip">
<string>Send the text in the edit box</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0" colspan="12">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Macros</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="4">
<widget class="QPushButton" name="macro5btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 5</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="macro2btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 2</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="macro4btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 4</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QCheckBox" name="macroEditChk">
<property name="toolTip">
<string>Check this box to enter edit mode, where you can then press the macro buttons to edit the macros.</string>
</property>
<property name="text">
<string>Edit Mode</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="macro7btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 7</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="macro3btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 3</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="macro6btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 6</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="macro10btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 10</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="macro9btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 9</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="macro8btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 8</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="macro1btn">
<property name="toolTip">
<string>Macro Access Button</string>
</property>
<property name="text">
<string>Macro 1</string>
</property>
</widget>
</item>
<item row="1" column="5">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Seq</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sequenceSpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sequence number, for contests. &lt;/p&gt;&lt;p&gt;Substitute &amp;quot;%1&amp;quot; in your macro text to use it. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="12">
<widget class="QPlainTextEdit" name="transcriptText">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>CW Transmission Transcript</string>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="stopBtn">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Stop sending CW</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Local Sidetone Level</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="sidetoneLevelSlider">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="sidetoneEnableChk">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="sendBtn">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Send</string>
</property>
<property name="shortcut">
<string>Return</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="textToSendEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Type here to send text as CW</string>
</property>
<property name="inputMethodHints">
<set>Qt::ImhUppercaseOnly</set>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string notr="true"/>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="3" colspan="2">
<layout class="QGridLayout" name="gridLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item row="3" column="0">
<widget class="QComboBox" name="breakinCombo">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the desired break-in mode:&lt;/p&gt;&lt;p&gt;1. None: You must manually key and unkey the radio.&lt;/p&gt;&lt;p&gt;2. Semi: Transmit is automatic and switches to receive at the end of the text.&lt;/p&gt;&lt;p&gt;3. Full: Same as semi, but with breaks between characters when possible.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>Off</string>
</property>
</item>
<item>
<property name="text">
<string>Semi</string>
</property>
</item>
<item>
<property name="text">
<string>Full</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>PITCH (Hz):</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>WPM:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="pitchSpin">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>300</number>
</property>
<property name="maximum">
<number>900</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="value">
<number>600</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Break In</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QDoubleSpinBox" name="dashSpin">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>2.800000000000000</double>
</property>
<property name="maximum">
<double>4.500000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>3.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Dash Ratio</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="wpmSpin">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Set the Words Per Minute</string>
</property>
<property name="minimum">
<number>6</number>
</property>
<property name="maximum">
<number>48</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QCheckBox" name="cutNumbersChk">
<property name="text">
<string>Cut Num</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QCheckBox" name="sendImmediateChk">
<property name="text">
<string>Send Immed</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

308
cwsidetone.cpp 100644
Wyświetl plik

@ -0,0 +1,308 @@
#include "cwsidetone.h"
#include "logcategories.h"
cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* parent) :
parent(parent),
volume(level),
speed(speed),
frequency(freq),
ratio(ratio)
{
/*
* Characters to match Icom table
* Unknown characters will return '?'
*/
cwTable.clear();
cwTable['0'] = "-----";
cwTable['1'] = ".----";
cwTable['2'] = "..---";
cwTable['3'] = "...--";
cwTable['4'] = "....-";
cwTable['5'] = ".....";
cwTable['6'] = "-....";
cwTable['7'] = "--...";
cwTable['8'] = "---..";
cwTable['9'] = "----.";
cwTable['A'] = ".-";
cwTable['B'] = "-...";
cwTable['C'] = "-.-.";
cwTable['D'] = "-..";
cwTable['E'] = ".";
cwTable['F'] = "..-.";
cwTable['G'] = "--.";
cwTable['H'] = "....";
cwTable['I'] = "..";
cwTable['J'] = ".---";
cwTable['K'] = "-.-";
cwTable['L'] = ".-..";
cwTable['M'] = "--";
cwTable['N'] = "-.";
cwTable['O'] = "---";
cwTable['P'] = ".--.";
cwTable['Q'] = "--.-";
cwTable['R'] = ".-.";
cwTable['S'] = "...";
cwTable['T'] = "-";
cwTable['U'] = "..-";
cwTable['V'] = "...-";
cwTable['W'] = ".--";
cwTable['X'] = "-..-";
cwTable['Y'] = "-.--";
cwTable['Z'] = "--..";
cwTable['/'] = "-..-.";
cwTable['?'] = "..--..";
cwTable['.'] = ".-.-.-";
cwTable['-'] = "-....-";
cwTable[','] = "--..--";
cwTable[':'] = "---...";
cwTable['\''] = ".----.";
cwTable['('] = "-.--.-";
cwTable[')'] = "-.--.-";
cwTable['='] = "-...-";
cwTable['+'] = ".-.-.";
cwTable['"'] = ".-..-.";
cwTable[' '] = " ";
init();
}
cwSidetone::~cwSidetone()
{
qInfo(logCW()) << "cwSidetone() finished";
this->stop();
output->stop();
}
void cwSidetone::init()
{
format.setSampleRate(44100);
format.setChannelCount(1);
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
format.setCodec("audio/pcm");
format.setSampleSize(16);
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo device(QAudioDeviceInfo::defaultOutputDevice());
#else
format.setSampleFormat(QAudioFormat::Int16);
QAudioDevice device = QMediaDevices::defaultAudioOutput();
#endif
if (!device.isNull()) {
if (!device.isFormatSupported(format)) {
qWarning(logCW()) << "Default format not supported, using preferred";
format = device.preferredFormat();
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
output.reset(new QAudioOutput(device,format));
#else
output.reset(new QAudioSink(device,format));
#endif
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 size: %3 type: %4)")
.arg(device.deviceName()).arg(volume).arg(format.sampleRate()).arg(format.sampleSize()).arg(format.sampleType());
#else
qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 type: %3")
.arg(device.description()).arg(volume).arg(format.sampleRate()).arg(format.sampleFormat());
#endif
}
this->start(); // Start QIODevice
}
void cwSidetone::send(QString text)
{
text=text.simplified();
for (int pos=0; pos < text.size(); pos++)
{
QChar ch = text.at(pos).toUpper();
QString currentChar;
if (ch == NULL)
{
currentChar = cwTable[' '];
}
else if (this->cwTable.contains(ch))
{
currentChar = cwTable[ch];
}
else
{
currentChar=cwTable['?'];
}
generateMorse(currentChar);
}
if (output->state() == QAudio::StoppedState)
{
output->start(this);
}
else if (output->state() == QAudio::IdleState) {
output->suspend();
output->resume();
}
return;
}
void cwSidetone::start()
{
open(QIODevice::ReadOnly);
}
void cwSidetone::stop()
{
close();
}
qint64 cwSidetone::readData(char *data, qint64 len)
{
QMutexLocker locker(&mutex);
const qint64 total = qMin(((qint64)buffer.size()), len);
memcpy(data, buffer.constData(), total);
buffer.remove(0,total);
if (buffer.size() == 0) {
emit finished();
}
return total;
}
qint64 cwSidetone::writeData(const char *data, qint64 len)
{
Q_UNUSED(data);
Q_UNUSED(len);
return 0;
}
qint64 cwSidetone::bytesAvailable() const
{
return buffer.size() + QIODevice::bytesAvailable();
}
void cwSidetone::generateMorse(QString morse)
{
int dit = int(double(SIDETONE_MULTIPLIER / this->speed * SIDETONE_MULTIPLIER));
int dah = int(double(dit * this->ratio));
QMutexLocker locker(&mutex);
for (int i=0;i<morse.size();i++)
{
QChar c = morse.at(i);
if (c == '-')
{
buffer.append(generateData(dah,this->frequency));
}
else if (c == '.')
{
buffer.append(generateData(dit,this->frequency));
}
else // Space char
{
buffer.append(generateData(dit,0));
}
if (i<morse.size()-1)
{
buffer.append(generateData(dit,0));
}
else
{
buffer.append(generateData(dit*3,0)); // inter-character space
}
}
return;
}
QByteArray cwSidetone::generateData(qint64 len, qint64 freq)
{
QByteArray data;
const int channels = format.channelCount();
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
const int channelBytes = format.sampleSize() / 8;
#else
const int channelBytes = format.bytesPerSample();
#endif
const int sampleRate = format.sampleRate();
//qint64 length = (sampleRate * channels * channelBytes) * len / 100000;
qint64 length = format.bytesForDuration(len);
const int sampleBytes = channels * channelBytes;
length -= length % sampleBytes;
Q_UNUSED(sampleBytes) // suppress warning in release builds
data.resize(length);
unsigned char *ptr = reinterpret_cast<unsigned char *>(data.data());
int sampleIndex = 0;
while (length) {
const qreal x = (qSin(2 * M_PI * freq * qreal(sampleIndex % sampleRate) / sampleRate)) * qreal(volume/100.0);
for (int i=0; i<channels; ++i) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt)
*reinterpret_cast<quint8 *>(ptr) = static_cast<quint8>((1.0 + x) / 2 * 255);
else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt)
*reinterpret_cast<qint16 *>(ptr) = static_cast<qint16>(x * std::numeric_limits<qint16>::max());
else if (format.sampleSize() == 32 && format.sampleType() == QAudioFormat::SignedInt)
*reinterpret_cast<qint32 *>(ptr) = static_cast<qint32>(x * std::numeric_limits<qint32>::max());
else if (format.sampleType() == QAudioFormat::Float)
*reinterpret_cast<float *>(ptr) = x;
else
qWarning(logCW()) << QString("Unsupported sample size: %0 type: %1").arg(format.sampleSize()).arg(format.sampleType());
#else
if (format.sampleFormat() == QAudioFormat::UInt8)
*reinterpret_cast<quint8 *>(ptr) = static_cast<quint8>((1.0 + x) / 2 * 255);
else if (format.sampleFormat() == QAudioFormat::Int16)
*reinterpret_cast<qint16 *>(ptr) = static_cast<qint16>(x * std::numeric_limits<qint16>::max());
else if (format.sampleFormat() == QAudioFormat::Int32)
*reinterpret_cast<qint32 *>(ptr) = static_cast<qint32>(x * std::numeric_limits<qint32>::max());
else if (format.sampleFormat() == QAudioFormat::Float)
*reinterpret_cast<float *>(ptr) = x;
else
qWarning(logCW()) << QString("Unsupported sample format: %0").arg(format.sampleFormat());
#endif
ptr += channelBytes;
length -= channelBytes;
}
++sampleIndex;
}
return data;
}
void cwSidetone::setSpeed(unsigned char speed)
{
this->speed = (int)speed;
}
void cwSidetone::setFrequency(unsigned char frequency)
{
this->frequency = round((((600.0 / 255.0) * frequency) + 300) / 5.0) * 5.0;
}
void cwSidetone::setRatio(unsigned char ratio)
{
this->ratio = (double)ratio/10.0;
}
void cwSidetone::setLevel(int level) {
volume = level;
}
void cwSidetone::stopSending() {
QMutexLocker locker(&mutex);
buffer.clear();
emit finished();
}

69
cwsidetone.h 100644
Wyświetl plik

@ -0,0 +1,69 @@
#ifndef CWSIDETONE_H
#define CWSIDETONE_H
#include <QApplication>
#include <QAudioOutput>
#include <QMap>
#include <QScopedPointer>
#include <QtMath>
#include <QMutex>
#include <QMutexLocker>
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
#include <QAudioDeviceInfo>
#include <QAudioOutput>
#else
#include <QAudioDevice>
#include <QAudioSink>
#include <QMediaDevices>
#endif
//#define SIDETONE_MULTIPLIER 386.0
#define SIDETONE_MULTIPLIER 1095.46
class cwSidetone : public QIODevice
{
Q_OBJECT
public:
explicit cwSidetone(int level, int speed, int freq, double ratio, QWidget *parent = 0);
~cwSidetone();
void start();
void stop();
qint64 readData(char *data, qint64 maxlen) override;
qint64 writeData(const char *data, qint64 len) override;
qint64 bytesAvailable() const override;
qint64 size() const override { return buffer.size(); }
signals:
void finished();
public slots:
void send(QString text);
void setSpeed(unsigned char speed);
void setFrequency(unsigned char frequency);
void setRatio(unsigned char ratio);
void setLevel(int level);
void stopSending();
private:
void init();
void generateMorse(QString morse);
QByteArray generateData(qint64 len, qint64 freq);
QByteArray buffer;
QMap< QChar, QString> cwTable;
QWidget* parent;
int volume;
int speed;
int frequency;
double ratio;
QAudioFormat format;
QMutex mutex;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
QScopedPointer<QAudioOutput> output;
#else
QScopedPointer<QAudioSink> output;
#endif
};
#endif // CWSIDETONE_H

107
database.cpp 100644
Wyświetl plik

@ -0,0 +1,107 @@
#ifdef USESQL
#include "database.h"
#include "logcategories.h"
database::database()
{
open();
}
database::~database()
{
}
bool database::open()
{
auto name = "my_db_" + QString::number((quint64)QThread::currentThread(), 16);
if (QSqlDatabase::contains(name))
{
db = QSqlDatabase::database(name);
qu = QSqlQuery(db);
return true;
}
else {
qInfo(logCluster()) << "Creating new connection" << name;
db = QSqlDatabase::addDatabase("QSQLITE", name);
qu = QSqlQuery(db);
}
//QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/" + "wfview.db";
QString path = ":memory:";
qInfo(logCluster()) << "DB Filename" << path;
db.setDatabaseName(path);
if (db.isValid())
{
db.open();
if (check()) {
return true;
}
}
qWarning(logCluster()) << "Database is not valid!";
return false;
}
void database::close()
{
auto name = "my_db_" + QString::number((quint64)QThread::currentThread(), 16);
qInfo(logCluster()) << "Closing database connection:" << name;
db.close();
}
QSqlQuery database::query(QString query)
{
if (!db.isOpen())
{
qWarning(logCluster()) << "Query Database is not open!";
db.open();
}
qu.exec(query);
return qu;
}
bool database::check()
{
if (db.isOpen()) {
for (const auto& table : db.tables())
{
if (table == "spots")
{
qInfo(logCluster()) << "DB Contains spots table";
return true;
}
}
qInfo(logCluster()) << "Creating spots table";
// Spots table does not exist, need to create it.
/*
QString dxcall;
double frequency;
QString spottercall;
QDateTime timestamp;
QString mode;
QString comment;
QCPItemText* text = Q_NULLPTR;*/
qu.exec("CREATE TABLE spots "
"(id INTEGER PRIMARY KEY, "
"type VARCHAR(3),"
"dxcall VARCHAR(30),"
"spottercall VARCHAR(30),"
"frequency DOUBLE,"
"timestamp DATETIME,"
"mode VARCHAR(30),"
"comment VARCHAR(255) )");
qu.exec("CREATE INDEX spots_index ON spots(type,dxcall,frequency,timestamp)");
return true;
}
else {
qWarning(logCluster()) << "Database is not open";
}
return false;
}
#endif

36
database.h 100644
Wyświetl plik

@ -0,0 +1,36 @@
#ifdef USESQL
#ifndef DATABASE_H
#define DATABASE_H
#include <QObject>
#include <QDebug>
#include <QDateTime>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QThread>
#include <QStandardPaths>
class database
{
public:
explicit database();
virtual ~database();
bool open();
void close();
QSqlQuery query(QString query);
signals:
public slots:
private:
bool check();
QSqlDatabase db;
QSqlQuery qu;
};
#endif
#endif

Wyświetl plik

@ -1,7 +1,7 @@
#include "freqmemory.h"
#include "logcategories.h"
// Copytight 2017-2020 Elliott H. Liggett
// Copyright 2017-2020 Elliott H. Liggett
freqMemory::freqMemory()
{

Wyświetl plik

@ -2,44 +2,7 @@
#define FREQMEMORY_H
#include <QString>
#include <QDebug>
// 0 1 2 3 4
//modes << "LSB" << "USB" << "AM" << "CW" << "RTTY";
// 5 6 7 8 9
// modes << "FM" << "CW-R" << "RTTY-R" << "LSB-D" << "USB-D";
enum mode_kind {
modeLSB=0x00,
modeUSB=0x01,
modeAM=0x02,
modeCW=0x03,
modeRTTY=0x04,
modeFM=0x05,
modeCW_R=0x07,
modeRTTY_R=0x08,
modeLSB_D=0x80,
modeUSB_D=0x81,
modeDV=0x17,
modeDD=0x27,
modeWFM,
modeS_AMD,
modeS_AML,
modeS_AMU,
modeP25,
modedPMR,
modeNXDN_VN,
modeNXDN_N,
modeDCR,
modePSK,
modePSK_R
};
struct mode_info {
mode_kind mk;
unsigned char reg;
unsigned char filter;
QString name;
};
#include "wfviewtypes.h"
struct preset_kind {
// QString name;

26
keyboard.cpp 100644
Wyświetl plik

@ -0,0 +1,26 @@
#include <QCoreApplication>
#include <QObject>
#include <QThread>
#include <QFile>
#include <QTextStream>
#include "keyboard.h"
keyboard::keyboard(void)
{
}
keyboard::~keyboard(void)
{
}
void keyboard::run()
{
while (true)
{
char key = getchar();
if (key == 'q') {
QCoreApplication::quit();
}
}
return;
}

11
keyboard.h 100644
Wyświetl plik

@ -0,0 +1,11 @@
#include <QCoreApplication>
#include <QObject>
#include <QThread>
class keyboard : public QThread
{
Q_OBJECT
public:
keyboard(void);
~keyboard(void);
void run();
};

Wyświetl plik

@ -3,8 +3,16 @@
Q_LOGGING_CATEGORY(logSystem, "system")
Q_LOGGING_CATEGORY(logSerial, "serial")
Q_LOGGING_CATEGORY(logGui, "gui")
Q_LOGGING_CATEGORY(logLogger, "log")
Q_LOGGING_CATEGORY(logUser, "user")
Q_LOGGING_CATEGORY(logRig, "rig")
Q_LOGGING_CATEGORY(logRigTraffic, "rigTraffic")
Q_LOGGING_CATEGORY(logCW, "cw")
Q_LOGGING_CATEGORY(logAudio, "audio")
Q_LOGGING_CATEGORY(logUdp, "udp")
Q_LOGGING_CATEGORY(logUdpServer, "udp.server")
Q_LOGGING_CATEGORY(logRigCtlD, "rigctld")
Q_LOGGING_CATEGORY(logTcpServer, "tcpserver")
Q_LOGGING_CATEGORY(logUsbControl, "usbcontrol")
Q_LOGGING_CATEGORY(logAudioConverter, "audioconverter")
Q_LOGGING_CATEGORY(logCluster, "cluster")

Wyświetl plik

@ -6,15 +6,28 @@
Q_DECLARE_LOGGING_CATEGORY(logSystem)
Q_DECLARE_LOGGING_CATEGORY(logSerial)
Q_DECLARE_LOGGING_CATEGORY(logGui)
Q_DECLARE_LOGGING_CATEGORY(logLogger)
Q_DECLARE_LOGGING_CATEGORY(logUser)
Q_DECLARE_LOGGING_CATEGORY(logRig)
Q_DECLARE_LOGGING_CATEGORY(logRigTraffic)
Q_DECLARE_LOGGING_CATEGORY(logCW)
Q_DECLARE_LOGGING_CATEGORY(logAudio)
Q_DECLARE_LOGGING_CATEGORY(logUdp)
Q_DECLARE_LOGGING_CATEGORY(logUdpServer)
Q_DECLARE_LOGGING_CATEGORY(logRigCtlD)
Q_DECLARE_LOGGING_CATEGORY(logTcpServer)
Q_DECLARE_LOGGING_CATEGORY(logUsbControl)
Q_DECLARE_LOGGING_CATEGORY(logAudioConverter)
Q_DECLARE_LOGGING_CATEGORY(logCluster)
#if defined(Q_OS_WIN) && !defined(__PRETTY_FUNCTION__)
#define __PRETTY_FUNCTION__ __FUNCSIG__
#endif
#if QT_VERSION > 0x060000
//#define hex Qt::hex
//#define bin Qt::bin
#endif
#endif // LOGCATEGORIES_H

214
loggingwindow.cpp 100644
Wyświetl plik

@ -0,0 +1,214 @@
#include "loggingwindow.h"
#include "ui_loggingwindow.h"
loggingWindow::loggingWindow(QString logFilename, QWidget *parent) :
QWidget(parent),
ui(new Ui::loggingWindow),
logFilename(logFilename)
{
ui->setupUi(this);
this->setWindowTitle("Log");
ui->logTextDisplay->setReadOnly(true);
ui->userAnnotationText->setFocus();
ui->annotateBtn->setDefault(true);
ui->logTextDisplay->setFocusPolicy(Qt::NoFocus);
ui->annotateBtn->setFocusPolicy(Qt::NoFocus);
QDir d = QFileInfo(logFilename).absoluteDir();
logDirectory = d.absolutePath();
QFont font("Monospace");
font.setStyleHint(QFont::TypeWriter);
ui->logTextDisplay->setFont(font);
ui->userAnnotationText->setFont(font);
clipboard = QApplication::clipboard();
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()), this, SLOT(connectedToHost()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnectedFromHost()));
connect(socket, SIGNAL(readyRead()), this, SLOT(handleDataFromLoggingHost()));
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(handleLoggingHostError(QAbstractSocket::SocketError)));
#else
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(handleLoggingHostError(QAbstractSocket::SocketError)));
#endif
vertLogScroll = ui->logTextDisplay->verticalScrollBar();
horizLogScroll = ui->logTextDisplay->horizontalScrollBar();
vertLogScroll->setValue(vertLogScroll->maximum());
horizLogScroll->setValue(horizLogScroll->minimum());
}
loggingWindow::~loggingWindow()
{
QMutexLocker lock(&textMutex);
delete ui;
}
void loggingWindow::showEvent(QShowEvent *event)
{
(void)event;
on_toBottomBtn_clicked();
}
void loggingWindow::setInitialDebugState(bool debugModeEnabled)
{
ui->debugBtn->blockSignals(true);
ui->debugBtn->setChecked(debugModeEnabled);
ui->debugBtn->blockSignals(false);
}
void loggingWindow::acceptLogText(QString text)
{
QMutexLocker lock(&textMutex);
ui->logTextDisplay->appendPlainText(text);
if(vertLogScroll->value() == vertLogScroll->maximum())
{
horizLogScroll->setValue(horizLogScroll->minimum());
}
}
void loggingWindow::sendToTermbin()
{
qInfo(logLogger()) << "Sending data to termbin.com. Standby.";
socket->connectToHost("termbin.com", 9999);
ui->sendToPasteBtn->setDisabled(true);
}
void loggingWindow::handleDataFromLoggingHost()
{
qInfo(logLogger()) << "Receiving data from logging host.";
QString URL;
QByteArray data = socket->readAll();
if(data.length() < 256)
{
URL = QString(data).trimmed();
if(!URL.isEmpty())
{
clipboard->setText(URL);
qInfo(logLogger()) << "Sent log to URL: " << URL;
qInfo(logLogger()) << "This address already copied to the clipboard. Please paste this URL in to your support questions.";
URLmsgBox.setText("Your log has been posted, and the URL has been copied to the clipboard.");
URLmsgBox.setInformativeText("<b>" + URL + "</b>");
URLmsgBox.exec();
// For whatever reason, showing the message box hides https://termbin.com/ypxbthis window.
this->show();
this->raise();
this->activateWindow();
}
} else {
qDebug(logLogger()) << "Error, return from logging host too large. Received " << data.length() << " bytes.";
}
}
void loggingWindow::disconnectedFromHost()
{
qInfo(logLogger()) << "Disconnected from logging host";
ui->sendToPasteBtn->setDisabled(false);
}
void loggingWindow::connectedToHost()
{
qInfo(logLogger()) << "Connected to logging host";
QMutexLocker lock(&textMutex);
QTextStream outText(socket);
outText << ui->logTextDisplay->toPlainText();
outText << "\n----------\nSent from wfview version ";
outText << WFVIEW_VERSION << "\n----------\n";
outText.flush();
}
void loggingWindow::handleLoggingHostError(QAbstractSocket::SocketError error)
{
switch(error)
{
case QAbstractSocket::RemoteHostClosedError:
//qInfo(logLogger()) << "Disconnected from logging host.";
break;
default:
qWarning(logLogger()) << "Error connecting to logging host. Check internet connection. Error code: " << error;
ui->sendToPasteBtn->setDisabled(false);
break;
}
}
void loggingWindow::on_clearDisplayBtn_clicked()
{
QMutexLocker lock(&textMutex);
// Only clears the displayed text, not the log file.
ui->logTextDisplay->clear();
}
void loggingWindow::on_openDirBtn_clicked()
{
QString cmd;
bool rtn = false;
QStringList arg;
const QFileInfo dir(logDirectory);
#ifdef Q_OS_LINUX
cmd = "xdg-open";
#elif defined(Q_OS_WIN)
cmd = QStandardPaths::findExecutable("explorer.exe");
if (!dir.isDir())
arg += QLatin1String("/select,");
#else
cmd = "open";
#endif
arg += QDir::toNativeSeparators(dir.canonicalFilePath());;
rtn = QProcess::startDetached(cmd, arg);
if(!rtn)
qInfo(logLogger()) << "Error, open log directory" << logDirectory << "command failed";
}
void loggingWindow::on_openLogFileBtn_clicked()
{
QString cmd;
bool rtn = false;
#ifdef Q_OS_LINUX
cmd = "xdg-open";
#elif defined(Q_OS_WIN)
cmd = QStandardPaths::findExecutable("notepad.exe");
#else
cmd = "open";
#endif
rtn = QProcess::startDetached(cmd, { logFilename });
if(!rtn)
qInfo(logLogger()) << "Error, open log file command failed";
}
void loggingWindow::on_sendToPasteBtn_clicked()
{
sendToTermbin();
}
void loggingWindow::on_annotateBtn_clicked()
{
QMutexLocker lock(&textMutex);
if(ui->userAnnotationText->text().isEmpty())
return;
qInfo(logUser()) << ui->userAnnotationText->text();
ui->userAnnotationText->clear();
}
void loggingWindow::on_userAnnotationText_returnPressed()
{
on_annotateBtn_clicked();
}
void loggingWindow::on_copyPathBtn_clicked()
{
clipboard->setText(logFilename);
}
void loggingWindow::on_debugBtn_clicked(bool checked)
{
emit setDebugMode(checked);
}
void loggingWindow::on_toBottomBtn_clicked()
{
vertLogScroll->setValue(vertLogScroll->maximum());
horizLogScroll->setValue(horizLogScroll->minimum());
}

75
loggingwindow.h 100644
Wyświetl plik

@ -0,0 +1,75 @@
#ifndef LOGGINGWINDOW_H
#define LOGGINGWINDOW_H
#include <QWidget>
#include <QMutexLocker>
#include <QMutex>
#include <QStandardPaths>
#include <QClipboard>
#include <QTcpSocket>
#include <QTextStream>
#include <QMessageBox>
#include <QScrollBar>
#include <QProcess>
#include <QFileInfo>
#include <QDir>
#include "logcategories.h"
namespace Ui {
class loggingWindow;
}
class loggingWindow : public QWidget
{
Q_OBJECT
public:
explicit loggingWindow(QString logFilename, QWidget *parent = 0);
~loggingWindow();
void acceptLogText(QString text);
public slots:
void setInitialDebugState(bool debugModeEnabled);
private slots:
void connectedToHost();
void disconnectedFromHost();
void handleDataFromLoggingHost();
void handleLoggingHostError(QAbstractSocket::SocketError);
void showEvent(QShowEvent* event);
void on_clearDisplayBtn_clicked();
void on_openDirBtn_clicked();
void on_openLogFileBtn_clicked();
void on_sendToPasteBtn_clicked();
void on_annotateBtn_clicked();
void on_userAnnotationText_returnPressed();
void on_copyPathBtn_clicked();
void on_debugBtn_clicked(bool checked);
void on_toBottomBtn_clicked();
signals:
void setDebugMode(bool debugOn);
private:
Ui::loggingWindow* ui;
QString logFilename;
QString logDirectory;
QClipboard *clipboard;
QMessageBox URLmsgBox;
QScrollBar *vertLogScroll;
QScrollBar *horizLogScroll;
QMutex textMutex;
QTcpSocket *socket;
void sendToTermbin();
};
#endif // LOGGINGWINDOW_H

191
loggingwindow.ui 100644
Wyświetl plik

@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>loggingWindow</class>
<widget class="QWidget" name="loggingWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>625</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="logTextDisplay">
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="annotateLabel">
<property name="minimumSize">
<size>
<width>75</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Annotation:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="userAnnotationText">
<property name="minimumSize">
<size>
<width>290</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>You may enter your own log notes here.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="annotateBtn">
<property name="minimumSize">
<size>
<width>85</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>85</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Adds user-text to the log.</string>
</property>
<property name="text">
<string>Annotate</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="debugBtn">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable debug logging. Use the &amp;quot;-d&amp;quot; or &amp;quot;--debug&amp;quot; flag to open wfview with debug logging enabled on startup. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Debug</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toBottomBtn">
<property name="toolTip">
<string>Scroll to bottom</string>
</property>
<property name="text">
<string>Scroll Down</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearDisplayBtn">
<property name="toolTip">
<string>Clears the display. Does not clear the log file.</string>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="openDirBtn">
<property name="toolTip">
<string>Makes a best-effort to ask the host system to open the log file directory.</string>
</property>
<property name="text">
<string>Open Log Directory</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="openLogFileBtn">
<property name="toolTip">
<string>Makes a best-effort to ask the host system to open the logfile.</string>
</property>
<property name="text">
<string>Open Log</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="copyPathBtn">
<property name="toolTip">
<string>Copy the path of the log file to your clipboard.</string>
</property>
<property name="text">
<string>Copy Path</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="sendToPasteBtn">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sends text to termbin.com. Some personal information (such as your username) is in the log file, so do not click this button unless you are ok sharing your log file. This is a quick way to receive a URL, pointing to your log file text, that you can send to other people. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Send to termbin.com</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

162
main.cpp
Wyświetl plik

@ -1,77 +1,107 @@
#ifdef BUILD_WFSERVER
#include <QtCore/QCoreApplication>
#include "keyboard.h"
#else
#include <QApplication>
#endif
#ifdef Q_OS_WIN
#include <windows.h>
#include <csignal>
#endif
#include <iostream>
#include "wfmain.h"
// Copyright 2017-2022 Elliott H. Liggett
#include "logcategories.h"
// Copytight 2017-2021 Elliott H. Liggett
#ifdef BUILD_WFSERVER
// Smart pointer to log file
QScopedPointer<QFile> m_logFile;
QMutex logMutex;
#endif
bool debugMode=false;
#ifdef BUILD_WFSERVER
servermain* w=Q_NULLPTR;
#ifdef Q_OS_WIN
bool __stdcall cleanup(DWORD sig)
#else
static void cleanup(int sig)
#endif
{
Q_UNUSED(sig)
qDebug() << "Exiting via SIGNAL";
if (w!=Q_NULLPTR) w->deleteLater();
QCoreApplication::quit();
#ifdef Q_OS_WIN
return true;
#else
return;
#endif
}
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
#endif
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//a.setStyle( "Fusion" );
#ifdef BUILD_WFSERVER
QCoreApplication a(argc, argv);
a.setOrganizationName("wfview");
a.setOrganizationDomain("wfview.org");
a.setApplicationName("wfserver");
keyboard* kb = new keyboard();
kb->start();
#else
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication a(argc, argv);
a.setOrganizationName("wfview");
a.setOrganizationDomain("wfview.org");
a.setApplicationName("wfview");
#endif
#ifdef QT_DEBUG
debugMode = true;
//debugMode = true;
#endif
QString serialPortCL;
QString hostCL;
QString civCL;
#ifdef Q_OS_MAC
QString logFilename= QStandardPaths::standardLocations(QStandardPaths::DownloadLocation)[0] + "/wfview.log";
#else
QString logFilename= QStandardPaths::standardLocations(QStandardPaths::TempLocation)[0] + "/wfview.log";
#endif
QDateTime date = QDateTime::currentDateTime();
QString formattedTime = date.toString("dd.MM.yyyy hh:mm:ss");
QString logFilename = (QString("%1/%2-%3.log").arg(QStandardPaths::standardLocations(QStandardPaths::TempLocation)[0]).arg(a.applicationName()).arg(date.toString("yyyyMMddhhmmss")));
QString settingsFile = NULL;
QString currentArg;
const QString helpText = QString("\nUsage: -p --port /dev/port, -h --host remotehostname, -c --civ 0xAddr, -l --logfile filename.log, -s --settings filename.ini, -d --debug\n"); // TODO...
const QString helpText = QString("\nUsage: -l --logfile filename.log, -s --settings filename.ini, -d --debug, -v --version\n"); // TODO...
#ifdef BUILD_WFSERVER
const QString version = QString("wfserver version: %1 (Git:%2 on %3 at %4 by %5@%6)\nOperating System: %7 (%8)\nBuild Qt Version %9. Current Qt Version: %10\n")
.arg(QString(WFVIEW_VERSION))
.arg(GITSHORT).arg(__DATE__).arg(__TIME__).arg(UNAME).arg(HOST)
.arg(QSysInfo::prettyProductName()).arg(QSysInfo::buildCpuArchitecture())
.arg(QT_VERSION_STR).arg(qVersion());
#else
const QString version = QString("wfview version: %1 (Git:%2 on %3 at %4 by %5@%6)\nOperating System: %7 (%8)\nBuild Qt Version %9. Current Qt Version: %10\n")
.arg(QString(WFVIEW_VERSION))
.arg(GITSHORT).arg(__DATE__).arg(__TIME__).arg(UNAME).arg(HOST)
.arg(QSysInfo::prettyProductName()).arg(QSysInfo::buildCpuArchitecture())
.arg(QT_VERSION_STR).arg(qVersion());
#endif
for(int c=1; c<argc; c++)
{
//qInfo() << "Argc: " << c << " argument: " << argv[c];
currentArg = QString(argv[c]);
if ((currentArg == "-p") || (currentArg == "--port"))
{
if (argc > c)
{
serialPortCL = argv[c + 1];
c += 1;
}
}
else if ((currentArg == "-d") || (currentArg == "--debug"))
if ((currentArg == "-d") || (currentArg == "--debug"))
{
debugMode = true;
}
else if ((currentArg == "-h") || (currentArg == "--host"))
{
if(argc > c)
{
hostCL = argv[c+1];
c+=1;
}
}
else if ((currentArg == "-c") || (currentArg == "--civ"))
{
if (argc > c)
{
civCL = argv[c + 1];
c += 1;
}
}
else if ((currentArg == "-l") || (currentArg == "--logfile"))
{
if (argc > c)
@ -88,28 +118,25 @@ int main(int argc, char *argv[])
c += 1;
}
}
else if ((currentArg == "--help"))
else if ((currentArg == "-?") || (currentArg == "--help"))
{
#ifdef Q_OS_WIN
QMessageBox::information(0, "wfview help", helpText);
#else
std::cout << helpText.toStdString();
#endif
return 0;
}
else if ((currentArg == "-v") || (currentArg == "--version"))
{
std::cout << version.toStdString();
return 0;
} else {
#ifdef Q_OS_WIN
QMessageBox::information(0, "wfview unrecognised argument", helpText);
#else
std::cout << "Unrecognized option: " << currentArg.toStdString();
std::cout << helpText.toStdString();
#endif
return -1;
return -1;
}
}
#ifdef BUILD_WFSERVER
// Set the logging file before doing anything else.
m_logFile.reset(new QFile(logFilename));
// Open the file logging
@ -117,23 +144,29 @@ int main(int argc, char *argv[])
// Set handler
qInstallMessageHandler(messageHandler);
qInfo(logSystem()) << QString("Starting wfview: build %1 on %2 at %3 by %5@%6").arg(GITSHORT).arg(__DATE__).arg(__TIME__).arg(UNAME).arg(HOST);
qInfo(logSystem()) << QString("Operating System: %1 (%2)").arg(QSysInfo::prettyProductName()).arg(QSysInfo::buildCpuArchitecture());
qInfo(logSystem()) << QString("Build Qt Version %1. Current Qt Version: %2").arg(QT_VERSION_STR).arg(qVersion());
qDebug(logSystem()) << QString("SerialPortCL as set by parser: %1").arg(serialPortCL);
qDebug(logSystem()) << QString("remote host as set by parser: %1").arg(hostCL);
qDebug(logSystem()) << QString("CIV as set by parser: %1").arg(civCL);
qInfo(logSystem()) << version;
#endif
#ifdef BUILD_WFSERVER
#ifdef Q_OS_WIN
SetConsoleCtrlHandler((PHANDLER_ROUTINE)cleanup, TRUE);
#else
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
signal(SIGKILL, cleanup);
#endif
w = new servermain(settingsFile);
#else
a.setWheelScrollLines(1); // one line per wheel click
wfmain w( serialPortCL, hostCL, settingsFile);
wfmain w(settingsFile, logFilename, debugMode);
w.show();
#endif
return a.exec();
}
#ifdef BUILD_WFSERVER
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
@ -144,6 +177,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
}
QMutexLocker locker(&logMutex);
QTextStream out(m_logFile.data());
QString text;
// Write the date of recording
out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz ");
@ -169,5 +203,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
}
// Write to the output category of the message and the message itself
out << context.category << ": " << msg << "\n";
std::cout << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz ").toLocal8Bit().toStdString() << msg.toLocal8Bit().toStdString() << "\n";
out.flush(); // Clear the buffered data
}
#endif

662
meter.cpp
Wyświetl plik

@ -23,6 +23,15 @@ meter::meter(QWidget *parent) : QWidget(parent)
//
// Text in qdarkstylesheet seems to be #EFF0F1
if(drawLabels)
{
mXstart = 32;
} else {
mXstart = 0;
}
meterType = meterS;
currentColor.setNamedColor("#148CD2");
currentColor = currentColor.darker();
@ -34,42 +43,297 @@ meter::meter(QWidget *parent) : QWidget(parent)
lowTextColor.setNamedColor("#eff0f1");
lowLineColor = lowTextColor;
avgLevels.resize(averageBalisticLength, 0);
peakLevels.resize(peakBalisticLength, 0);
}
void meter::setColors(QColor current, QColor peakScale, QColor peakLevel,
QColor average, QColor lowLine,
QColor lowText)
{
currentColor = current;
peakColor = peakLevel; // color for the peak level indicator
highLineColor = peakScale; // color for the red side of the scale
highTextColor = peakScale; // color for the red side of the scale's text
averageColor = average;
midScaleColor = QColor(Qt::yellow);
centerTuningColor = QColor(Qt::green);
lowLineColor = lowLine;
lowTextColor = lowText;
this->update();
}
void meter::clearMeterOnPTTtoggle()
{
// When a meter changes type, such as the fixed S -- TxPo meter,
// there is automatic clearing. However, some meters do not switch on their own,
// and thus we are providing this clearing method. We are careful
// not to clear meters that don't make sense to clear (such as Vd and Id)
if( (meterType == meterALC) || (meterType == meterSWR)
|| (meterType == meterComp) || (meterType == meterTxMod)
|| (meterType == meterCenter ))
{
clearMeter();
}
}
void meter::clearMeter()
{
current = 0;
average = 0;
peak = 0;
avgLevels.clear();
peakLevels.clear();
avgLevels.resize(averageBalisticLength, 0);
peakLevels.resize(peakBalisticLength, 0);
peakPosition = 0;
avgPosition = 0;
// re-draw scale:
update();
}
void meter::setMeterType(meterKind type)
{
if(type == meterType)
return;
meterType = type;
// clear average and peak vectors:
this->clearMeter();
}
meterKind meter::getMeterType()
{
return meterType;
}
void meter::setMeterShortString(QString s)
{
meterShortString = s;
}
QString meter::getMeterShortString()
{
return meterShortString;
}
void meter::paintEvent(QPaintEvent *)
{
QPainter painter(this);
// This next line sets up a canvis within the
// space of the widget, and gives it corrdinates.
// space of the widget, and gives it coordinates.
// The end effect, is that the drawing functions will all
// scale to the window size.
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setFont(QFont(this->fontInfo().family(), fontSize));
widgetWindowHeight = this->height();
painter.setWindow(QRect(0, 0, 255+mXstart+15, widgetWindowHeight));
barHeight = widgetWindowHeight / 2;
painter.setWindow(QRect(0, 0, 255+mstart, 50));
drawScale(&painter);
// Current:
painter.setPen(currentColor);
painter.setBrush(currentColor);
painter.drawRect(mstart,mheight,current,mstart);
// Average:
painter.setPen(averageColor);
painter.setBrush(averageColor);
painter.drawRect(mstart+average-1,mheight,1,mstart);
// Peak:
painter.setPen(peakColor);
painter.setBrush(peakColor);
if(peak > 120)
switch(meterType)
{
// 120 = +S9
painter.setBrush(Qt::red);
painter.setPen(Qt::red);
case meterS:
label = "S";
peakRedLevel = 120; // S9+
drawScaleS(&painter);
break;
case meterPower:
label = "PWR";
peakRedLevel = 210; // 100%
drawScalePo(&painter);
break;
case meterALC:
label = "ALC";
peakRedLevel = 100;
drawScaleALC(&painter);
break;
case meterSWR:
label = "SWR";
peakRedLevel = 100; // SWR 2.5
drawScaleSWR(&painter);
break;
case meterCenter:
label = "CTR";
peakRedLevel = 256; // No need for red here
drawScaleCenter(&painter);
break;
case meterVoltage:
label = "Vd";
peakRedLevel = 241;
drawScaleVd(&painter);
break;
case meterCurrent:
label = "Id";
peakRedLevel = 120;
drawScaleId(&painter);
break;
case meterComp:
label = "CMP(dB)";
peakRedLevel = 100;
drawScaleComp(&painter);
break;
case meterNone:
return;
break;
case meterAudio:
label = "dBfs";
peakRedLevel = 241;
drawScale_dBFs(&painter);
break;
case meterRxAudio:
label = "Rx(dBfs)";
peakRedLevel = 241;
drawScale_dBFs(&painter);
break;
case meterTxMod:
label = "Tx(dBfs)";
peakRedLevel = 241;
drawScale_dBFs(&painter);
break;
default:
label = "DN";
peakRedLevel = 241;
drawScaleRaw(&painter);
break;
}
painter.drawRect(mstart+peak-1,mheight,2,mstart);
// Current: the most-current value.
// Draws a bar from start to value.
painter.setPen(currentColor);
painter.setBrush(currentColor);
if(meterType == meterCenter)
{
painter.drawRect(mXstart+128,mYstart,current-128,barHeight);
// Average:
painter.setPen(averageColor);
painter.setBrush(averageColor);
painter.drawRect(mXstart+average-1,mYstart,1,barHeight); // bar is 1 pixel wide, height = meter start?
// Peak:
painter.setPen(peakColor);
painter.setBrush(peakColor);
if((peak > 191) || (peak < 63))
{
painter.setBrush(Qt::red);
painter.setPen(Qt::red);
}
painter.drawRect(mXstart+peak-1,mYstart,1,barHeight);
} else if ( (meterType == meterAudio) ||
(meterType == meterTxMod) ||
(meterType == meterRxAudio))
{
// Log scale but still 0-255:
int logCurrent = (int)((1-audiopot[255-current])*255);
int logAverage = (int)((1-audiopot[255-average])*255);
int logPeak = (int)((1-audiopot[255-peak])*255);
// X, Y, Width, Height
painter.drawRect(mXstart,mYstart,logCurrent,barHeight);
// Average:
painter.setPen(averageColor);
painter.setBrush(averageColor);
painter.drawRect(mXstart+logAverage-1,mYstart,1,barHeight); // bar is 1 pixel wide, height = meter start?
// Peak:
painter.setPen(peakColor);
painter.setBrush(peakColor);
if(peak > peakRedLevel)
{
painter.setBrush(Qt::red);
painter.setPen(Qt::red);
}
painter.drawRect(mXstart+logPeak-1,mYstart,2,barHeight);
} else {
// X, Y, Width, Height
painter.drawRect(mXstart,mYstart,current,barHeight);
// Average:
painter.setPen(averageColor);
painter.setBrush(averageColor);
painter.drawRect(mXstart+average-1,mYstart,1,barHeight); // bar is 1 pixel wide, height = meter start?
// Peak:
painter.setPen(peakColor);
painter.setBrush(peakColor);
if(peak > peakRedLevel)
{
painter.setBrush(Qt::red);
painter.setPen(Qt::red);
}
painter.drawRect(mXstart+peak-1,mYstart,2,barHeight);
}
if(drawLabels)
{
drawLabel(&painter);
}
}
void meter::drawLabel(QPainter *qp)
{
qp->setPen(lowTextColor);
qp->drawText(0,scaleTextYstart, label );
}
void meter::setLevel(int current)
{
this->current = current;
avgLevels[(avgPosition++)%averageBalisticLength] = current;
peakLevels[(peakPosition++)%peakBalisticLength] = current;
int sum=0;
for(unsigned int i=0; i < (unsigned int)std::min(avgPosition, (int)avgLevels.size()); i++)
{
sum += avgLevels.at(i);
}
this->average = sum / std::min(avgPosition, (int)avgLevels.size());
this->peak = 0;
for(unsigned int i=0; i < peakLevels.size(); i++)
{
if( peakLevels.at(i) > this->peak)
this->peak = peakLevels.at(i);
}
this->update();
}
void meter::setLevels(int current, int peak)
{
this->current = current;
this->peak = peak;
avgLevels[(avgPosition++)%averageBalisticLength] = current;
int sum=0;
for(unsigned int i=0; i < (unsigned int)std::min(avgPosition, (int)avgLevels.size()); i++)
{
sum += avgLevels.at(i);
}
this->average = sum / std::min(avgPosition, (int)avgLevels.size());
this->update();
}
void meter::setLevels(int current, int peak, int average)
@ -77,6 +341,7 @@ void meter::setLevels(int current, int peak, int average)
this->current = current;
this->peak = peak;
this->average = average;
this->update();
}
@ -86,17 +351,345 @@ void meter::updateDrawing(int num)
length = num;
}
// The drawScale functions draw the numbers and number unerline for each type of meter
void meter::drawScale(QPainter *qp)
void meter::drawScaleRaw(QPainter *qp)
{
qp->setPen(lowTextColor);
qp->setFont(QFont("Arial", fontSize));
int i=mstart;
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
for(; i<mXstart+256; i+=25)
{
qp->drawText(i,scaleTextYstart, QString("%1").arg(i) );
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScale_dBFs(QPainter *qp)
{
qp->setPen(lowTextColor);
peakRedLevel = 193;
if(meterType==meterAudio)
qp->drawText(20+mXstart,scaleTextYstart, QString("-30"));
qp->drawText(38+mXstart+2,scaleTextYstart, QString("-24"));
qp->drawText(71+mXstart,scaleTextYstart, QString("-18"));
qp->drawText(124+mXstart,scaleTextYstart, QString("-12"));
qp->drawText(193+mXstart,scaleTextYstart, QString("-6"));
qp->drawText(255+mXstart,scaleTextYstart, QString("0"));
// Low ticks:
qp->setPen(lowLineColor);
qp->drawLine(20+mXstart,scaleTextYstart, 20+mXstart, scaleTextYstart+5);
qp->drawLine(38+mXstart,scaleTextYstart, 38+mXstart, scaleTextYstart+5);
qp->drawLine(71+mXstart,scaleTextYstart, 71+mXstart, scaleTextYstart+5);
qp->drawLine(124+mXstart,scaleTextYstart, 124+mXstart, scaleTextYstart+5);
// High ticks:
qp->setPen(highLineColor);
qp->drawLine(193+mXstart,scaleTextYstart, 193+mXstart, scaleTextYstart+5);
qp->drawLine(255+mXstart,scaleTextYstart, 255+mXstart, scaleTextYstart+5);
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScaleVd(QPainter *qp)
{
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
// 7300/9700 and others:
int midPointDn = 13;
int midPointVd = 10;
// 705:
//int midPointDn = 75;
//int midPointVd = 5;
int highPointDn = 241;
int highPointVd = 16;
float VdperDn = (float)(highPointVd-midPointVd) / float(highPointDn-midPointDn);
int i=mXstart;
for(; i<mXstart+midPointDn; i+=midPointDn/1)
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int)((i-mXstart) * (float(midPointVd) / float(midPointDn)) )) );
}
for(; i<mXstart+255; i+= (highPointDn-midPointDn) / (highPointVd-midPointVd))
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int) std::round( ((i-mXstart-midPointDn) * (VdperDn) ) + (midPointVd) )));
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScaleCenter(QPainter *qp)
{
// No known units
qp->setPen(lowLineColor);
qp->drawText(60+mXstart,scaleTextYstart, QString("-"));
qp->setPen(centerTuningColor);
// Attempt to draw the zero at the actual center
qp->drawText(128-2+mXstart,scaleTextYstart, QString("0"));
qp->setPen(lowLineColor);
qp->drawText(195+mXstart,scaleTextYstart, QString("+"));
qp->setPen(lowLineColor);
qp->drawLine(mXstart,scaleLineYstart,128-32+mXstart,scaleLineYstart);
qp->setPen(centerTuningColor);
qp->drawLine(128-32+mXstart,scaleLineYstart,128+32+mXstart,scaleLineYstart);
qp->setPen(lowLineColor);
qp->drawLine(128+32+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScalePo(QPainter *qp)
{
//From the manual: "0000=0% to 0143=50% to 0213=100%"
float dnPerWatt = 143.0f / 50.0f;
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
// 13.3 DN per s-unit:
int p=0;
for(; i<mXstart+143; i+=(int)(10*dnPerWatt))
{
// Stop just before the next 10w spot
if(i<mXstart+140)
qp->drawText(i,scaleTextYstart, QString("%1").arg(10*(p++)) );
}
// Modify current scale position:
// Here, P is now 60 watts:
// Higher scale:
//i = i - (int)(10*dnPerWatt); // back one tick first. Otherwise i starts at 178. **Not used?**
//qDebug() << "meter i: " << i;
dnPerWatt = (213-143.0f) / 50.0f; // 1.4 dn per watt
// P=5 here.
qp->setPen(midScaleColor);
int k=0;
for(i=mXstart+143; i<mXstart+213; i+=(5*dnPerWatt))
{
k = 50+(( i-mXstart-143 ) / dnPerWatt);
if(k==40||k==50||k==65||k==80)
qp->drawText(i,scaleTextYstart, QString("%1").arg(k) );
}
// Now we're out past 100:
qp->setPen(highTextColor);
for(i=mXstart+213; i<mXstart+255; i+=(10*dnPerWatt))
{
k = 50+(( i-mXstart-143 ) / dnPerWatt);
if(k==100)
qp->drawText(i,scaleTextYstart, QString("%1").arg(k) );
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,213+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(213+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
(void)qp;
}
void meter::drawScaleRxdB(QPainter *qp)
{
(void)qp;
}
void meter::drawScaleALC(QPainter *qp)
{
// From the manual: 0000=Minimum to 0120=Maximum
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
int alc=0;
for(; i<mXstart+100; i += (20))
{
qp->drawText(i,scaleTextYstart, QString("%1").arg(alc) );
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
alc +=20;
}
qp->setPen(highTextColor);
for(; i<mXstart+120; i+=(int)(10*i))
{
qp->drawText(i,scaleTextYstart, QString("+%1").arg(alc) );
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
alc +=10;
}
qp->setPen(lowLineColor);
qp->drawLine(mXstart,scaleLineYstart,100+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(100+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
(void)qp;
}
void meter::drawScaleComp(QPainter *qp)
{
//
// 0000=0 dB, 0130=15 dB,0241=30 dB
//
qp->setPen(lowTextColor);
int midPointDn = 130;
int midPointdB = 15;
int highPointDn = 241;
int highPointdB = 30;
float dBperDn = (float)(highPointdB-midPointdB) / float(highPointDn-midPointDn);
int i=mXstart;
i+=midPointDn/4; // skip the 0 for cleaner label space
for(; i<mXstart+midPointDn; i+=midPointDn/4)
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int)((i-mXstart) * (float(midPointdB) / float(midPointDn)) )) );
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
}
i = midPointDn+60;
for(; i<mXstart+255; i+= 30)
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int) std::round( ((i-mXstart-midPointDn) * (dBperDn) ) + (midPointdB) )));
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScaleSWR(QPainter *qp)
{
// From the manual:
// 0000=SWR1.0,
// 0048=SWR1.5,
// 0080=SWR2.0,
// 0120=SWR3.0
qp->setPen(lowTextColor);
qp->drawText(mXstart,scaleTextYstart, QString("1.0"));
qp->drawText(24+mXstart,scaleTextYstart, QString("1.3"));
qp->drawText(48+mXstart,scaleTextYstart, QString("1.5"));
qp->drawText(80+mXstart,scaleTextYstart, QString("2.0"));
qp->drawText(100+mXstart,scaleTextYstart, QString("2.5"));
qp->setPen(highTextColor);
qp->drawText(120+mXstart,scaleTextYstart, QString("3.0"));
qp->setPen(lowLineColor);
qp->drawLine( 0+mXstart,scaleTextYstart, 0+mXstart, scaleTextYstart+5);
qp->drawLine( 24+mXstart,scaleTextYstart, 24+mXstart, scaleTextYstart+5);
qp->drawLine( 48+mXstart,scaleTextYstart, 48+mXstart, scaleTextYstart+5);
qp->drawLine( 80+mXstart,scaleTextYstart, 80+mXstart, scaleTextYstart+5);
qp->drawLine(100+mXstart,scaleTextYstart,100+mXstart, scaleTextYstart+5); // does not draw?
qp->setPen(highLineColor);
qp->drawLine(120+mXstart,scaleTextYstart,120+mXstart, scaleTextYstart+5);
qp->setPen(lowLineColor);
qp->drawLine(mXstart,scaleLineYstart,100+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(100+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScaleId(QPainter *qp)
{
// IC-7300:
// 0000=0, 0097=10, 0146=15, 0241=25
//
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
// 7300/9700 and others:
int midPointDn = 97;
int midPointId = 10;
int highPointDn = 146;
int highPointId = 15;
float IdperDn = (float)(highPointId-midPointId) / float(highPointDn-midPointDn);
int i=mXstart;
for(; i<mXstart+midPointDn; i+=midPointDn/4)
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int)((i-mXstart) * (float(midPointId) / float(midPointDn)) )) );
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
}
for(; i<mXstart+255; i+= 4*(highPointDn-midPointDn) / (highPointId-midPointId))
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int) std::round( ((i-mXstart-midPointDn) * (IdperDn) ) + (midPointId) )));
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScaleS(QPainter *qp)
{
//
// 0000=S0, 0120=S9, 0241=S9+60dB
// 120 / 9 = 13.333 steps per S-unit
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
// 13.3 DN per s-unit:
int s=0;
for(; i<mstart+120; i+=13)
for(; i<mXstart+120; i+=13)
{
qp->drawText(i,mstart, QString("%1").arg(s++) );
qp->drawText(i,scaleTextYstart, QString("%1").arg(s++) );
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
}
// 2 DN per 1 dB now:
@ -107,18 +700,17 @@ void meter::drawScale(QPainter *qp)
s = 20;
i+=20;
qp->setPen(Qt::red);
qp->setPen(highTextColor);
for(; i<mstart+255; i+=40)
for(; i<mXstart+255; i+=40)
{
qp->drawText(i,mstart, QString("+%1").arg(s) );
qp->drawText(i,scaleTextYstart, QString("+%1").arg(s) );
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
s = s + 20;
}
qp->setPen(lowLineColor);
qp->drawLine(mstart,12,130,12);
qp->setPen(Qt::red);
qp->drawLine(130,12,255,12);
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(highLineColor);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}

59
meter.h
Wyświetl plik

@ -3,6 +3,13 @@
#include <QWidget>
#include <QPainter>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>
#include "rigcommander.h" // for meter types
#include "audiotaper.h"
class meter : public QWidget
{
@ -17,20 +24,61 @@ public slots:
void updateDrawing(int num);
void setLevels(int current, int peak, int average);
void setLevels(int current, int peak); // calculate avg
void setLevel(int current);
void clearMeterOnPTTtoggle();
void clearMeter();
void setMeterType(meterKind type);
void setMeterShortString(QString);
QString getMeterShortString();
meterKind getMeterType();
void setColors(QColor current, QColor peakScale, QColor peakLevel,
QColor average, QColor lowLine,
QColor lowText);
private:
//QPainter painter;
int fontSize = 5;
meterKind meterType;
QString meterShortString;
int fontSize = 10;
int length=30;
int current=0;
int peak = 0;
int average = 0;
int mstart = 10; // Starting point for S=0.
int mheight = 14; // "thickness" of the meter block rectangle
int averageBalisticLength = 30;
int peakBalisticLength = 30;
int avgPosition=0;
int peakPosition=0;
std::vector<unsigned char> avgLevels;
std::vector<unsigned char> peakLevels;
void drawScale(QPainter *qp);
int peakRedLevel=0;
bool drawLabels = true;
int mXstart = 0; // Starting point for S=0.
int mYstart = 14; // height, down from top, where the drawing starts
int barHeight = 10; // Height of meter "bar" indicators
int scaleLineYstart = 12;
int scaleTextYstart = 10;
int widgetWindowHeight = mYstart + barHeight + 0; // height of drawing canvis.
void drawScaleS(QPainter *qp);
void drawScaleCenter(QPainter *qp);
void drawScalePo(QPainter *qp);
void drawScaleRxdB(QPainter *qp);
void drawScaleALC(QPainter *qp);
void drawScaleSWR(QPainter *qp);
void drawScaleVd(QPainter *qp);
void drawScaleId(QPainter *qp);
void drawScaleComp(QPainter *qp);
void drawScale_dBFs(QPainter *qp);
void drawScaleRaw(QPainter *qp);
void drawLabel(QPainter *qp);
QString label;
QColor currentColor;
QColor averageColor;
@ -42,6 +90,9 @@ private:
QColor highTextColor;
QColor highLineColor;
QColor midScaleColor;
QColor centerTuningColor;
};
#endif // METER_H

@ -1 +0,0 @@
Subproject commit ae5d6d59e82ef40300a4dece7897499685f87184

Wyświetl plik

@ -4,6 +4,22 @@
#pragma pack(push, 1)
// Various settings used by both client and server
#define PURGE_SECONDS 10
#define TOKEN_RENEWAL 60000
#define PING_PERIOD 500
#define IDLE_PERIOD 100
#define AREYOUTHERE_PERIOD 500
#define WATCHDOG_PERIOD 500
#define RETRANSMIT_PERIOD 100 // How often to attempt retransmit
#define LOCK_PERIOD 10 // How long to try to lock mutex (ms)
#define STALE_CONNECTION 15 // Not heard from in this many seconds
#define BUFSIZE 500 // Number of packets to buffer
#define MAX_MISSING 50 // More than this indicates serious network problem
#define AUDIO_PERIOD 20
#define GUIDLEN 16
// Fixed Size Packets
#define CONTROL_SIZE 0x10
#define WATCHDOG_SIZE 0x14
@ -15,13 +31,15 @@
#define LOGIN_RESPONSE_SIZE 0x60
#define LOGIN_SIZE 0x80
#define CONNINFO_SIZE 0x90
#define CAPABILITIES_SIZE 0xA8
#define CAPABILITIES_SIZE 0x42
#define RADIO_CAP_SIZE 0x66
// Variable size packets + payload
#define CIV_SIZE 0x15
#define AUDIO_SIZE 0x18
#define DATA_SIZE 0x15
// 0x10 length control packet (connect/disconnect/idle.)
typedef union control_packet {
struct {
@ -103,6 +121,7 @@ typedef union audio_packet {
quint16 seq; // 0x06
quint32 sentid; // 0x08
quint32 rcvdid; // 0x0c
quint16 ident; // 0x10
quint16 sendseq; // 0x12
quint16 unused; // 0x14
@ -147,19 +166,26 @@ typedef union token_packet {
quint16 seq; // 0x06
quint32 sentid; // 0x08
quint32 rcvdid; // 0x0c
char unuseda[3]; // 0x10
quint16 code; // 0x13
quint16 res; // 0x15
quint8 innerseq; // 0x17
char unusedb; // 0x18
char unusedc; // 0x19
char unuseda[2]; // 0x10
quint16 payloadsize; // 0x12
quint8 requestreply; // 0x13
quint8 requesttype; // 0x14
quint16 innerseq; // 0x16
char unusedb[2]; // 0x18
quint16 tokrequest; // 0x1a
quint32 token; // 0x1c
char unusedd[7]; // 0x20
quint16 commoncap; // 0x27
char unuseddd[2]; // 0x29
char identa; // 0x2b
quint32 identb; // 0x2c
union {
struct {
quint16 authstartid; // 0x20
char unusedg2[2]; // 0x22
quint16 resetcap; // 0x24
char unusedg1; // 0x26
quint16 commoncap; // 0x27
char unusedh; // 0x29
quint8 macaddress[6]; // 0x2a
};
quint8 guid[GUIDLEN]; // 0x20
};
quint32 response; // 0x30
char unusede[12]; // 0x34
};
@ -175,20 +201,24 @@ typedef union status_packet {
quint16 seq; // 0x06
quint32 sentid; // 0x08
quint32 rcvdid; // 0x0c
char unuseda[3]; // 0x10
quint16 code; // 0x13
quint16 res; // 0x15
quint8 innerseq; // 0x17
char unusedb; // 0x18
char unusedc; // 0x19
char unuseda[2]; // 0x10
quint16 payloadsize; // 0x12
quint8 requestreply; // 0x13
quint8 requesttype; // 0x14
quint16 innerseq; // 0x16
char unusedb[2]; // 0x18
quint16 tokrequest; // 0x1a
quint32 token; // 0x1c
char unusedd[6]; // 0x20
quint16 unknown; // 0x26
char unusede; // 0x28
char unusedf[2]; // 0x29
char identa; // 0x2b
quint32 identb; // 0x2c
union {
struct {
quint16 authstartid; // 0x20
char unusedd[5]; // 0x22
quint16 commoncap; // 0x27
char unusede; // 0x29
quint8 macaddress[6]; // 0x2a
};
quint8 guid[GUIDLEN]; // 0x20
};
quint32 error; // 0x30
char unusedg[12]; // 0x34
char disc; // 0x40
@ -210,12 +240,12 @@ typedef union login_response_packet {
quint16 seq; // 0x06
quint32 sentid; // 0x08
quint32 rcvdid; // 0x0c
char unuseda[3]; // 0x10
quint16 code; // 0x13
quint16 res; // 0x15
quint8 innerseq; // 0x17
char unusedb; // 0x18
char unusedc; // 0x19
char unuseda[2]; // 0x10
quint16 payloadsize; // 0x12
quint8 requestreply; // 0x13
quint8 requesttype; // 0x14
quint16 innerseq; // 0x16
char unusedb[2]; // 0x18
quint16 tokrequest; // 0x1a
quint32 token; // 0x1c
quint16 authstartid; // 0x20
@ -237,12 +267,12 @@ typedef union login_packet {
quint16 seq; // 0x06
quint32 sentid; // 0x08
quint32 rcvdid; // 0x0c
char unuseda[3]; // 0x10
quint16 code; // 0x13
quint16 res; // 0x15
quint8 innerseq; // 0x17
char unusedaa; // 0x18;
char unusedb; // 0x19
char unuseda[2]; // 0x10
quint16 payloadsize; // 0x12
quint8 requestreply; // 0x13
quint8 requesttype; // 0x14
quint16 innerseq; // 0x16
char unusedb[2]; // 0x18
quint16 tokrequest; // 0x1a
quint32 token; // 0x1c
char unusedc[32]; // 0x20
@ -263,22 +293,26 @@ typedef union conninfo_packet {
quint16 seq; // 0x06
quint32 sentid; // 0x08
quint32 rcvdid; // 0x0c
char unuseda[3]; // 0x10
quint16 code; // 0x13
quint16 res; // 0x15
quint8 innerseq; // 0x17
char unusedaa; // 0x18
char unusedb; // 0x19
char unuseda[2]; // 0x10
quint16 payloadsize; // 0x12
quint8 requestreply; // 0x13
quint8 requesttype; // 0x14
quint16 innerseq; // 0x16
char unusedb[2]; // 0x18
quint16 tokrequest; // 0x1a
quint32 token; // 0x1c
quint16 authstartid; // 0x20
char unusedd[5]; // 0x22
quint32 commoncap; // 0x27
char identa; // 0x2b
quint32 identb; // 0x2c
char unusedf[16]; // 0x30
char name[16]; // 0x40
char unusedg[16]; // 0x50
union {
struct {
quint16 authstartid; // 0x20
char unusedg[5]; // 0x22
quint16 commoncap; // 0x27
char unusedh; // 0x29
quint8 macaddress[6]; // 0x2a
};
quint8 guid[GUIDLEN]; // 0x20
};
char unusedab[16]; // 0x30
char name[32]; // 0x40
union { // This contains differences between the send/receive packet
struct { // Receive
quint32 busy; // 0x60
@ -306,6 +340,41 @@ typedef union conninfo_packet {
char packet[CONNINFO_SIZE];
} *conninfo_packet_t;
// 0x64 length radio capabilities part of cap packet.
typedef union radio_cap_packet {
struct
{
union {
struct {
quint8 unusede[7]; // 0x00
quint16 commoncap; // 0x07
quint8 unused; // 0x09
quint8 macaddress[6]; // 0x0a
};
quint8 guid[GUIDLEN]; // 0x0
};
char name[32]; // 0x10
char audio[32]; // 0x30
quint16 conntype; // 0x50
char civ; // 0x52
quint16 rxsample; // 0x53
quint16 txsample; // 0x55
quint8 enablea; // 0x57
quint8 enableb; // 0x58
quint8 enablec; // 0x59
quint32 baudrate; // 0x5a
quint16 capf; // 0x5e
char unusedi; // 0x60
quint16 capg; // 0x61
char unusedj[3]; // 0x63
};
char packet[RADIO_CAP_SIZE];
} *radio_cap_packet_t;
// 0xA8 length capabilities packet
typedef union capabilities_packet {
struct
@ -315,39 +384,63 @@ typedef union capabilities_packet {
quint16 seq; // 0x06
quint32 sentid; // 0x08
quint32 rcvdid; // 0x0c
char unuseda[3]; // 0x10
quint16 code; // 0x13
quint16 res; // 0x15
quint8 innerseq; // 0x17
char unusedb; // 0x18
char unusedc; // 0x19
char unuseda[2]; // 0x10
quint16 payloadsize; // 0x12
quint8 requestreply; // 0x13
quint8 requesttype; // 0x14
quint16 innerseq; // 0x16
char unusedb[2]; // 0x18
quint16 tokrequest; // 0x1a
quint32 token; // 0x1c
char unusedd[33]; // 0x20
char capa; // 0x41
char unusede[7]; // 0x42
quint16 commoncap; // 0x49
char unused; // 0x4b
char macaddress[6]; // 0x4c
char name[32]; // 0x52
char audio[32]; // 0x72
quint16 conntype; // 0x92
char civ; // 0x94
quint16 rxsample; // 0x95
quint16 txsample; // 0x97
quint8 enablea; // 0x99
quint8 enableb; // 0x9a
quint8 enablec; // 0x9b
quint32 baudrate; // 0x9c
quint16 capf; // 0xa0
char unusedi; // 0xa2
quint16 capg; // 0xa3
char unusedj[3]; // 0xa5
char unusedd[32]; // 0x20
quint16 numradios; // 0x40
};
char packet[CAPABILITIES_SIZE];
} *capabilities_packet_t;
typedef union streamdeck_image_header {
struct
{
quint8 cmd;
quint8 suffix;
quint8 button;
quint8 isLast;
quint16 length;
quint16 index;
};
char packet[8];
} *streamdeck_image_header_t;
typedef union streamdeck_v1_image_header {
struct
{
quint8 cmd;
quint8 suffix;
quint16 index;
quint8 isLast;
quint8 button;
quint8 unused[10];
};
char packet[16];
} *streamdeck_v1_image_header_t;
typedef union streamdeck_lcd_header {
struct
{
quint8 cmd;
quint8 suffix;
quint16 x;
quint16 y;
quint16 width;
quint16 height;
quint8 isLast;
quint16 index;
quint16 length;
quint8 unused;
};
char packet[16];
} *streamdeck_lcd_header_t;
#pragma pack(pop)

343
pahandler.cpp 100644
Wyświetl plik

@ -0,0 +1,343 @@
#include "pahandler.h"
#include "logcategories.h"
#if defined(Q_OS_WIN)
#include <objbase.h>
#endif
paHandler::paHandler(QObject* parent)
{
Q_UNUSED(parent)
}
paHandler::~paHandler()
{
if (converterThread != Q_NULLPTR) {
converterThread->quit();
converterThread->wait();
}
if (isInitialized) {
Pa_StopStream(audio);
Pa_CloseStream(audio);
}
}
bool paHandler::init(audioSetup setup)
{
if (isInitialized) {
return false;
}
this->setup = setup;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "PortAudio handler starting:" << setup.name;
if (setup.portInt == -1)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "No audio device was found.";
return false;
}
radioFormat = toQAudioFormat(setup.codec, setup.sampleRate);
qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name <<
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
", bits" << radioFormat.sampleSize() <<
#else
", format" << radioFormat.sampleFormat() <<
#endif
", codec" << setup.codec <<
", latency" << setup.latency <<
", localAFGain" << setup.localAFgain <<
", radioChan" << radioFormat.channelCount() <<
", resampleQuality" << setup.resampleQuality <<
", samplerate" << radioFormat.sampleRate() <<
", uLaw" << setup.ulaw;
PaError err;
#ifdef Q_OS_WIN
CoInitialize(0);
#endif
//err = Pa_Initialize();
//if (err != paNoError)
//{
// qDebug(logAudio()) << "Portaudio initialized";
//}
codecType codec = LPCM;
if (setup.codec == 0x01 || setup.codec == 0x20)
codec = PCMU;
else if (setup.codec == 0x40 || setup.codec == 0x40)
codec = OPUS;
memset(&aParams, 0, sizeof(PaStreamParameters));
aParams.device = setup.portInt;
info = Pa_GetDeviceInfo(aParams.device);
qDebug(logAudio()) << "PortAudio" << (setup.isinput ? "Input" : "Output") << setup.portInt << "Input Channels" << info->maxInputChannels << "Output Channels" << info->maxOutputChannels;
if (setup.isinput) {
nativeFormat.setChannelCount(info->maxInputChannels);
}
else {
nativeFormat.setChannelCount(info->maxOutputChannels);
}
aParams.suggestedLatency = (float)setup.latency / 1000.0f;
nativeFormat.setSampleRate(info->defaultSampleRate);
aParams.sampleFormat = paFloat32;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
nativeFormat.setSampleSize(32);
nativeFormat.setSampleType(QAudioFormat::Float);
nativeFormat.setByteOrder(QAudioFormat::LittleEndian);
nativeFormat.setCodec("audio/pcm");
#else
nativeFormat.setSampleFormat(QAudioFormat::Float);
#endif
if (nativeFormat.channelCount() > 2) {
nativeFormat.setChannelCount(2);
}
else if (nativeFormat.channelCount() < 1)
{
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "No channels found, aborting setup.";
return false;
}
if (nativeFormat.channelCount() == 1 && radioFormat.channelCount() == 2) {
nativeFormat.setChannelCount(2);
}
aParams.channelCount = nativeFormat.channelCount();
if (nativeFormat.sampleRate() < 44100) {
nativeFormat.setSampleRate(48000);
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << nativeFormat.sampleSize() << "Channel Count" << nativeFormat.channelCount() <<
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec << "Sample Type" << nativeFormat.sampleType();
#else
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleFormat" << nativeFormat.sampleFormat() << "Channel Count" << nativeFormat.channelCount() <<
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec;
#endif
// We "hopefully" now have a valid format that is supported so try connecting
converter = new audioConverter();
converterThread = new QThread(this);
if (setup.isinput) {
converterThread->setObjectName("audioConvIn()");
}
else {
converterThread->setObjectName("audioConvOut()");
}
converter->moveToThread(converterThread);
connect(this, SIGNAL(setupConverter(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)), converter, SLOT(init(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)));
connect(converterThread, SIGNAL(finished()), converter, SLOT(deleteLater()));
connect(this, SIGNAL(sendToConverter(audioPacket)), converter, SLOT(convert(audioPacket)));
converterThread->start(QThread::TimeCriticalPriority);
aParams.hostApiSpecificStreamInfo = NULL;
// Per channel chunk size.
this->chunkSize = nativeFormat.framesForDuration(setup.blockSize * 1000);
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Chunk size" << this->chunkSize;
// Check the format is supported
err = -1;
int errCount = 0;
while (err != paNoError) {
if (setup.isinput) {
err = Pa_IsFormatSupported(&aParams, NULL, nativeFormat.sampleRate());
}
else
{
err = Pa_IsFormatSupported(NULL, &aParams, nativeFormat.sampleRate());
}
if (err == paInvalidChannelCount)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported channel count" << aParams.channelCount;
if (aParams.channelCount == 2) {
aParams.channelCount = 1;
nativeFormat.setChannelCount(1);
}
else {
aParams.channelCount = 2;
nativeFormat.setChannelCount(2);
}
}
if (err == paInvalidSampleRate)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported sample rate" << nativeFormat.sampleRate();
nativeFormat.setSampleRate(44100);
}
if (err == paSampleFormatNotSupported)
{
aParams.sampleFormat = paInt16;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported sample Format" << nativeFormat.sampleType();
nativeFormat.setSampleType(QAudioFormat::SignedInt);
nativeFormat.setSampleSize(16);
#else
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported sample Format" << nativeFormat.sampleFormat();
nativeFormat.setSampleFormat(QAudioFormat::Int16);
#endif
}
errCount++;
if (errCount > 5) {
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Cannot find suitable format, aborting:" << Pa_GetErrorText(err);
return false;
}
}
if (setup.isinput) {
err = Pa_OpenStream(&audio, &aParams, 0, nativeFormat.sampleRate(), this->chunkSize, paNoFlag, &paHandler::staticWrite, (void*)this);
emit setupConverter(nativeFormat, codecType::LPCM, radioFormat, codec, 7, setup.resampleQuality);
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedInput(audioPacket)));
}
else {
err = Pa_OpenStream(&audio, 0, &aParams, nativeFormat.sampleRate(), this->chunkSize, paNoFlag, NULL, NULL);
emit setupConverter(radioFormat, codec, nativeFormat, codecType::LPCM, 7, setup.resampleQuality);
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedOutput(audioPacket)));
}
if (err == paNoError) {
err = Pa_StartStream(audio);
}
if (err == paNoError) {
isInitialized = true;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "device successfully opened";
}
else {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "failed to open device" << Pa_GetErrorText(err);
}
this->setVolume(setup.localAFgain);
return isInitialized;
}
void paHandler::setVolume(unsigned char volume)
{
#ifdef Q_OS_WIN
this->volume = audiopot[volume] * 5;
#else
this->volume = audiopot[volume];
#endif
}
void paHandler::incomingAudio(audioPacket packet)
{
packet.volume = volume;
if (Pa_IsStreamActive(audio) == 1) {
emit sendToConverter(packet);
}
else
{
Pa_StartStream(audio);
}
return;
}
int paHandler::writeData(const void* inputBuffer, void* outputBuffer,
unsigned long nFrames, const PaStreamCallbackTimeInfo * streamTime,
PaStreamCallbackFlags status)
{
Q_UNUSED(outputBuffer);
Q_UNUSED(streamTime);
Q_UNUSED(status);
audioPacket packet;
packet.time = QTime::currentTime();
packet.sent = 0;
packet.volume = volume;
memcpy(&packet.guid, setup.guid, GUIDLEN);
packet.data.append((char*)inputBuffer, nFrames*nativeFormat.bytesPerFrame());
emit sendToConverter(packet);
if (status == paInputUnderflow) {
isUnderrun = true;
}
else if (status == paInputOverflow) {
isOverrun = true;
}
else
{
isUnderrun = false;
isOverrun = false;
}
return paContinue;
}
void paHandler::convertedOutput(audioPacket packet) {
if (packet.data.size() > 0) {
if (Pa_IsStreamActive(audio) == 1) {
PaError err = Pa_WriteStream(audio, (char*)packet.data.data(), packet.data.size() / nativeFormat.bytesPerFrame());
if (err != paNoError) {
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Error writing audio!";
}
const PaStreamInfo* info = Pa_GetStreamInfo(audio);
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->outputLatency * 1000);
}
amplitude = packet.amplitudePeak;
emit haveLevels(getAmplitude(), static_cast<quint16>(packet.amplitudeRMS * 255.0), setup.latency, currentLatency, isUnderrun, isOverrun);
}
}
void paHandler::convertedInput(audioPacket packet)
{
if (packet.data.size() > 0) {
emit haveAudioData(packet);
amplitude = packet.amplitudePeak;
const PaStreamInfo* info = Pa_GetStreamInfo(audio);
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (info->inputLatency * 1000);
emit haveLevels(getAmplitude(), packet.amplitudeRMS, setup.latency, currentLatency, isUnderrun, isOverrun);
}
}
void paHandler::changeLatency(const quint16 newSize)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << setup.latency;
setup.latency = newSize;
latencyAllowance = 0;
}
int paHandler::getLatency()
{
return currentLatency;
}
quint16 paHandler::getAmplitude()
{
return static_cast<quint16>(amplitude * 255.0);
}

97
pahandler.h 100644
Wyświetl plik

@ -0,0 +1,97 @@
#ifndef PAHANDLER_H
#define PAHANDLER_H
#include <QObject>
#include <QByteArray>
#include <QThread>
#include "portaudio.h"
#include <QAudioFormat>
#include <QTime>
#include <QMap>
/* wfview Packet types */
#include "packettypes.h"
/* Logarithmic taper for volume control */
#include "audiotaper.h"
#include "audiohandler.h"
/* Audio converter class*/
#include "audioconverter.h"
#include <QDebug>
class paHandler : public audioHandler
{
Q_OBJECT
public:
paHandler(QObject* parent = 0);
~paHandler();
int getLatency();
using audioHandler::getNextAudioChunk;
void getNextAudioChunk(QByteArray& data);
quint16 getAmplitude();
public slots:
bool init(audioSetup setup);
void changeLatency(const quint16 newSize);
void setVolume(unsigned char volume);
void convertedInput(audioPacket audio);
void convertedOutput(audioPacket audio);
void incomingAudio(const audioPacket data);
private slots:
signals:
void audioMessage(QString message);
void sendLatency(quint16 newSize);
void haveAudioData(const audioPacket& data);
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS, quint16 latency, quint16 current, bool under, bool over);
void setupConverter(QAudioFormat in, codecType codecIn, QAudioFormat out, codecType codecOut, quint8 opus, quint8 resamp);
void sendToConverter(audioPacket audio);
private:
int writeData(const void* inputBuffer, void* outputBuffer,
unsigned long nFrames,
const PaStreamCallbackTimeInfo* streamTime,
PaStreamCallbackFlags status);
static int staticWrite(const void* inputBuffer, void* outputBuffer, unsigned long nFrames, const PaStreamCallbackTimeInfo* streamTime, PaStreamCallbackFlags status, void* userData) {
return ((paHandler*)userData)->writeData(inputBuffer, outputBuffer, nFrames, streamTime, status);
}
bool isInitialized = false;
PaStream* audio = Q_NULLPTR;
PaStreamParameters aParams;
const PaDeviceInfo* info;
quint16 audioLatency;
unsigned int chunkSize;
quint32 lastSeq;
quint32 lastSentSeq = 0;
quint16 currentLatency;
float amplitude=0.0;
qreal volume = 1.0;
audioSetup setup;
QAudioFormat radioFormat;
QAudioFormat nativeFormat;
audioConverter* converter = Q_NULLPTR;
QThread* converterThread = Q_NULLPTR;
bool isUnderrun = false;
bool isOverrun = false;
int latencyAllowance = 0;
};
#endif // PAHANDLER_H

73
prefs.h 100644
Wyświetl plik

@ -0,0 +1,73 @@
#ifndef PREFS_H
#define PREFS_H
#include <QString>
#include <QColor>
#include <QMap>
#include "wfviewtypes.h"
struct preferences {
// Program:
QString version;
int majorVersion = 0;
int minorVersion = 0;
QString gitShort;
// Interface:
bool useFullScreen;
bool useSystemTheme;
int wfEnable;
bool drawPeaks;
underlay_t underlayMode = underlayNone;
int underlayBufferSize = 64;
bool wfAntiAlias;
bool wfInterpolate;
int wftheme;
int plotFloor;
int plotCeiling;
QString stylesheetPath;
unsigned int wflength;
bool confirmExit;
bool confirmPowerOff;
meterKind meter2Type;
bool clickDragTuningEnable;
// Radio:
unsigned char radioCIVAddr;
bool CIVisRadioModel;
bool forceRTSasPTT;
int polling_ms;
QString serialPortRadio;
quint32 serialPortBaud;
QString virtualSerialPort;
unsigned char localAFgain;
audioType audioSystem;
// Controls:
bool enablePTT;
bool niceTS;
bool automaticSidebandSwitching = true;
bool enableUSBControllers;
// LAN:
bool enableLAN;
bool enableRigCtlD;
quint16 rigCtlPort;
int currentColorPresetNumber = 0;
quint16 tcpPort;
quint8 waterfallFormat;
// Cluster:
bool clusterUdpEnable;
bool clusterTcpEnable;
int clusterUdpPort;
QString clusterTcpServerName;
QString clusterTcpUserName;
QString clusterTcpPassword;
int clusterTimeout;
bool clusterSkimmerSpotsEnable;
};
#endif // PREFS_H

42
printhex.h 100644
Wyświetl plik

@ -0,0 +1,42 @@
#ifndef PRINTHEX_H
#define PRINTHEX_H
#include <QByteArray>
#include <QString>
#include "logcategories.h"
QString inline getHex(const QByteArray &pdata)
{
QString head = "---- Begin hex dump -----:\n";
QString sdata("DATA: ");
QString index("INDEX: ");
for(int i=0; i < pdata.length(); i++)
{
sdata.append(QString("%1 ").arg((unsigned char)pdata[i], 2, 16, QChar('0')) );
index.append(QString("%1 ").arg(i, 2, 10, QChar('0')));
}
sdata.append("\n");
index.append("\n");
QString tail = "---- End hex dump -----\n";
return head + sdata + index + tail;
}
void inline printHexNow(const QByteArray &pdata, const QLoggingCategory &cat)
{
QString d = getHex(pdata);
// These lines are needed to keep the formatting as expected in the log file
if(d.endsWith("\n"))
{
d.chop(1);
}
QStringList s = d.split("\n");
for(int i=0; i < s.length(); i++)
{
qDebug(cat) << s.at(i);
}
}
#endif // PRINTHEX_H

Wyświetl plik

@ -8,11 +8,12 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#endif
// Copyright 2017-2021 Elliott H. Liggett & Phil Taylor
pttyHandler::pttyHandler(QString pty)
pttyHandler::pttyHandler(QString pty, QObject* parent) : QObject(parent)
{
//constructor
if (pty == "" || pty.toLower() == "none")
@ -72,6 +73,9 @@ void pttyHandler::openPort()
// we're good!
qInfo(logSerial()) << "Opened pseudoterminal, slave name :" << ptsname(ptfd);
// Open the slave device to keep alive.
ptKeepAlive = open(ptsname(ptfd), O_RDONLY);
ptReader = new QSocketNotifier(ptfd, QSocketNotifier::Read, this);
connect(ptReader, &QSocketNotifier::activated,
this, &pttyHandler::receiveDataIn);
@ -86,7 +90,7 @@ void pttyHandler::openPort()
qInfo(logSerial()) << "Could not open pseudo terminal port, please restart.";
isConnected = false;
serialError = true;
emit haveSerialPortError(portName, "Could not open pseudo terminal port. Please restart.");
emit havePortError(errorType(portName, "Could not open pseudo terminal port. Please restart."));
return;
}
@ -210,16 +214,15 @@ void pttyHandler::receiveDataIn(int fd) {
if (civId == 0 && inPortData.length() > lastFE + 2 && (quint8)inPortData[lastFE + 2] > (quint8)0xdf && (quint8)inPortData[lastFE + 2] < (quint8)0xef) {
// This is (should be) the remotes CIV id.
civId = (quint8)inPortData[lastFE + 2];
qInfo(logSerial()) << "pty detected remote CI-V:" << hex << civId;
qInfo(logSerial()) << "pty detected remote CI-V:" << QString("0x%1").arg(civId,0,16);
}
else if (civId != 0 && inPortData.length() > lastFE + 2 && (quint8)inPortData[lastFE + 2] != civId)
{
civId = (quint8)inPortData[lastFE + 2];
qInfo(logSerial()) << "pty remote CI-V changed:" << hex << (quint8)civId;
qInfo(logSerial()) << "pty remote CI-V changed:" << QString("0x%1").arg((quint8)civId,0,16);
}
// filter 1A 05 01 12/27 = C-IV transceive command before forwarding on.
if (inPortData.contains(QByteArrayLiteral("\x1a\x05\x01\x12")) || inPortData.contains(QByteArrayLiteral("\x1a\x05\x01\x27")))
// filter C-IV transceive command before forwarding on.
if (inPortData.contains(rigCaps.transceiveCommand))
{
//qInfo(logSerial()) << "Filtered transceive command";
//printHex(inPortData, false, true);
@ -242,14 +245,14 @@ void pttyHandler::receiveDataIn(int fd) {
if (rolledBack)
{
// qInfo(logSerial()) << "Rolled back and was successfull. Length: " << inPortData.length();
// qInfo(logSerial()) << "Rolled back and was successful. Length: " << inPortData.length();
//printHex(inPortData, false, true);
rolledBack = false;
}
}
else {
// did not receive the entire thing so roll back:
// qInfo(logSerial()) << "Rolling back transaction. End not detected. Lenth: " << inPortData.length();
// qInfo(logSerial()) << "Rolling back transaction. End not detected. Length: " << inPortData.length();
//printHex(inPortData, false, true);
rolledBack = true;
#ifdef Q_OS_WIN
@ -283,6 +286,10 @@ void pttyHandler::closePort()
{
QFile::remove(portName);
}
if (ptKeepAlive > 0) {
close(ptKeepAlive);
}
#endif
isConnected = false;
}
@ -330,4 +337,10 @@ void pttyHandler::printHex(const QByteArray& pdata, bool printVert, bool printHo
qDebug(logSerial()) << "----- End hex dump -----";
}
void pttyHandler::receiveFoundRigID(rigCapabilities rigCaps) {
this->rigCaps = rigCaps;
qInfo(logSerial) << "Received rigCapabilities for" << rigCaps.modelName;
}

Wyświetl plik

@ -9,6 +9,9 @@
#include <QSocketNotifier>
#include <QtSerialPort/QSerialPort>
#include "rigidentities.h"
#include "wfviewtypes.h"
// This class abstracts the comm port in a useful way and connects to
// the command creator and command parser.
@ -17,7 +20,7 @@ class pttyHandler : public QObject
Q_OBJECT
public:
pttyHandler(QString portName);
explicit pttyHandler(QString portName, QObject* parent = nullptr);
pttyHandler(QString portName, quint32 baudRate);
bool serialError;
@ -27,11 +30,12 @@ private slots:
void receiveDataIn(int fd); // from physical port
void receiveDataFromRigToPtty(const QByteArray& data);
void debugThis();
void receiveFoundRigID(rigCapabilities rigCaps);
signals:
void haveTextMessage(QString message); // status, debug only
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
void haveSerialPortError(const QString port, const QString error);
void havePortError(errorType err);
void haveStatusUpdate(const QString text);
private:
@ -59,6 +63,7 @@ private:
bool rolledBack;
int ptfd; // pseudo-terminal file desc.
int ptKeepAlive=0; // Used to keep the pty alive after client disconnects.
bool havePt;
QString ptDevSlave;
@ -66,8 +71,9 @@ private:
mutable QMutex mutex;
void printHex(const QByteArray& pdata, bool printVert, bool printHoriz);
bool disableTransceive = false;
QSocketNotifier *ptReader = nullptr;
QSocketNotifier *ptReader = Q_NULLPTR;
quint8 civId=0;
rigCapabilities rigCaps;
};
#endif // PTTYHANDLER_H

Wyświetl plik

@ -1,5 +1,5 @@
QToolTip {
border: 1px solid #76797C;
border: 1px solid #767676;
background-color: #5A7566;
color: white;
padding: 0px; /*remove padding, for fix combobox tooltip.*/
@ -8,7 +8,7 @@ QToolTip {
QWidget {
color: #eff0f1;
background-color: #31363b;
background-color: #313131;
selection-background-color: #3daee9;
selection-color: #eff0f1;
background-clip: border;
@ -34,7 +34,7 @@ QCheckBox {
}
QCheckBox:disabled {
color: #76797C;
color: #767676;
}
QCheckBox::indicator,
@ -105,7 +105,7 @@ QRadioButton {
}
QRadioButton:disabled {
color: #76797C;
color: #767676;
}
QRadioButton::indicator {
@ -149,7 +149,7 @@ QRadioButton::indicator:unchecked:disabled {
}
QMenuBar {
background-color: #31363b;
background-color: #313131;
color: #eff0f1;
}
@ -159,11 +159,11 @@ QMenuBar::item {
QMenuBar::item:selected {
background: transparent;
border: 1px solid #76797C;
border: 1px solid #767676;
}
QMenuBar::item:pressed {
border: 1px solid #76797C;
border: 1px solid #767676;
background-color: #3daee9;
color: #eff0f1;
margin-bottom: -1px;
@ -171,7 +171,7 @@ QMenuBar::item:pressed {
}
QMenu {
border: 1px solid #76797C;
border: 1px solid #767676;
color: #eff0f1;
margin: 2px;
}
@ -248,11 +248,11 @@ QMenu::right-arrow {
QWidget:disabled {
color: #454545;
background-color: #31363b;
background-color: #313131;
}
QAbstractItemView {
alternate-background-color: #31363b;
alternate-background-color: #313131;
color: #eff0f1;
border: 1px solid #3A3939;
border-radius: 2px;
@ -274,7 +274,7 @@ QLineEdit {
background-color: #232629;
padding: 5px;
border-style: solid;
border: 1px solid #76797C;
border: 1px solid #767676;
border-radius: 2px;
color: #eff0f1;
}
@ -284,7 +284,7 @@ QAbstractItemView QLineEdit {
}
QGroupBox {
border: 1px solid #76797C;
border: 1px solid #767676;
border-radius: 2px;
margin-top: 20px;
}
@ -299,7 +299,7 @@ QGroupBox::title {
QAbstractScrollArea {
border-radius: 2px;
border: 1px solid #76797C;
border: 1px solid #767676;
background-color: transparent;
}
@ -426,7 +426,7 @@ QScrollBar::sub-page:vertical {
QTextEdit {
background-color: #232629;
color: #eff0f1;
border: 1px solid #76797C;
border: 1px solid #767676;
}
QPlainTextEdit {
@ -434,14 +434,14 @@ QPlainTextEdit {
;
color: #eff0f1;
border-radius: 2px;
border: 1px solid #76797C;
border: 1px solid #767676;
}
QHeaderView::section {
background-color: #76797C;
background-color: #767676;
color: #eff0f1;
padding: 5px;
border: 1px solid #76797C;
border: 1px solid #767676;
}
QSizeGrip {
@ -451,24 +451,24 @@ QSizeGrip {
}
QMainWindow::separator {
background-color: #31363b;
background-color: #313131;
color: white;
padding-left: 4px;
spacing: 2px;
border: 1px dashed #76797C;
border: 1px dashed #767676;
}
QMainWindow::separator:hover {
background-color: #787876;
color: white;
padding-left: 4px;
border: 1px solid #76797C;
border: 1px solid #767676;
spacing: 2px;
}
QMenu::separator {
height: 1px;
background-color: #76797C;
background-color: #767676;
color: white;
padding-left: 4px;
margin-left: 10px;
@ -477,12 +477,12 @@ QMenu::separator {
QFrame {
border-radius: 2px;
border: 1px solid #76797C;
border: 1px solid #767676;
}
QFrame[frameShape="0"] {
border-radius: 2px;
border: 1px transparent #76797C;
border: 1px transparent #767676;
}
QStackedWidget {
@ -491,7 +491,7 @@ QStackedWidget {
QToolBar {
border: 1px transparent #393838;
background: 1px solid #31363b;
background: 1px solid #313131;
font-weight: bold;
}
@ -512,14 +512,14 @@ QToolBar::separator:vertical {
}
QToolButton#qt_toolbar_ext_button {
background: #58595a
background: #585858
}
QPushButton {
color: #eff0f1;
background-color: #31363b;
background-color: #313131;
border-width: 1px;
border-color: #76797C;
border-color: #767676;
border-style: solid;
padding: 5px;
border-radius: 2px;
@ -527,7 +527,7 @@ QPushButton {
}
QPushButton:disabled {
background-color: #31363b;
background-color: #313131;
border-width: 1px;
border-color: #454545;
border-style: solid;
@ -553,14 +553,14 @@ QPushButton:pressed {
QComboBox {
selection-background-color: #3daee9;
border-style: solid;
border: 1px solid #76797C;
border: 1px solid #767676;
border-radius: 2px;
padding: 5px;
min-width: 75px;
}
QPushButton:checked {
background-color: #76797C;
background-color: #767676;
border-color: #6A6969;
}
@ -585,7 +585,7 @@ QComboBox:on {
QComboBox QAbstractItemView {
background-color: #232629;
border-radius: 2px;
border: 1px solid #76797C;
border: 1px solid #767676;
selection-background-color: #18465d;
}
@ -612,7 +612,7 @@ QComboBox::down-arrow:focus {
QAbstractSpinBox {
padding: 5px;
border: 1px solid #76797C;
border: 1px solid #767676;
background-color: #232629;
color: #eff0f1;
border-radius: 2px;
@ -664,7 +664,7 @@ QTabWidget {
}
QTabWidget::pane {
border: 1px solid #76797C;
border: 1px solid #767676;
padding: 5px;
margin: 0px;
}
@ -702,9 +702,9 @@ QTabBar::close-button:pressed {
QTabBar::tab:top {
color: #eff0f1;
border: 1px solid #76797C;
border: 1px solid #767676;
border-bottom: 1px transparent black;
background-color: #31363b;
background-color: #313131;
padding: 5px;
min-width: 50px;
border-top-left-radius: 2px;
@ -714,7 +714,7 @@ QTabBar::tab:top {
QTabBar::tab:top:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
border: 1px solid #767676;
border-bottom: 2px solid #3daee9;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
@ -729,9 +729,9 @@ QTabBar::tab:top:!selected:hover {
QTabBar::tab:bottom {
color: #eff0f1;
border: 1px solid #76797C;
border: 1px solid #767676;
border-top: 1px transparent black;
background-color: #31363b;
background-color: #313131;
padding: 5px;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
@ -741,7 +741,7 @@ QTabBar::tab:bottom {
QTabBar::tab:bottom:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
border: 1px solid #767676;
border-top: 2px solid #3daee9;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
@ -756,9 +756,9 @@ QTabBar::tab:bottom:!selected:hover {
QTabBar::tab:left {
color: #eff0f1;
border: 1px solid #76797C;
border: 1px solid #767676;
border-left: 1px transparent black;
background-color: #31363b;
background-color: #313131;
padding: 5px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
@ -768,7 +768,7 @@ QTabBar::tab:left {
QTabBar::tab:left:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
border: 1px solid #767676;
border-left: 2px solid #3daee9;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
@ -783,9 +783,9 @@ QTabBar::tab:left:!selected:hover {
QTabBar::tab:right {
color: #eff0f1;
border: 1px solid #76797C;
border: 1px solid #767676;
border-right: 1px transparent black;
background-color: #31363b;
background-color: #313131;
padding: 5px;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
@ -795,7 +795,7 @@ QTabBar::tab:right {
QTabBar::tab:right:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
border: 1px solid #767676;
border-right: 2px solid #3daee9;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
@ -822,7 +822,7 @@ QTabBar QToolButton::left-arrow:disabled {
}
QDockWidget {
background: #31363b;
background: #313131;
border: 1px solid #403F3F;
titlebar-close-icon: url(:/qss_icons/rc/close.png);
titlebar-normal-icon: url(:/qss_icons/rc/undock.png);
@ -848,7 +848,7 @@ QDockWidget::float-button:pressed {
QTreeView,
QListView {
border: 1px solid #76797C;
border: 1px solid #767676;
background-color: #232629;
}
@ -980,7 +980,7 @@ QSlider::handle:vertical {
QToolButton {
background-color: transparent;
border: 1px transparent #76797C;
border: 1px transparent #767676;
border-radius: 2px;
margin: 3px;
padding: 5px;
@ -990,7 +990,7 @@ QToolButton[popupMode="1"] {
/* only for MenuButtonPopup */
padding-right: 20px;
/* make way for the popup button */
border: 1px #76797C;
border: 1px #767676;
border-radius: 5px;
}
@ -998,7 +998,7 @@ QToolButton[popupMode="2"] {
/* only for InstantPopup */
padding-right: 10px;
/* make way for the popup button */
border: 1px #76797C;
border: 1px #767676;
}
QToolButton:hover,
@ -1030,7 +1030,7 @@ QToolButton::menu-indicator {
/* the subcontrols below are used only in the MenuButtonPopup mode */
QToolButton::menu-button {
border: 1px transparent #76797C;
border: 1px transparent #767676;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
/* 16px width + 4px for border = 20px allocated above */
@ -1043,7 +1043,7 @@ QToolButton::menu-arrow {
}
QToolButton::menu-arrow:open {
border: 1px solid #76797C;
border: 1px solid #767676;
}
QPushButton::menu-indicator {
@ -1053,8 +1053,8 @@ QPushButton::menu-indicator {
}
QTableView {
border: 1px solid #76797C;
gridline-color: #31363b;
border: 1px solid #767676;
gridline-color: #313131;
background-color: #232629;
}
@ -1078,7 +1078,7 @@ QListView::item:selected:active {
}
QHeaderView {
background-color: #31363b;
background-color: #313131;
border: 1px transparent;
border-radius: 0px;
margin: 0px;
@ -1086,17 +1086,17 @@ QHeaderView {
}
QHeaderView::section {
background-color: #31363b;
background-color: #313131;
color: #eff0f1;
padding: 5px;
border: 1px solid #76797C;
border: 1px solid #767676;
border-radius: 0px;
text-align: center;
}
QHeaderView::section::vertical::first,
QHeaderView::section::vertical::only-one {
border-top: 1px solid #76797C;
border-top: 1px solid #767676;
}
QHeaderView::section::vertical {
@ -1105,7 +1105,7 @@ QHeaderView::section::vertical {
QHeaderView::section::horizontal::first,
QHeaderView::section::horizontal::only-one {
border-left: 1px solid #76797C;
border-left: 1px solid #767676;
}
QHeaderView::section::horizontal {
@ -1129,8 +1129,8 @@ QHeaderView::up-arrow {
}
QTableCornerButton::section {
background-color: #31363b;
border: 1px transparent #76797C;
background-color: #313131;
border: 1px transparent #767676;
border-radius: 0px;
}
@ -1141,9 +1141,9 @@ QToolBox {
QToolBox::tab {
color: #eff0f1;
background-color: #31363b;
border: 1px solid #76797C;
border-bottom: 1px transparent #31363b;
background-color: #313131;
border: 1px solid #767676;
border-bottom: 1px transparent #313131;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
@ -1151,7 +1151,7 @@ QToolBox::tab {
QToolBox::tab:selected {
/* italicize selected tabs */
font: italic;
background-color: #31363b;
background-color: #313131;
border-color: #3daee9;
}
@ -1161,16 +1161,16 @@ QStatusBar::item {
QFrame[height="3"],
QFrame[width="3"] {
background-color: #76797C;
background-color: #767676;
}
QSplitter::handle {
border: 1px dashed #76797C;
border: 1px dashed #767676;
}
QSplitter::handle:hover {
background-color: #787876;
border: 1px solid #76797C;
border: 1px solid #767676;
}
QSplitter::handle:horizontal {
@ -1182,7 +1182,7 @@ QSplitter::handle:vertical {
}
QProgressBar {
border: 1px solid #76797C;
border: 1px solid #767676;
border-radius: 5px;
text-align: center;
}

Wyświetl plik

@ -4,20 +4,23 @@
static const int SIZE = 16;
static const QString greenSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.145, y1:0.16, x2:1, y2:1, stop:0 rgba(20, 252, 7, 255), stop:1 rgba(25, 134, 5, 255));").arg(SIZE / 2);
static const QString redSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.145, y1:0.16, x2:0.92, y2:0.988636, stop:0 rgba(255, 12, 12, 255), stop:0.869347 rgba(103, 0, 0, 255));").arg(SIZE / 2);
static const QString rgSplitSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(255, 0, 0, 255), stop:1.0 rgba(0, 255, 0, 255));").arg(SIZE / 2);
static const QString orangeSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.232, y1:0.272, x2:0.98, y2:0.959773, stop:0 rgba(255, 113, 4, 255), stop:1 rgba(91, 41, 7, 255))").arg(SIZE / 2);
static const QString blueSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.04, y1:0.0565909, x2:0.799, y2:0.795, stop:0 rgba(203, 220, 255, 255), stop:0.41206 rgba(0, 115, 255, 255), stop:1 rgba(0, 49, 109, 255));").arg(SIZE / 2);
static const QString blankSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.04, y1:0.0565909, x2:0.799, y2:0.795, stop:0 rgba(203, 220, 255, 0), stop:0.41206 rgba(0, 115, 255, 0), stop:1 rgba(0, 49, 109, 0));").arg(SIZE / 2);
QLedLabel::QLedLabel(QWidget* parent) :
QLabel(parent)
{
//Set to ok by default
setState(StateOkBlue);
baseColor = QColor(0, 115, 255, 255);
setFixedSize(SIZE, SIZE);
}
void QLedLabel::setState(State state)
{
qInfo() << "setState" << state;
//Debug() << "LED: setState" << state;
switch (state) {
case StateOk:
setStyleSheet(greenSS);
@ -29,6 +32,14 @@ void QLedLabel::setState(State state)
setStyleSheet(redSS);
break;
case StateOkBlue:
setStyleSheet(blueSS);
break;
case StateBlank:
setStyleSheet(blankSS);
break;
case StateSplitErrorOk:
setStyleSheet(rgSplitSS);
break;
default:
setStyleSheet(blueSS);
break;
@ -38,4 +49,62 @@ void QLedLabel::setState(State state)
void QLedLabel::setState(bool state)
{
setState(state ? StateOk : StateError);
}
}
void QLedLabel::setColor(QColor customColor, bool applyGradient=true)
{
QColor top,middle,bottom;
this->baseColor = customColor;
if(applyGradient)
{
top = customColor.lighter(200);
middle = customColor;
bottom = customColor.darker(200);
} else {
top = customColor;
middle = customColor;
bottom = customColor;
}
// Stop 0 is the upper corner color, white-ish
// Stop 0.4 is the middle color
// Stop 1 is the bottom-right corner, darker.
QString colorSS = QString("color: white;\
border-radius: %1;background-color: \
qlineargradient(spread:pad, x1:0.04, \
y1:0.0565909, x2:0.799, y2:0.795, \
stop:0 \
rgba(%2, %3, %4, %5), \
stop:0.41206 \
rgba(%6, %7, %8, %9), \
stop:1 \
rgba(%10, %11, %12, %13));").arg(SIZE / 2)
.arg(top.red()).arg(top.green()).arg(top.blue()).arg(top.alpha())
.arg(middle.red()).arg(middle.green()).arg(middle.blue()).arg(middle.alpha())
.arg(bottom.red()).arg(bottom.green()).arg(bottom.blue()).arg(bottom.alpha());
setStyleSheet(colorSS);
}
void QLedLabel::setColor(QString colorString, bool applyGradient=true)
{
QColor c = QColor(colorString);
setColor(c, applyGradient);
}
void QLedLabel::setColor(QColor c)
{
this->setColor(c, true);
}
void QLedLabel::setColor(QString s)
{
this->setColor(s, true);
}
QColor QLedLabel::getColor()
{
return baseColor;
}

Wyświetl plik

@ -13,7 +13,9 @@ public:
StateOk,
StateOkBlue,
StateWarning,
StateError
StateError,
StateSplitErrorOk,
StateBlank
};
@ -22,6 +24,14 @@ signals:
public slots:
void setState(State state);
void setState(bool state);
void setColor(QColor customColor, bool applyGradient);
void setColor(QString colorString, bool applyGradient);
void setColor(QColor c);
void setColor(QString s);
QColor getColor();
private:
QColor baseColor;
};
#endif // QLEDLABEL_H

Wyświetl plik

@ -2,31 +2,7 @@
#define REPEATERATTRIBUTES_H
#include <QMetaType>
enum duplexMode {
dmSplitOff=0x00,
dmSplitOn=0x01,
dmSimplex=0x10,
dmDupMinus=0x11,
dmDupPlus=0x12,
dmDupRPS=0x13,
dmDupAutoOn=0x26,
dmDupAutoOff=0x36
};
// TODO: Remove this file as it does nothing.
// Here, T=tone, D=DCS, N=none
// And the naming convention order is Transmit Receive
enum rptAccessTxRx {
ratrNN=0x00,
ratrTN=0x01, // "TONE" (T only)
ratrNT=0x02, // "TSQL" (R only)
ratrDD=0x03, // "DTCS" (TR)
ratrDN=0x06, // "DTCS(T)"
ratrTD=0x07, // "TONE(T) / TSQL(R)"
ratrDT=0x08, // "DTCS(T) / TSQL(R)"
ratrTT=0x09 // "TONE(T) / TSQL(R)"
};
Q_DECLARE_METATYPE(enum duplexMode)
Q_DECLARE_METATYPE(enum rptAccessTxRx)
#endif // REPEATERATTRIBUTES_H

Wyświetl plik

@ -7,25 +7,18 @@ repeaterSetup::repeaterSetup(QWidget *parent) :
{
ui->setupUi(this);
ui->autoTrackLiveBtn->setEnabled(false); // until we set split enabled.
ui->warningFMLabel->setVisible(false);
// populate the CTCSS combo box:
populateTones();
// populate the DCS combo box:
populateDTCS();
#ifdef QT_DEBUG
ui->debugBtn->setVisible(true);
ui->rptReadRigBtn->setVisible(true);
#else
ui->debugBtn->setVisible(false);
ui->rptReadRigBtn->setVisible(false);
#endif
}
repeaterSetup::~repeaterSetup()
{
// Trying this for more consistant destruction
// Trying this for more consistent destruction
rig.inputs.clear();
rig.preamps.clear();
rig.attenuators.clear();
@ -48,7 +41,6 @@ void repeaterSetup::setRig(rigCapabilities inRig)
ui->toneTone->setDisabled(true);
ui->toneTSQL->setDisabled(true);
}
if(rig.hasDTCS)
{
ui->rptDTCSCombo->setDisabled(false);
@ -61,6 +53,55 @@ void repeaterSetup::setRig(rigCapabilities inRig)
ui->rptDTCSInvertRx->setDisabled(true);
ui->rptDTCSInvertTx->setDisabled(true);
}
if(rig.hasVFOAB)
{
ui->selABtn->setDisabled(false);
ui->selBBtn->setDisabled(false);
ui->aEqBBtn->setDisabled(false);
ui->swapABBtn->setDisabled(false);
} else {
ui->selABtn->setDisabled(true);
ui->selBBtn->setDisabled(true);
ui->aEqBBtn->setDisabled(true);
ui->swapABBtn->setDisabled(true);
}
if(rig.hasVFOMS)
{
ui->selMainBtn->setDisabled(false);
ui->selSubBtn->setDisabled(false);
ui->mEqSBtn->setDisabled(false);
ui->swapMSBtn->setDisabled(false);
} else {
ui->selMainBtn->setDisabled(true);
ui->selSubBtn->setDisabled(true);
ui->mEqSBtn->setDisabled(true);
ui->swapMSBtn->setDisabled(true);
}
if(rig.hasVFOMS && rig.hasVFOAB)
{
// Rigs that have both AB and MS
// do not have a swap AB command.
ui->swapABBtn->setDisabled(true);
}
if(rig.hasSpecifyMainSubCmd)
{
ui->setRptrSubVFOBtn->setEnabled(true);
ui->setToneSubVFOBtn->setEnabled(true);
ui->setSplitRptrToneChk->setEnabled(true);
} else {
ui->setRptrSubVFOBtn->setDisabled(true);
ui->setToneSubVFOBtn->setDisabled(true);
ui->setSplitRptrToneChk->setDisabled(true);
}
ui->rptAutoBtn->setEnabled(rig.hasRepeaterModes);
ui->rptDupMinusBtn->setEnabled(rig.hasRepeaterModes);
ui->rptDupPlusBtn->setEnabled(rig.hasRepeaterModes);
ui->rptSimplexBtn->setEnabled(rig.hasRepeaterModes);
ui->rptrOffsetEdit->setEnabled(rig.hasRepeaterModes);
ui->rptrOffsetSetBtn->setEnabled(rig.hasRepeaterModes);
ui->setToneSubVFOBtn->setEnabled(rig.hasSpecifyMainSubCmd);
ui->setRptrSubVFOBtn->setEnabled(rig.hasSpecifyMainSubCmd);
ui->quickSplitChk->setVisible(rig.hasQuickSplitCommand);
}
void repeaterSetup::populateTones()
@ -235,44 +276,81 @@ void repeaterSetup::populateDTCS()
void repeaterSetup::receiveDuplexMode(duplexMode dm)
{
currentdm = dm;
ui->splitEnableChk->blockSignals(true);
switch(dm)
{
case dmSimplex:
case dmSplitOff:
ui->splitOffBtn->setChecked(true);
ui->autoTrackLiveBtn->setDisabled(true);
break;
case dmSplitOn:
ui->splitEnableChk->setChecked(true);
ui->rptSimplexBtn->setChecked(false);
ui->rptDupPlusBtn->setChecked(false);
ui->autoTrackLiveBtn->setEnabled(true);
ui->rptDupMinusBtn->setChecked(false);
break;
case dmSimplex:
ui->rptSimplexBtn->setChecked(true);
//ui->splitEnableChk->setChecked(false);
ui->autoTrackLiveBtn->setDisabled(true);
break;
case dmDupPlus:
ui->rptDupPlusBtn->setChecked(true);
//ui->splitEnableChk->setChecked(false);
ui->autoTrackLiveBtn->setDisabled(true);
break;
case dmDupMinus:
ui->rptDupMinusBtn->setChecked(true);
//ui->splitEnableChk->setChecked(false);
ui->autoTrackLiveBtn->setDisabled(true);
break;
default:
qDebug() << "Did not understand duplex/split/repeater value of " << (unsigned char)dm;
break;
}
ui->splitEnableChk->blockSignals(false);
}
void repeaterSetup::handleRptAccessMode(rptAccessTxRx tmode)
{
// ratrXY
// X = Transmit (T)one or (N)one or (D)CS
// Y = Receive (T)sql or (N)one or (D)CS
switch(tmode)
{
case ratrNN:
ui->toneNone->setChecked(true);
break;
case ratrTT:
ui->toneTSQL->setChecked(true);
break;
case ratrTN:
ui->toneTone->setChecked(true);
break;
case ratrDD:
ui->toneDTCS->setChecked(true);
break;
default:
break;
case ratrNN:
ui->toneNone->setChecked(true);
break;
case ratrTT:
case ratrNT:
ui->toneTSQL->setChecked(true);
break;
case ratrTN:
ui->toneTone->setChecked(true);
break;
case ratrDD:
ui->toneDTCS->setChecked(true);
break;
case ratrTONEoff:
ui->toneTone->setChecked(false);
break;
case ratrTONEon:
ui->toneTone->setChecked(true);
break;
case ratrTSQLoff:
ui->toneTSQL->setChecked(false);
break;
case ratrTSQLon:
ui->toneTSQL->setChecked(true);
break;
default:
break;
}
if( !ui->toneTSQL->isChecked() && !ui->toneTone->isChecked() && !ui->toneDTCS->isChecked())
{
ui->toneNone->setChecked(true);
}
(void)tmode;
}
void repeaterSetup::handleTone(quint16 tone)
@ -296,11 +374,112 @@ void repeaterSetup::handleDTCS(quint16 dcode, bool tinv, bool rinv)
ui->rptDTCSInvertRx->setChecked(rinv);
}
void repeaterSetup::handleUpdateCurrentMainFrequency(freqt mainfreq)
{
if(amTransmitting)
return;
// Track if autoTrack enabled, split enabled, and there's a split defined.
if(ui->autoTrackLiveBtn->isChecked() && (currentdm == dmSplitOn) && !ui->splitOffsetEdit->text().isEmpty())
{
if(currentMainFrequency.Hz != mainfreq.Hz)
{
this->currentMainFrequency = mainfreq;
if(!ui->splitTransmitFreqEdit->hasFocus())
{
if(usedPlusSplit)
{
on_splitPlusButton_clicked();
} else {
on_splitMinusBtn_clicked();
}
}
}
if(ui->setSplitRptrToneChk->isChecked())
{
// TODO, not really needed if the op
// just sets the tone when needed, as it will do both bands.
}
}
this->currentMainFrequency = mainfreq;
}
void repeaterSetup::handleUpdateCurrentMainMode(mode_info m)
{
// Used to set the secondary VFO to the same mode
// (generally FM)
// NB: We don't accept values during transmit as they
// may represent the inactive VFO
if(!amTransmitting)
{
this->currentModeMain = m;
this->modeTransmitVFO = m;
this->modeTransmitVFO.VFO = inactiveVFO;
if(m.mk == modeFM)
ui->warningFMLabel->setVisible(false);
else
ui->warningFMLabel->setVisible(true);
}
}
void repeaterSetup::handleRptOffsetFrequency(freqt f)
{
// Called when a new offset is available from the radio.
QString offsetstr = QString::number(f.Hz / double(1E6), 'f', 4);
if(!ui->rptrOffsetEdit->hasFocus())
{
ui->rptrOffsetEdit->setText(offsetstr);
currentOffset = f;
}
}
void repeaterSetup::handleTransmitStatus(bool amTransmitting)
{
this->amTransmitting = amTransmitting;
}
void repeaterSetup::showEvent(QShowEvent *event)
{
emit getDuplexMode();
emit getSplitModeEnabled();
if(rig.hasRepeaterModes)
emit getRptDuplexOffset();
QMainWindow::showEvent(event);
(void)event;
}
void repeaterSetup::on_splitEnableChk_clicked()
{
emit setDuplexMode(dmSplitOn);
ui->autoTrackLiveBtn->setEnabled(true);
if(ui->autoTrackLiveBtn->isChecked() && !ui->splitOffsetEdit->text().isEmpty())
{
if(usedPlusSplit)
{
on_splitPlusButton_clicked();
} else {
on_splitMinusBtn_clicked();
}
}
}
void repeaterSetup::on_splitOffBtn_clicked()
{
emit setDuplexMode(dmSplitOff);
ui->autoTrackLiveBtn->setDisabled(true);
}
void repeaterSetup::on_rptSimplexBtn_clicked()
{
// Simplex
emit setDuplexMode(dmDupAutoOff);
emit setDuplexMode(dmSimplex);
emit setDuplexMode(dmSplitOff);
if(rig.hasRepeaterModes)
{
emit setDuplexMode(dmDupAutoOff);
emit setDuplexMode(dmSimplex);
}
}
void repeaterSetup::on_rptDupPlusBtn_clicked()
@ -324,20 +503,29 @@ void repeaterSetup::on_rptAutoBtn_clicked()
emit setDuplexMode(dmDupAutoOn);
}
void repeaterSetup::on_rptReadRigBtn_clicked()
{
emit getDuplexMode();
}
void repeaterSetup::on_rptToneCombo_activated(int tindex)
{
quint16 tone=0;
tone = (quint16)ui->rptToneCombo->itemData(tindex).toUInt();
rptrTone_t rt;
rt.tone = tone;
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
if(ui->toneTone->isChecked())
{
emit setTone(tone);
emit setTone(rt);
if(updateSub)
{
rt.useSecondaryVFO = true;
emit setTone(rt);
}
} else if (ui->toneTSQL->isChecked()) {
emit setTSQL(tone);
emit setTSQL(rt);
if(updateSub)
{
rt.useSecondaryVFO = true;
emit setTone(rt);
}
}
}
@ -353,45 +541,304 @@ void repeaterSetup::on_rptDTCSCombo_activated(int index)
void repeaterSetup::on_toneNone_clicked()
{
rptAccessTxRx rm;
rptrAccessData_t rd;
rm = ratrNN;
emit setRptAccessMode(rm);
rd.accessMode = rm;
emit setRptAccessMode(rd);
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
if(updateSub)
{
rd.useSecondaryVFO = true;
emit setRptAccessMode(rd);
}
}
void repeaterSetup::on_toneTone_clicked()
{
rptAccessTxRx rm;
rptrAccessData_t rd;
rm = ratrTN;
emit setRptAccessMode(rm);
emit setTone((quint16)ui->rptToneCombo->currentData().toUInt());
rd.accessMode = rm;
rptrTone_t rt;
rt.tone = (quint16)ui->rptToneCombo->currentData().toUInt();
emit setRptAccessMode(rd);
emit setTone(rt);
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
if(updateSub)
{
rd.useSecondaryVFO = true;
rt.useSecondaryVFO = true;
emit setRptAccessMode(rd);
emit setTone(rt);
}
}
void repeaterSetup::on_toneTSQL_clicked()
{
rptAccessTxRx rm;
rptrAccessData_t rd;
rm = ratrTT;
emit setRptAccessMode(rm);
emit setTSQL((quint16)ui->rptToneCombo->currentData().toUInt());
rptrTone_t rt;
rt.tone = (quint16)ui->rptToneCombo->currentData().toUInt();
rd.accessMode = rm;
emit setRptAccessMode(rd);
emit setTSQL(rt);
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
if(updateSub)
{
rd.useSecondaryVFO = true;
rt.useSecondaryVFO = true;
emit setRptAccessMode(rd);
emit setTone(rt);
}
}
void repeaterSetup::on_toneDTCS_clicked()
{
rptAccessTxRx rm;
rptrAccessData_t rd;
quint16 dcode=0;
rm = ratrDD;
emit setRptAccessMode(rm);
rd.accessMode = ratrDD;
emit setRptAccessMode(rd);
bool tinv = ui->rptDTCSInvertTx->isChecked();
bool rinv = ui->rptDTCSInvertRx->isChecked();
dcode = (quint16)ui->rptDTCSCombo->currentData().toUInt();
emit setDTCS(dcode, tinv, rinv);
// TODO: DTCS with subband
}
void repeaterSetup::on_debugBtn_clicked()
quint64 repeaterSetup::getFreqHzFromKHzString(QString khz)
{
// TODO: Move these four commands to wfview's startup command list (place at the end)
//emit getTone();
//emit getTSQL();
//emit getDTCS();
emit getRptAccessMode();
// This function takes a string containing a number in KHz,
// and creates an accurate quint64 in Hz.
quint64 fhz = 0;
bool ok = true;
if(khz.isEmpty())
{
qWarning() << "KHz offset was empty!";
return fhz;
}
if(khz.contains("."))
{
// "600.245" becomes "600"
khz.chop(khz.indexOf("."));
}
fhz = 1E3 * khz.toUInt(&ok);
if(!ok)
{
qWarning() << "Could not understand user KHz text";
}
return fhz;
}
quint64 repeaterSetup::getFreqHzFromMHzString(QString MHz)
{
// This function takes a string containing a number in KHz,
// and creates an accurate quint64 in Hz.
quint64 fhz = 0;
bool ok = true;
if(MHz.isEmpty())
{
qWarning() << "MHz string was empty!";
return fhz;
}
if(MHz.contains("."))
{
int decimalPtIndex = MHz.indexOf(".");
// "29.623"
// indexOf(".") = 2
// length = 6
// We want the right 4xx 3 characters.
QString KHz = MHz.right(MHz.length() - decimalPtIndex - 1);
MHz.chop(MHz.length() - decimalPtIndex);
if(KHz.length() != 6)
{
QString zeros = QString("000000");
zeros.chop(KHz.length());
KHz.append(zeros);
}
//qInfo() << "KHz string: " << KHz;
fhz = MHz.toUInt(&ok) * 1E6; if(!ok) goto handleError;
fhz += KHz.toUInt(&ok) * 1; if(!ok) goto handleError;
//qInfo() << "Fhz: " << fhz;
} else {
// Frequency was already MHz (unlikely but what can we do?)
fhz = MHz.toUInt(&ok) * 1E6; if(!ok) goto handleError;
}
return fhz;
handleError:
qWarning() << "Could not understand user MHz text " << MHz;
return 0;
}
void repeaterSetup::on_splitPlusButton_clicked()
{
quint64 hzOffset = getFreqHzFromKHzString(ui->splitOffsetEdit->text());
quint64 txfreqhz;
freqt f;
QString txString;
if(hzOffset)
{
txfreqhz = currentMainFrequency.Hz + hzOffset;
f.Hz = txfreqhz;
f.VFO = inactiveVFO;
f.MHzDouble = f.Hz/1E6;
txString = QString::number(f.Hz / double(1E6), 'f', 6);
ui->splitTransmitFreqEdit->setText(txString);
usedPlusSplit = true;
emit setTransmitFrequency(f);
emit setTransmitMode(modeTransmitVFO);
}
}
void repeaterSetup::on_splitMinusBtn_clicked()
{
quint64 hzOffset = getFreqHzFromKHzString(ui->splitOffsetEdit->text());
quint64 txfreqhz;
freqt f;
QString txString;
if(hzOffset)
{
txfreqhz = currentMainFrequency.Hz - hzOffset;
f.Hz = txfreqhz;
f.VFO = inactiveVFO;
f.MHzDouble = f.Hz/1E6;
txString = QString::number(f.Hz / double(1E6), 'f', 6);
ui->splitTransmitFreqEdit->setText(txString);
usedPlusSplit = false;
emit setTransmitFrequency(f);
emit setTransmitMode(modeTransmitVFO);
}
}
void repeaterSetup::on_splitTxFreqSetBtn_clicked()
{
quint64 fHz = getFreqHzFromMHzString(ui->splitTransmitFreqEdit->text());
freqt f;
if(fHz)
{
f.Hz = fHz;
f.VFO = inactiveVFO;
f.MHzDouble = f.Hz/1E6;
emit setTransmitFrequency(f);
emit setTransmitMode(modeTransmitVFO);
}
}
void repeaterSetup::on_splitTransmitFreqEdit_returnPressed()
{
this->on_splitTxFreqSetBtn_clicked();
ui->splitTransmitFreqEdit->clearFocus();
}
void repeaterSetup::on_selABtn_clicked()
{
vfo_t v = vfoA;
emit selectVFO(v);
}
void repeaterSetup::on_selBBtn_clicked()
{
vfo_t v = vfoB;
emit selectVFO(v);
}
void repeaterSetup::on_aEqBBtn_clicked()
{
emit equalizeVFOsAB();
}
void repeaterSetup::on_swapABBtn_clicked()
{
emit swapVFOs();
}
void repeaterSetup::on_selMainBtn_clicked()
{
vfo_t v = vfoMain;
emit selectVFO(v);
}
void repeaterSetup::on_selSubBtn_clicked()
{
vfo_t v = vfoSub;
emit selectVFO(v);
}
void repeaterSetup::on_mEqSBtn_clicked()
{
emit equalizeVFOsMS();
}
void repeaterSetup::on_swapMSBtn_clicked()
{
emit swapVFOs();
}
void repeaterSetup::on_setToneSubVFOBtn_clicked()
{
// Perhaps not needed
// Set the secondary VFO to the selected tone
// TODO: DTCS
rptrTone_t rt;
rt.tone = (quint16)ui->rptToneCombo->currentData().toUInt();
rt.useSecondaryVFO = true;
emit setTone(rt);
}
void repeaterSetup::on_setRptrSubVFOBtn_clicked()
{
// Perhaps not needed
// Set the secondary VFO to the selected repeater mode
rptrAccessData_t rd;
rd.useSecondaryVFO = true;
if(ui->toneTone->isChecked())
rd.accessMode=ratrTN;
if(ui->toneNone->isChecked())
rd.accessMode=ratrNN;
if(ui->toneTSQL->isChecked())
rd.accessMode=ratrTT;
if(ui->toneDTCS->isChecked())
rd.accessMode=ratrDD;
emit setRptAccessMode(rd);
}
void repeaterSetup::on_rptrOffsetSetBtn_clicked()
{
freqt f;
f.Hz = getFreqHzFromMHzString(ui->rptrOffsetEdit->text());
f.MHzDouble = f.Hz/1E6;
f.VFO=activeVFO;
if(f.Hz != 0)
{
emit setRptDuplexOffset(f);
}
ui->rptrOffsetEdit->clearFocus();
}
void repeaterSetup::on_rptrOffsetEdit_returnPressed()
{
this->on_rptrOffsetSetBtn_clicked();
}
void repeaterSetup::on_setSplitRptrToneChk_clicked(bool checked)
{
if(checked)
{
on_setRptrSubVFOBtn_clicked();
on_setToneSubVFOBtn_clicked();
}
}
void repeaterSetup::on_quickSplitChk_clicked(bool checked)
{
emit setQuickSplit(checked);
}

Wyświetl plik

@ -23,14 +23,29 @@ public:
signals:
void getDuplexMode();
void setDuplexMode(duplexMode dm);
void setTone(quint16 tone);
void setTSQL(quint16 tsql);
void setTone(rptrTone_t tone);
void setTSQL(rptrTone_t tsql);
void setDTCS(quint16 dcode, bool tinv, bool rinv);
void getTone();
void getTSQL();
void getDTCS();
void setRptAccessMode(rptAccessTxRx tmode);
void setRptAccessMode(rptrAccessData_t rd);
void getRptAccessMode();
void setRptDuplexOffset(freqt f);
void getRptDuplexOffset();
// Split:
void getSplitModeEnabled();
void setQuickSplit(bool qsOn);
void getTransmitFrequency();
// Use the duplexMode to communicate split.
// void setSplitModeEnabled(bool splitEnabled);
void setTransmitFrequency(freqt transmitFreq);
void setTransmitMode(mode_info m);
// VFO:
void selectVFO(vfo_t v); // A,B,M,S
void equalizeVFOsAB();
void equalizeVFOsMS();
void swapVFOs();
public slots:
void receiveDuplexMode(duplexMode dm);
@ -38,29 +53,80 @@ public slots:
void handleTone(quint16 tone);
void handleTSQL(quint16 tsql);
void handleDTCS(quint16 dcscode, bool tinv, bool rinv);
// void handleSplitMode(bool splitEnabled);
// void handleSplitFrequency(freqt transmitFreq);
void handleUpdateCurrentMainFrequency(freqt mainfreq);
void handleUpdateCurrentMainMode(mode_info m);
void handleTransmitStatus(bool amTransmitting);
void handleRptOffsetFrequency(freqt f);
private slots:
void showEvent(QShowEvent *event);
void on_rptSimplexBtn_clicked();
void on_rptDupPlusBtn_clicked();
void on_rptDupMinusBtn_clicked();
void on_rptAutoBtn_clicked();
void on_rptReadRigBtn_clicked();
void on_rptToneCombo_activated(int index);
void on_rptDTCSCombo_activated(int index);
void on_debugBtn_clicked();
void on_toneNone_clicked();
void on_toneTone_clicked();
void on_toneTSQL_clicked();
void on_toneDTCS_clicked();
void on_toneDTCS_clicked();
void on_splitPlusButton_clicked();
void on_splitMinusBtn_clicked();
void on_splitTxFreqSetBtn_clicked();
void on_selABtn_clicked();
void on_selBBtn_clicked();
void on_aEqBBtn_clicked();
void on_swapABBtn_clicked();
void on_selMainBtn_clicked();
void on_selSubBtn_clicked();
void on_mEqSBtn_clicked();
void on_swapMSBtn_clicked();
void on_setToneSubVFOBtn_clicked();
void on_setRptrSubVFOBtn_clicked();
void on_rptrOffsetSetBtn_clicked();
void on_splitOffBtn_clicked();
void on_splitEnableChk_clicked();
void on_rptrOffsetEdit_returnPressed();
void on_splitTransmitFreqEdit_returnPressed();
void on_setSplitRptrToneChk_clicked(bool checked);
void on_quickSplitChk_clicked(bool checked);
private:
Ui::repeaterSetup *ui;
freqt currentMainFrequency;
void populateTones();
void populateDTCS();
quint64 getFreqHzFromKHzString(QString khz);
quint64 getFreqHzFromMHzString(QString MHz);
rigCapabilities rig;
bool haveRig = false;
duplexMode currentdm;
mode_info currentModeMain;
mode_info modeTransmitVFO;
freqt currentOffset;
bool usedPlusSplit = false;
bool amTransmitting = false;
};
#endif // REPEATERSETUP_H

Wyświetl plik

@ -6,62 +6,27 @@
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>217</height>
<width>1071</width>
<height>231</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>1071</width>
<height>230</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>1071</width>
<height>231</height>
</size>
</property>
<property name="windowTitle">
<string>Repeater Setup</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="rptReadRigBtn">
<property name="text">
<string>Read Current Settings</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="debugBtn">
<property name="text">
<string>Debug</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
@ -71,7 +36,13 @@
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<widget class="QGroupBox" name="rptGrpbox">
<property name="maximumSize">
<size>
<width>180</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Repeater Duplex</string>
</property>
@ -116,15 +87,328 @@
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QPushButton" name="rptrOffsetSetBtn">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the repeater offset for radios using Repeater modes. Only available on radios that have repeater modes. Radios using Split should instead use the provided Split Mode section with a custom Offset. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Set Offset (MHz):</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLineEdit" name="rptrOffsetEdit">
<property name="placeholderText">
<string>Rpt Offset (MHz)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="splitModeGrpbox">
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Split Mode</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QRadioButton" name="splitEnableChk">
<property name="toolTip">
<string>Turn on Split</string>
</property>
<property name="text">
<string>Split On</string>
</property>
<attribute name="buttonGroup">
<string notr="true">rptDuplexBtns</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="splitOffBtn">
<property name="toolTip">
<string>Turn off Split</string>
</property>
<property name="text">
<string>Split Off</string>
</property>
<attribute name="buttonGroup">
<string notr="true">rptDuplexBtns</string>
</attribute>
</widget>
</item>
<item>
<widget class="QCheckBox" name="quickSplitChk">
<property name="text">
<string>QuickSplit</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QCheckBox" name="setSplitRptrToneChk">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Click here to automatically set the sub VFO (transmit VFO) tone. Only available on some radios. Other radios may take care of this for you.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Set Rpt Tone</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoTrackLiveBtn">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Click here to continually set the transmit VFO to match the receive VFO with the offset accounted for. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>AutoTrack</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Offset (KHz):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="splitOffsetEdit">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Enter the desired split offset in KHz.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="splitPlusButton">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the transmit frequency to the receive frequency PLUS the offset. Sets the radio sub VFO and also populates the wfview text box (as a convenience). &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Split+</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="splitMinusBtn">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the transmit frequency to the receive frequency PLUS the offset. Sets the radio sub VFO and also populates the wfview text box (as a convenience). &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Split-</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Tx Freq (MHz):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="splitTransmitFreqEdit">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="splitTxFreqSetBtn">
<property name="maximumSize">
<size>
<width>116</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the transmit frequency manually. Not needed if the Split+ or Split- button was used. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Set</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="maximumSize">
<size>
<width>220</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>VFO</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QPushButton" name="swapABBtn">
<property name="toolTip">
<string>Swap VFO A with VFO B. Some radios do not support this.</string>
</property>
<property name="text">
<string>Swap AB</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="selSubBtn">
<property name="toolTip">
<string>Select the Sub VFO</string>
</property>
<property name="text">
<string>Sel Sub</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="selMainBtn">
<property name="toolTip">
<string>Select the Main VFO</string>
</property>
<property name="text">
<string>Sel Main</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="selBBtn">
<property name="toolTip">
<string>Select VFO B</string>
</property>
<property name="text">
<string>Sel B</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="selABtn">
<property name="toolTip">
<string>Select VFO A</string>
</property>
<property name="text">
<string>Sel A</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="aEqBBtn">
<property name="toolTip">
<string>Set VFO B to VFO A</string>
</property>
<property name="text">
<string>A=B</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="mEqSBtn">
<property name="toolTip">
<string>Set the SUB VFO to match the Main VFO</string>
</property>
<property name="text">
<string>M=&gt;S</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="swapMSBtn">
<property name="toolTip">
<string>Swap the Main VFO and Sub VFO</string>
</property>
<property name="text">
<string>Swap MS</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Repeater Tone Type</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="warningFMLabel">
<property name="text">
<string>Only available in FM</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="toneNone">
<property name="text">
@ -165,11 +449,27 @@
</attribute>
</widget>
</item>
<item>
<widget class="QPushButton" name="setRptrSubVFOBtn">
<property name="toolTip">
<string>Set the Tone Mode for the Sub VFO. Not available on all radios.</string>
</property>
<property name="text">
<string>Set Sub VFO</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Tone Selection</string>
</property>
@ -220,6 +520,16 @@
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="setToneSubVFOBtn">
<property name="toolTip">
<string>Set the Sub VFO to the selected Tone. Not available on all radios and not available for DTCS.</string>
</property>
<property name="text">
<string>Set Sub VFO</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

Wyświetl plik

@ -96,15 +96,15 @@ static void speex_free(void* ptr) { free(ptr); }
#define UINT32_MAX 4294967295U
#endif
#ifdef USE_SSE
#if defined(USE_SSE) && !defined(__aarch64__)
#include "resample_sse.h"
#endif
#ifdef USE_NEON
#if defined(USE_NEON) || defined(__aarch64__)
#include "resample_neon.h"
#endif
/* Numer of elements to allocate on the stack */
/* Number of elements to allocate on the stack */
#ifdef VAR_ARRAYS
#define FIXED_STACK_ALLOC 8192
#else
@ -294,7 +294,7 @@ static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef* win
else if (fabs(x) > .5 * N)
return 0;
/*FIXME: Can it really be any slower than this? */
return cutoff * sin(M_PI * xx) / (M_PI * xx) * compute_func(fabs(2. * x / N), window_func);
return (spx_word16_t)(cutoff * (float)(sin(M_PI * xx) / (M_PI * xx) * compute_func((float)fabs(2. * x / N), window_func)));
}
#endif
@ -324,7 +324,7 @@ static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
interp[3] = -0.33333f * frac + 0.5f * frac * frac - 0.16667f * frac * frac * frac;
/* Just to make sure we don't have rounding problems */
interp[2] = 1. - interp[0] - interp[1] - interp[3];
interp[2] = (spx_word16_t) (1. - interp[0] - interp[1] - interp[3]);
}
#endif
@ -419,7 +419,7 @@ static int resampler_basic_direct_double(SpeexResamplerState* st, spx_uint32_t c
sum = inner_product_double(sinct, iptr, N);
#endif
out[out_stride * out_sample++] = PSHR32(sum, 15);
out[out_stride * out_sample++] = (spx_word16_t)PSHR32(sum, 15);
last_sample += int_advance;
samp_frac_num += frac_advance;
if (samp_frac_num >= den_rate)
@ -539,7 +539,7 @@ static int resampler_basic_interpolate_double(SpeexResamplerState* st, spx_uint3
sum = MULT16_32_Q15(interp[0], accum[0]) + MULT16_32_Q15(interp[1], accum[1]) + MULT16_32_Q15(interp[2], accum[2]) + MULT16_32_Q15(interp[3], accum[3]);
#else
cubic_coef(frac, interp);
sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
sum = (spx_word16_t)interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
#endif
out[out_stride * out_sample++] = PSHR32(sum, 15);
@ -673,7 +673,7 @@ static int update_filter(SpeexResamplerState* st)
for (i = 0; i < st->den_rate; i++)
{
spx_int32_t j;
for (j = 0; j < st->filt_len; j++)
for (j = 0; j < (spx_int32_t)st->filt_len; j++)
{
st->sinc_table[i * st->filt_len + j] = sinc(st->cutoff, ((j - (spx_int32_t)st->filt_len / 2 + 1) - ((float)i) / st->den_rate), st->filt_len, quality_map[st->quality].window_func);
}
@ -710,7 +710,7 @@ static int update_filter(SpeexResamplerState* st)
/* Adding buffer_size to filt_len won't overflow here because filt_len
could be multiplied by sizeof(spx_word16_t) above. */
min_alloc_size = st->filt_len - 1 + st->buffer_size;
if (min_alloc_size > st->mem_alloc_size)
if (min_alloc_size > st->mem_alloc_size && st->nb_channels>0)
{
spx_word16_t* mem;
if (INT_MAX / sizeof(spx_word16_t) / st->nb_channels < min_alloc_size)
@ -934,7 +934,7 @@ EXPORT int speex_resampler_process_int(SpeexResamplerState* st, spx_uint32_t cha
EXPORT int speex_resampler_process_float(SpeexResamplerState* st, spx_uint32_t channel_index, const float* in, spx_uint32_t* in_len, float* out, spx_uint32_t* out_len)
#endif
{
int j;
spx_uint32_t j;
spx_uint32_t ilen = *in_len;
spx_uint32_t olen = *out_len;
spx_word16_t* x = st->mem + channel_index * st->mem_alloc_size;
@ -976,7 +976,7 @@ EXPORT int speex_resampler_process_float(SpeexResamplerState* st, spx_uint32_t c
EXPORT int speex_resampler_process_int(SpeexResamplerState* st, spx_uint32_t channel_index, const spx_int16_t* in, spx_uint32_t* in_len, spx_int16_t* out, spx_uint32_t* out_len)
#endif
{
int j;
spx_uint32_t j;
const int istride_save = st->in_stride;
const int ostride_save = st->out_stride;
spx_uint32_t ilen = *in_len;
@ -1246,4 +1246,4 @@ EXPORT const char* speex_resampler_strerror(int err)
default:
return "Unknown error. Bad error code or strange version mismatch.";
}
}
}

Wyświetl plik

@ -39,7 +39,7 @@
#define OVERRIDE_INNER_PRODUCT_SINGLE
static inline float inner_product_single(const float* a, const float* b, unsigned int len)
{
int i;
unsigned int i;
float ret;
__m128 sum = _mm_setzero_ps();
for (i = 0; i < len; i += 8)
@ -55,7 +55,7 @@ static inline float inner_product_single(const float* a, const float* b, unsigne
#define OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
static inline float interpolate_product_single(const float* a, const float* b, unsigned int len, const spx_uint32_t oversample, float* frac) {
int i;
unsigned int i;
float ret;
__m128 sum = _mm_setzero_ps();
__m128 f = _mm_loadu_ps(frac);
@ -71,13 +71,13 @@ static inline float interpolate_product_single(const float* a, const float* b, u
return ret;
}
#ifdef USE_SSE2
#if defined(USE_SSE2) && !defined(__aarch64__)
#include <emmintrin.h>
#define OVERRIDE_INNER_PRODUCT_DOUBLE
static inline double inner_product_double(const float* a, const float* b, unsigned int len)
{
int i;
unsigned int i;
double ret;
__m128d sum = _mm_setzero_pd();
__m128 t;
@ -98,7 +98,7 @@ static inline double inner_product_double(const float* a, const float* b, unsign
#define OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
static inline double interpolate_product_double(const float* a, const float* b, unsigned int len, const spx_uint32_t oversample, float* frac) {
int i;
unsigned int i;
double ret;
__m128d sum;
__m128d sum1 = _mm_setzero_pd();
@ -125,4 +125,4 @@ static inline double interpolate_product_double(const float* a, const float* b,
return ret;
}
#endif
#endif

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 321 KiB

Wyświetl plik

@ -1,10 +1,11 @@
#!/bin/bash
echo "This script copies the following items into your system:"
echo ""
echo "icon: wfview.png to /usr/share/pixmaps/"
echo "icon: unix_icons/wfview.png to /usr/share/icons/hicolor/256x256/apps/"
echo "wfview application to /usr/local/bin/"
echo "wfview.desktop to /usr/share/applications/"
echo "qdarkstyle stylesheet to /usr/share/wfview/stylesheets"
echo "org.wfview.wfview.metainfo.xml metadata file to /usr/share/metainfo/"
echo "qdarkstyle stylesheet to /usr/share/wfview/stylesheets/"
echo ""
echo "This script MUST be run from the build directory. Do not run it from the source directory!"
@ -30,7 +31,8 @@ echo ""
cp wfview /usr/local/bin/wfview
cp wfview.desktop /usr/share/applications/
cp wfview.png /usr/share/pixmaps/
cp unix_icons/wfview.png /usr/share/icons/hicolor/256x256/apps/
cp org.wfview.wfview.metainfo.xml /usr/share/metainfo/
mkdir -p /usr/share/wfview/stylesheets
cp -r qdarkstyle /usr/share/wfview/stylesheets/

Wyświetl plik

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>org.wfview.wfview</id>
<launchable type="desktop-id">wfview.desktop</launchable>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<name>wfview</name>
<developer_name>Elliott H. Liggett</developer_name>
<summary>Open Source interface for Icom transceivers</summary>
<description>
<p>
wfview is a program developed by amateur radio enthusiasts to control modern Icom ham radios. It provides the user with controls
that may be comfortably operated from a keyboard, mouse, or touch screen interface. wfview is free and open source software.
</p>
<p>
wfview has been developed with an eye towards compatibility. Even though our target platform consists of modern-era transceivers,
wfviews command dictionary is focused on commands with the most compatibility. Many of Icoms transceivers from the last 20 years
will work to some degree with wfview, and we are always adding more.
</p>
</description>
<screenshots>
<screenshot type="default">
<image type="source">https://wfview.org/wp-content/uploads/2021/11/7300-remote-screenshot.png</image>
</screenshot>
</screenshots>
<url type="homepage">https://wfview.org</url>
<url type="bugtracker">https://gitlab.com/eliggett/wfview/-/issues</url>
<content_rating type="oars-1.1"/>
</component>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 113 KiB

BIN
resources/rc28.png 100644

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 106 KiB

Wyświetl plik

@ -1,5 +1,16 @@
<RCC>
<qresource prefix="resources">
<file>wfview.png</file>
</qresource>
<qresource prefix="/resources">
<file>wfview.png</file>
<file>shuttlexpress.png</file>
<file>shuttlepro.png</file>
<file>rc28.png</file>
<file>ecoder.png</file>
<file>quickkeys.png</file>
<file>xbox.png</file>
<file>streamdeck.png</file>
<file>streamdeckmini.png</file>
<file>streamdeckxl.png</file>
<file>streamdeckpedal.png</file>
<file>streamdeckplus.png</file>
</qresource>
</RCC>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 185 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 428 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 179 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 331 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 396 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 217 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 412 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 53 KiB

Wyświetl plik

@ -18,5 +18,7 @@
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
</dict>
</plist>

BIN
resources/xbox.png 100644

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 240 KiB

Plik diff jest za duży Load Diff

Wyświetl plik

@ -2,14 +2,19 @@
#define RIGCOMMANDER_H
#include <QObject>
#include <QMutexLocker>
#include <QDebug>
#include "wfviewtypes.h"
#include "commhandler.h"
#include "pttyhandler.h"
#include "udphandler.h"
#include "rigidentities.h"
#include "repeaterattributes.h"
#include "freqmemory.h"
#include "tcpserver.h"
#include "rigstate.h"
// This file figures out what to send to the comm and also
// parses returns into useful things.
@ -18,78 +23,26 @@
// note: using a define because switch case doesn't even work with const unsigned char. Surprised me.
#define compCivAddr 0xE1
enum meterKind {
meterS,
meterSWR,
meterPower,
meterALC,
meterComp,
meterVoltage,
meterCurrent
};
enum spectrumMode {
spectModeCenter=0x00,
spectModeFixed=0x01,
spectModeScrollC=0x02,
spectModeScrollF=0x03,
spectModeUnknown=0xff
};
struct freqt {
quint64 Hz;
double MHzDouble;
};
struct rigStateStruct {
freqt vfoAFreq;
freqt vfoBFreq;
unsigned char ptt;
unsigned char mode;
unsigned char filter;
bool datamode;
// Tones
quint16 ctcss;
quint16 tsql;
quint16 dtcs;
quint16 csql;
// Levels
unsigned char preamp;
unsigned char modInput;
unsigned char afGain;
unsigned char rfGain;
unsigned char squelch;
unsigned char txPower;
unsigned char micGain;
unsigned char compLevel;
unsigned char monitorLevel;
unsigned char voxGain;
unsigned char antiVoxGain;
// Meters
unsigned char sMeter;
unsigned char powerMeter;
unsigned char swrMeter;
unsigned char alcMeter;
unsigned char compMeter;
unsigned char voltageMeter;
unsigned char currentMeter;
};
class rigCommander : public QObject
{
Q_OBJECT
public:
rigCommander();
explicit rigCommander(QObject* parent=nullptr);
explicit rigCommander(quint8 guid[GUIDLEN], QObject* parent = nullptr);
~rigCommander();
bool usingLAN();
quint8* getGUID();
public slots:
void process();
void commSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate,QString vsp);
void commSetup(unsigned char rigCivAddr, udpPreferences prefs, audioSetup rxSetup, audioSetup txSetup, QString vsp);
void commSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate, QString vsp, quint16 tcp, quint8 wf);
void commSetup(unsigned char rigCivAddr, udpPreferences prefs, audioSetup rxSetup, audioSetup txSetup, QString vsp, quint16 tcp);
void closeComm();
void stateUpdated();
void setRTSforPTT(bool enabled);
// Power:
void powerOn();
@ -116,22 +69,32 @@ public slots:
void getScopeMode();
// Frequency, Mode, BSR:
void setFrequency(freqt freq);
void setFrequency(unsigned char vfo, freqt freq);
void getFrequency(unsigned char vfo);
void getFrequency();
void selectVFO(vfo_t vfo);
void equalizeVFOsAB();
void equalizeVFOsMS();
void exchangeVFOs();
void setMode(unsigned char mode, unsigned char modeFilter);
void setMode(mode_info);
void getMode();
void setDataMode(bool dataOn, unsigned char filter);
void getDataMode();
void getSplit();
void setSplit(bool splitEnabled);
void getBandStackReg(char band, char regCode);
void getRitEnabled();
void getRitValue();
void setRitValue(int ritValue);
void setRitEnable(bool ritEnabled);
void setPassband(quint16 pass);
// PTT, ATU, ATT, Antenna, and Preamp:
void getPTT();
void setPTT(bool pttOn);
void sendCW(QString textToSend);
void sendStopCW();
void startATU();
void setATU(bool enabled);
void getATUStatus();
@ -140,30 +103,72 @@ public slots:
void getAntenna();
void setAttenuator(unsigned char att);
void setPreamp(unsigned char pre);
void setAntenna(unsigned char ant);
void setAntenna(unsigned char ant, bool rx);
void setNB(bool enabled);
void getNB();
void setNR(bool enabled);
void getNR();
void setAutoNotch(bool enabled);
void getAutoNotch();
void setToneEnabled(bool enabled);
void getToneEnabled();
void setToneSql(bool enabled);
void getToneSqlEnabled();
void setCompressor(bool enabled);
void getCompressor();
void setMonitor(bool enabled);
void getMonitor();
void setVox(bool enabled);
void getVox();
void setBreakIn(unsigned char type);
void getBreakIn();
void setKeySpeed(unsigned char wpm);
void getKeySpeed();
void setManualNotch(bool enabled);
void getManualNotch();
void getPassband();
void getNBLevel();
void getNRLevel(); void getCwPitch();
void setCwPitch(unsigned char pitch);
void getDashRatio();
void setDashRatio(unsigned char ratio);
void getPskTone();
void setPskTone(unsigned char tone);
void getRttyMark();
void setRttyMark(unsigned char mark);
// Repeater:
void setDuplexMode(duplexMode dm);
void getDuplexMode();
void setQuickSplit(bool qsOn);
void getTransmitFrequency();
void setTone(quint16 tone);
void setTSQL(quint16 tsql);
void setTone(rptrTone_t t);
void setTSQL(rptrTone_t t);
void setTone(quint16 t);
void setTSQL(quint16 t);
void getTSQL();
void getTone();
void setDTCS(quint16 dcscode, bool tinv, bool rinv);
void getDTCS();
void setRptAccessMode(rptAccessTxRx ratr);
void setRptAccessMode(rptrAccessData_t ratr);
void getRptAccessMode();
void setRptDuplexOffset(freqt f);
void getRptDuplexOffset();
// Get Levels:
void getLevels(); // all supported levels
void getRfGain();
void getAfGain();
void getSql();
void getIFShift();
void getTPBFInner();
void getTPBFOuter();
void getTxLevel();
void getMicGain();
void getCompLevel();
void getMonitorLevel();
void getMonitorGain();
void getVoxGain();
void getAntiVoxGain();
void getUSBGain();
@ -172,11 +177,16 @@ public slots:
void getACCGain(unsigned char ab);
void getModInput(bool dataOn);
void getModInputLevel(rigInput input);
void getAfMute();
void getDialLock();
// Set Levels:
void setSquelch(unsigned char level);
void setRfGain(unsigned char level);
void setAfGain(unsigned char level);
void setIFShift(unsigned char level);
void setTPBFInner(unsigned char level);
void setTPBFOuter(unsigned char level);
void setTxPower(unsigned char power);
void setMicGain(unsigned char gain);
void setUSBGain(unsigned char gain);
@ -184,11 +194,15 @@ public slots:
void setACCGain(unsigned char gain);
void setACCGain(unsigned char gain, unsigned char ab);
void setCompLevel(unsigned char compLevel);
void setMonitorLevel(unsigned char monitorLevel);
void setMonitorGain(unsigned char monitorLevel);
void setVoxGain(unsigned char gain);
void setAntiVoxGain(unsigned char gain);
void setModInput(rigInput input, bool dataOn);
void setModInputLevel(rigInput input, unsigned char level);
void setAfMute(bool muteOn);
void setDialLock(bool lockOn);
void setNBLevel(unsigned char level);
void setNRLevel(unsigned char level);
// NB, NR, IP+:
void setIPP(bool enabled);
@ -207,6 +221,7 @@ public slots:
// Meters:
void getSMeter();
void getCenterMeter();
void getRFPowerMeter();
void getSWRMeter();
void getALCMeter();
@ -218,6 +233,7 @@ public slots:
// Rig ID and CIV:
void getRigID();
void findRigs();
void setRigID(unsigned char rigID);
void setCIVAddr(unsigned char civAddr);
// Calibration:
@ -226,6 +242,12 @@ public slots:
void setRefAdjustCourse(unsigned char level);
void setRefAdjustFine(unsigned char level);
// Time and Date:
void setTime(timekind t);
void setDate(datekind d);
void setUTCOffset(timekind t);
// Satellite:
void setSatelliteMode(bool enabled);
void getSatelliteMode();
@ -233,7 +255,7 @@ public slots:
// UDP:
void handleNewData(const QByteArray& data);
void receiveAudioData(const audioPacket& data);
void handleSerialPortError(const QString port, const QString errorText);
void handlePortError(errorType err);
void changeLatency(const quint16 value);
void dataFromServer(QByteArray data);
void receiveBaudRate(quint32 baudrate);
@ -244,15 +266,22 @@ public slots:
void sayAll();
// Housekeeping:
void handleStatusUpdate(const QString text);
void handleStatusUpdate(const networkStatus status);
void handleNetworkAudioLevels(networkAudioLevels);
void radioSelection(QList<radio_cap_packet> radios);
void radioUsage(quint8 radio, quint8 busy, QString name, QString ip);
void setCurrentRadio(quint8 radio);
void sendState();
void getDebug();
signals:
// Communication:
void commReady();
void haveSerialPortError(const QString port, const QString errorText);
void haveStatusUpdate(const QString text);
void havePortError(errorType err);
void haveStatusUpdate(const networkStatus status);
void haveNetworkAudioLevels(const networkAudioLevels l);
void dataForComm(const QByteArray &outData);
void toggleRTS(bool rtsOn);
// UDP:
void haveChangeLatency(quint16 value);
@ -269,6 +298,7 @@ signals:
void haveSpectrumMode(spectrumMode spectmode);
void haveScopeEdge(char edge);
void haveSpectrumRefLevel(int level);
void haveScopeOutOfRange(bool outOfRange);
// Rig ID:
void haveRigID(rigCapabilities rigCaps);
@ -281,6 +311,10 @@ signals:
void haveBandStackReg(freqt f, char mode, char filter, bool dataOn);
void haveRitEnabled(bool ritEnabled);
void haveRitFrequency(int ritHz);
void havePassband(quint16 pass);
void haveCwPitch(unsigned char pitch);
void havePskTone(unsigned char tone);
void haveRttyMark(unsigned char mark);
// Repeater:
void haveDuplexMode(duplexMode);
@ -288,17 +322,28 @@ signals:
void haveTone(quint16 tone);
void haveTSQL(quint16 tsql);
void haveDTCS(quint16 dcscode, bool tinv, bool rinv);
void haveRptOffsetFrequency(freqt f);
// Levels:
void haveRfGain(unsigned char level);
void haveAfGain(unsigned char level);
void haveSql(unsigned char level);
void haveTPBFInner(unsigned char level);
void haveTPBFOuter(unsigned char level);
void haveIFShift(unsigned char level);
void haveTxPower(unsigned char level);
void haveMicGain(unsigned char level);
void haveCompLevel(unsigned char level);
void haveMonitorLevel(unsigned char level);
void haveMonitorGain(unsigned char level);
void haveVoxGain(unsigned char gain);
void haveAntiVoxGain(unsigned char gain);
void haveNBLevel(unsigned char level);
void haveNRLevel(unsigned char level);
void haveVox(bool en);
void haveMonitor(bool en);
void haveComp(bool en);
void haveNB(bool en);
void haveNR(bool en);
// Modulation source and gain:
void haveModInput(rigInput input, bool isData);
@ -326,12 +371,21 @@ signals:
void haveATUStatus(unsigned char status);
void haveAttenuator(unsigned char att);
void havePreamp(unsigned char pre);
void haveAntenna(unsigned char ant);
void haveAntenna(unsigned char ant,bool rx);
// CW:
void haveKeySpeed(unsigned char wpm);
void haveCWBreakMode(unsigned char bmode);
void haveDashRatio(unsigned char ratio);
// Rig State
void stateInfo(rigStateStruct* state);
void stateInfo(rigstate* state);
// Housekeeping:
void requestRadioSelection(QList<radio_cap_packet> radios);
void setRadioUsage(quint8 radio, quint8 busy, QString user, QString ip);
void selectedRadio(quint8 radio);
void getMoreDebug();
void finished();
@ -339,20 +393,28 @@ private:
void setup();
QByteArray stripData(const QByteArray &data, unsigned char cutPosition);
void parseData(QByteArray data); // new data come here
void parseCommand();
void parseCommand(); // Entry point for complete commands
unsigned char bcdHexToUChar(unsigned char in);
unsigned char bcdHexToUChar(unsigned char hundreds, unsigned char tensunits);
unsigned int bcdHexToUInt(unsigned char hundreds, unsigned char tensunits);
QByteArray bcdEncodeInt(unsigned int);
void parseFrequency();
freqt parseFrequency(QByteArray data, unsigned char lastPosition); // supply index where Mhz is found
freqt parseFrequencyRptOffset(QByteArray data);
QByteArray makeFreqPayloadRptOffset(freqt freq);
QByteArray makeFreqPayload(double frequency);
QByteArray makeFreqPayload(freqt freq);
QByteArray encodeTone(quint16 tone, bool tinv, bool rinv);
QByteArray encodeTone(quint16 tone);
unsigned char convertNumberToHex(unsigned char num);
quint16 decodeTone(QByteArray eTone);
quint16 decodeTone(QByteArray eTone, bool &tinv, bool &rinv);
unsigned char audioLevelRxMean[50];
unsigned char audioLevelRxPeak[50];
unsigned char audioLevelTxMean[50];
unsigned char audioLevelTxPeak[50];
void parseMode();
void parseSpectrum();
void parseWFData();
@ -382,6 +444,7 @@ private:
commHandler* comm = Q_NULLPTR;
pttyHandler* ptty = Q_NULLPTR;
tcpServer* tcp = Q_NULLPTR;
udpHandler* udp=Q_NULLPTR;
QThread* udpHandlerThread = Q_NULLPTR;
@ -402,7 +465,7 @@ private:
struct rigCapabilities rigCaps;
rigStateStruct rigState;
rigstate state;
bool haveRigCaps;
model_kind model;
@ -410,6 +473,7 @@ private:
quint16 spectAmpMax;
quint16 spectLenMax;
spectrumMode oldScopeMode;
bool wasOutOfRange = false;
bool usingNativeLAN; // indicates using OEM LAN connection (705,7610,9700,7850)
bool lookingForRig;
@ -419,6 +483,9 @@ private:
unsigned char civAddr;
unsigned char incomingCIVAddr; // place to store the incoming CIV.
bool pttAllowed;
bool useRTSforPTT_isSet = false;
bool useRTSforPTT_manual = false;
QString rigSerialPort;
quint32 rigBaudRate;
@ -431,7 +498,8 @@ private:
QString password;
QString serialPortError;
unsigned char localVolume=0;
quint8 guid[GUIDLEN] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
};

Plik diff jest za duży Load Diff

366
rigctld.h
Wyświetl plik

@ -1,3 +1,9 @@
/* This file contains portions of the Hamlib Interface - API header
* Copyright(c) 2000 - 2003 by Frank Singleton
* Copyright(c) 2000 - 2012 by Stephane Fillod
*/
#ifndef RIGCTLD_H
#define RIGCTLD_H
@ -13,13 +19,314 @@
#include <typeindex>
#include "rigcommander.h"
#include "rigstate.h"
#define CONSTANT_64BIT_FLAG(BIT) (1ull << (BIT))
#define RIG_MODE_NONE 0 /*!< '' -- None */
#define RIG_MODE_AM CONSTANT_64BIT_FLAG (0) /*!< \c AM -- Amplitude Modulation */
#define RIG_MODE_CW CONSTANT_64BIT_FLAG (1) /*!< \c CW -- CW "normal" sideband */
#define RIG_MODE_USB CONSTANT_64BIT_FLAG (2) /*!< \c USB -- Upper Side Band */
#define RIG_MODE_LSB CONSTANT_64BIT_FLAG (3) /*!< \c LSB -- Lower Side Band */
#define RIG_MODE_RTTY CONSTANT_64BIT_FLAG (4) /*!< \c RTTY -- Radio Teletype */
#define RIG_MODE_FM CONSTANT_64BIT_FLAG (5) /*!< \c FM -- "narrow" band FM */
#define RIG_MODE_WFM CONSTANT_64BIT_FLAG (6) /*!< \c WFM -- broadcast wide FM */
#define RIG_MODE_CWR CONSTANT_64BIT_FLAG (7) /*!< \c CWR -- CW "reverse" sideband */
#define RIG_MODE_RTTYR CONSTANT_64BIT_FLAG (8) /*!< \c RTTYR -- RTTY "reverse" sideband */
#define RIG_MODE_AMS CONSTANT_64BIT_FLAG (9) /*!< \c AMS -- Amplitude Modulation Synchronous */
#define RIG_MODE_PKTLSB CONSTANT_64BIT_FLAG (10) /*!< \c PKTLSB -- Packet/Digital LSB mode (dedicated port) */
#define RIG_MODE_PKTUSB CONSTANT_64BIT_FLAG (11) /*!< \c PKTUSB -- Packet/Digital USB mode (dedicated port) */
#define RIG_MODE_PKTFM CONSTANT_64BIT_FLAG (12) /*!< \c PKTFM -- Packet/Digital FM mode (dedicated port) */
#define RIG_MODE_ECSSUSB CONSTANT_64BIT_FLAG (13) /*!< \c ECSSUSB -- Exalted Carrier Single Sideband USB */
#define RIG_MODE_ECSSLSB CONSTANT_64BIT_FLAG (14) /*!< \c ECSSLSB -- Exalted Carrier Single Sideband LSB */
#define RIG_MODE_FAX CONSTANT_64BIT_FLAG (15) /*!< \c FAX -- Facsimile Mode */
#define RIG_MODE_SAM CONSTANT_64BIT_FLAG (16) /*!< \c SAM -- Synchronous AM double sideband */
#define RIG_MODE_SAL CONSTANT_64BIT_FLAG (17) /*!< \c SAL -- Synchronous AM lower sideband */
#define RIG_MODE_SAH CONSTANT_64BIT_FLAG (18) /*!< \c SAH -- Synchronous AM upper (higher) sideband */
#define RIG_MODE_DSB CONSTANT_64BIT_FLAG (19) /*!< \c DSB -- Double sideband suppressed carrier */
#define RIG_MODE_FMN CONSTANT_64BIT_FLAG (21) /*!< \c FMN -- FM Narrow Kenwood ts990s */
#define RIG_MODE_PKTAM CONSTANT_64BIT_FLAG (22) /*!< \c PKTAM -- Packet/Digital AM mode e.g. IC7300 */
#define RIG_MODE_P25 CONSTANT_64BIT_FLAG (23) /*!< \c P25 -- APCO/P25 VHF,UHF digital mode IC-R8600 */
#define RIG_MODE_DSTAR CONSTANT_64BIT_FLAG (24) /*!< \c D-Star -- VHF,UHF digital mode IC-R8600 */
#define RIG_MODE_DPMR CONSTANT_64BIT_FLAG (25) /*!< \c dPMR -- digital PMR, VHF,UHF digital mode IC-R8600 */
#define RIG_MODE_NXDNVN CONSTANT_64BIT_FLAG (26) /*!< \c NXDN-VN -- VHF,UHF digital mode IC-R8600 */
#define RIG_MODE_NXDN_N CONSTANT_64BIT_FLAG (27) /*!< \c NXDN-N -- VHF,UHF digital mode IC-R8600 */
#define RIG_MODE_DCR CONSTANT_64BIT_FLAG (28) /*!< \c DCR -- VHF,UHF digital mode IC-R8600 */
#define RIG_MODE_AMN CONSTANT_64BIT_FLAG (29) /*!< \c AM-N -- Narrow band AM mode IC-R30 */
#define RIG_MODE_PSK CONSTANT_64BIT_FLAG (30) /*!< \c PSK - Kenwood PSK and others */
#define RIG_MODE_PSKR CONSTANT_64BIT_FLAG (31) /*!< \c PSKR - Kenwood PSKR and others */
#define RIG_MODE_DD CONSTANT_64BIT_FLAG (32) /*!< \c DD Mode IC-9700 */
#define RIG_MODE_C4FM CONSTANT_64BIT_FLAG (33) /*!< \c Yaesu C4FM mode */
#define RIG_MODE_PKTFMN CONSTANT_64BIT_FLAG (34) /*!< \c Yaesu DATA-FM-N */
#define RIG_MODE_SPEC CONSTANT_64BIT_FLAG (35) /*!< \c Unfiltered as in PowerSDR */
#define RIG_LEVEL_NONE 0 /*!< '' -- No Level */
#define RIG_LEVEL_PREAMP CONSTANT_64BIT_FLAG(0) /*!< \c PREAMP -- Preamp, arg int (dB) */
#define RIG_LEVEL_ATT CONSTANT_64BIT_FLAG(1) /*!< \c ATT -- Attenuator, arg int (dB) */
#define RIG_LEVEL_VOXDELAY CONSTANT_64BIT_FLAG(2) /*!< \c VOXDELAY -- VOX delay, arg int (tenth of seconds) */
#define RIG_LEVEL_AF CONSTANT_64BIT_FLAG(3) /*!< \c AF -- Volume, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_RF CONSTANT_64BIT_FLAG(4) /*!< \c RF -- RF gain (not TX power) arg float [0.0 ... 1.0] */
#define RIG_LEVEL_SQL CONSTANT_64BIT_FLAG(5) /*!< \c SQL -- Squelch, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_IF CONSTANT_64BIT_FLAG(6) /*!< \c IF -- IF, arg int (Hz) */
#define RIG_LEVEL_APF CONSTANT_64BIT_FLAG(7) /*!< \c APF -- Audio Peak Filter, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_NR CONSTANT_64BIT_FLAG(8) /*!< \c NR -- Noise Reduction, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_PBT_IN CONSTANT_64BIT_FLAG(9) /*!< \c PBT_IN -- Twin PBT (inside) arg float [0.0 ... 1.0] */
#define RIG_LEVEL_PBT_OUT CONSTANT_64BIT_FLAG(10) /*!< \c PBT_OUT -- Twin PBT (outside) arg float [0.0 ... 1.0] */
#define RIG_LEVEL_CWPITCH CONSTANT_64BIT_FLAG(11) /*!< \c CWPITCH -- CW pitch, arg int (Hz) */
#define RIG_LEVEL_RFPOWER CONSTANT_64BIT_FLAG(12) /*!< \c RFPOWER -- RF Power, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_MICGAIN CONSTANT_64BIT_FLAG(13) /*!< \c MICGAIN -- MIC Gain, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_KEYSPD CONSTANT_64BIT_FLAG(14) /*!< \c KEYSPD -- Key Speed, arg int (WPM) */
#define RIG_LEVEL_NOTCHF CONSTANT_64BIT_FLAG(15) /*!< \c NOTCHF -- Notch Freq., arg int (Hz) */
#define RIG_LEVEL_COMP CONSTANT_64BIT_FLAG(16) /*!< \c COMP -- Compressor, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_AGC CONSTANT_64BIT_FLAG(17) /*!< \c AGC -- AGC, arg int (see enum agc_level_e) */
#define RIG_LEVEL_BKINDL CONSTANT_64BIT_FLAG(18) /*!< \c BKINDL -- BKin Delay, arg int (tenth of dots) */
#define RIG_LEVEL_BALANCE CONSTANT_64BIT_FLAG(19) /*!< \c BAL -- Balance (Dual Watch) arg float [0.0 ... 1.0] */
#define RIG_LEVEL_METER CONSTANT_64BIT_FLAG(20) /*!< \c METER -- Display meter, arg int (see enum meter_level_e) */
#define RIG_LEVEL_VOXGAIN CONSTANT_64BIT_FLAG(21) /*!< \c VOXGAIN -- VOX gain level, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_ANTIVOX CONSTANT_64BIT_FLAG(22) /*!< \c ANTIVOX -- anti-VOX level, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_SLOPE_LOW CONSTANT_64BIT_FLAG(23) /*!< \c SLOPE_LOW -- Slope tune, low frequency cut, arg int (Hz) */
#define RIG_LEVEL_SLOPE_HIGH CONSTANT_64BIT_FLAG(24) /*!< \c SLOPE_HIGH -- Slope tune, high frequency cut, arg int (Hz) */
#define RIG_LEVEL_BKIN_DLYMS CONSTANT_64BIT_FLAG(25) /*!< \c BKIN_DLYMS -- BKin Delay, arg int Milliseconds */
/*!< These are not settable */
#define RIG_LEVEL_RAWSTR CONSTANT_64BIT_FLAG(26) /*!< \c RAWSTR -- Raw (A/D) value for signal strength, specific to each rig, arg int */
//#define RIG_LEVEL_SQLSTAT CONSTANT_64BIT_FLAG(27) /*!< \c SQLSTAT -- SQL status, arg int (open=1/closed=0). Deprecated, use get_dcd instead */
#define RIG_LEVEL_SWR CONSTANT_64BIT_FLAG(28) /*!< \c SWR -- SWR, arg float [0.0 ... infinite] */
#define RIG_LEVEL_ALC CONSTANT_64BIT_FLAG(29) /*!< \c ALC -- ALC, arg float */
#define RIG_LEVEL_STRENGTH CONSTANT_64BIT_FLAG(30) /*!< \c STRENGTH -- Effective (calibrated) signal strength relative to S9, arg int (dB) */
/* RIG_LEVEL_BWC (1<<31) */ /*!< Bandwidth Control, arg int (Hz) */
#define RIG_LEVEL_RFPOWER_METER CONSTANT_64BIT_FLAG(32) /*!< \c RFPOWER_METER -- RF power output meter, arg float [0.0 ... 1.0] (percentage of maximum power) */
#define RIG_LEVEL_COMP_METER CONSTANT_64BIT_FLAG(33) /*!< \c COMP_METER -- Audio output level compression meter, arg float (dB) */
#define RIG_LEVEL_VD_METER CONSTANT_64BIT_FLAG(34) /*!< \c VD_METER -- Input voltage level meter, arg float (V, volts) */
#define RIG_LEVEL_ID_METER CONSTANT_64BIT_FLAG(35) /*!< \c ID_METER -- Current draw meter, arg float (A, amperes) */
#define RIG_LEVEL_NOTCHF_RAW CONSTANT_64BIT_FLAG(36) /*!< \c NOTCHF_RAW -- Notch Freq., arg float [0.0 ... 1.0] */
#define RIG_LEVEL_MONITOR_GAIN CONSTANT_64BIT_FLAG(37) /*!< \c MONITOR_GAIN -- Monitor gain (level for monitoring of transmitted audio) arg float [0.0 ... 1.0] */
#define RIG_LEVEL_NB CONSTANT_64BIT_FLAG(38) /*!< \c NB -- Noise Blanker level, arg float [0.0 ... 1.0] */
#define RIG_LEVEL_RFPOWER_METER_WATTS CONSTANT_64BIT_FLAG(39) /*!< \c RFPOWER_METER_WATTS -- RF power output meter, arg float [0.0 ... MAX] (output power in watts) */
#define RIG_LEVEL_SPECTRUM_MODE CONSTANT_64BIT_FLAG(40) /*!< \c SPECTRUM_MODE -- Spectrum scope mode, arg int (see enum rig_spectrum_mode_e). Supported modes defined in rig caps. */
#define RIG_LEVEL_SPECTRUM_SPAN CONSTANT_64BIT_FLAG(41) /*!< \c SPECTRUM_SPAN -- Spectrum scope span in center mode, arg int (Hz). Supported spans defined in rig caps. */
#define RIG_LEVEL_SPECTRUM_EDGE_LOW CONSTANT_64BIT_FLAG(42) /*!< \c SPECTRUM_EDGE_LOW -- Spectrum scope low edge in fixed mode, arg int (Hz) */
#define RIG_LEVEL_SPECTRUM_EDGE_HIGH CONSTANT_64BIT_FLAG(43) /*!< \c SPECTRUM_EDGE_HIGH -- Spectrum scope high edge in fixed mode, arg int (Hz) */
#define RIG_LEVEL_SPECTRUM_SPEED CONSTANT_64BIT_FLAG(44) /*!< \c SPECTRUM_SPEED -- Spectrum scope update speed, arg int (highest is fastest, define rig-specific granularity) */
#define RIG_LEVEL_SPECTRUM_REF CONSTANT_64BIT_FLAG(45) /*!< \c SPECTRUM_REF -- Spectrum scope reference display level, arg float (dB, define rig-specific granularity) */
#define RIG_LEVEL_SPECTRUM_AVG CONSTANT_64BIT_FLAG(46) /*!< \c SPECTRUM_AVG -- Spectrum scope averaging mode, arg int (see struct rig_spectrum_avg_mode). Supported averaging modes defined in rig caps. */
#define RIG_LEVEL_SPECTRUM_ATT CONSTANT_64BIT_FLAG(47) /*!< \c SPECTRUM_ATT -- Spectrum scope attenuator, arg int (dB). Supported attenuator values defined in rig caps. */
#define RIG_LEVEL_TEMP_METER CONSTANT_64BIT_FLAG(48) /*!< \c TEMP_METER -- arg int (C, centigrade) */
#define RIG_FUNC_NONE 0 /*!< '' -- No Function */
#define RIG_FUNC_FAGC CONSTANT_64BIT_FLAG (0) /*!< \c FAGC -- Fast AGC */
#define RIG_FUNC_NB CONSTANT_64BIT_FLAG (1) /*!< \c NB -- Noise Blanker */
#define RIG_FUNC_COMP CONSTANT_64BIT_FLAG (2) /*!< \c COMP -- Speech Compression */
#define RIG_FUNC_VOX CONSTANT_64BIT_FLAG (3) /*!< \c VOX -- Voice Operated Relay */
#define RIG_FUNC_TONE CONSTANT_64BIT_FLAG (4) /*!< \c TONE -- CTCSS Tone TX */
#define RIG_FUNC_TSQL CONSTANT_64BIT_FLAG (5) /*!< \c TSQL -- CTCSS Activate/De-activate RX */
#define RIG_FUNC_SBKIN CONSTANT_64BIT_FLAG (6) /*!< \c SBKIN -- Semi Break-in (CW mode) */
#define RIG_FUNC_FBKIN CONSTANT_64BIT_FLAG (7) /*!< \c FBKIN -- Full Break-in (CW mode) */
#define RIG_FUNC_ANF CONSTANT_64BIT_FLAG (8) /*!< \c ANF -- Automatic Notch Filter (DSP) */
#define RIG_FUNC_NR CONSTANT_64BIT_FLAG (9) /*!< \c NR -- Noise Reduction (DSP) */
#define RIG_FUNC_AIP CONSTANT_64BIT_FLAG (10) /*!< \c AIP -- RF pre-amp (AIP on Kenwood, IPO on Yaesu, etc.) */
#define RIG_FUNC_APF CONSTANT_64BIT_FLAG (11) /*!< \c APF -- Auto Passband/Audio Peak Filter */
#define RIG_FUNC_MON CONSTANT_64BIT_FLAG (12) /*!< \c MON -- Monitor transmitted signal */
#define RIG_FUNC_MN CONSTANT_64BIT_FLAG (13) /*!< \c MN -- Manual Notch */
#define RIG_FUNC_RF CONSTANT_64BIT_FLAG (14) /*!< \c RF -- RTTY Filter */
#define RIG_FUNC_ARO CONSTANT_64BIT_FLAG (15) /*!< \c ARO -- Auto Repeater Offset */
#define RIG_FUNC_LOCK CONSTANT_64BIT_FLAG (16) /*!< \c LOCK -- Lock */
#define RIG_FUNC_MUTE CONSTANT_64BIT_FLAG (17) /*!< \c MUTE -- Mute */
#define RIG_FUNC_VSC CONSTANT_64BIT_FLAG (18) /*!< \c VSC -- Voice Scan Control */
#define RIG_FUNC_REV CONSTANT_64BIT_FLAG (19) /*!< \c REV -- Reverse transmit and receive frequencies */
#define RIG_FUNC_SQL CONSTANT_64BIT_FLAG (20) /*!< \c SQL -- Turn Squelch Monitor on/off */
#define RIG_FUNC_ABM CONSTANT_64BIT_FLAG (21) /*!< \c ABM -- Auto Band Mode */
#define RIG_FUNC_BC CONSTANT_64BIT_FLAG (22) /*!< \c BC -- Beat Canceller */
#define RIG_FUNC_MBC CONSTANT_64BIT_FLAG (23) /*!< \c MBC -- Manual Beat Canceller */
#define RIG_FUNC_RIT CONSTANT_64BIT_FLAG (24) /*!< \c RIT -- Receiver Incremental Tuning */
#define RIG_FUNC_AFC CONSTANT_64BIT_FLAG (25) /*!< \c AFC -- Auto Frequency Control ON/OFF */
#define RIG_FUNC_SATMODE CONSTANT_64BIT_FLAG (26) /*!< \c SATMODE -- Satellite mode ON/OFF */
#define RIG_FUNC_SCOPE CONSTANT_64BIT_FLAG (27) /*!< \c SCOPE -- Simple bandscope ON/OFF */
#define RIG_FUNC_RESUME CONSTANT_64BIT_FLAG (28) /*!< \c RESUME -- Scan auto-resume */
#define RIG_FUNC_TBURST CONSTANT_64BIT_FLAG (29) /*!< \c TBURST -- 1750 Hz tone burst */
#define RIG_FUNC_TUNER CONSTANT_64BIT_FLAG (30) /*!< \c TUNER -- Enable automatic tuner */
#define RIG_FUNC_XIT CONSTANT_64BIT_FLAG (31) /*!< \c XIT -- Transmitter Incremental Tuning */
#define RIG_FUNC_NB2 CONSTANT_64BIT_FLAG (32) /*!< \c NB2 -- 2nd Noise Blanker */
#define RIG_FUNC_CSQL CONSTANT_64BIT_FLAG (33) /*!< \c CSQL -- DCS Squelch setting */
#define RIG_FUNC_AFLT CONSTANT_64BIT_FLAG (34) /*!< \c AFLT -- AF Filter setting */
#define RIG_FUNC_ANL CONSTANT_64BIT_FLAG (35) /*!< \c ANL -- Noise limiter setting */
#define RIG_FUNC_BC2 CONSTANT_64BIT_FLAG (36) /*!< \c BC2 -- 2nd Beat Cancel */
#define RIG_FUNC_DUAL_WATCH CONSTANT_64BIT_FLAG (37) /*!< \c DUAL_WATCH -- Dual Watch / Sub Receiver */
#define RIG_FUNC_DIVERSITY CONSTANT_64BIT_FLAG (38) /*!< \c DIVERSITY -- Diversity receive */
#define RIG_FUNC_DSQL CONSTANT_64BIT_FLAG (39) /*!< \c DSQL -- Digital modes squelch */
#define RIG_FUNC_SCEN CONSTANT_64BIT_FLAG (40) /*!< \c SCEN -- scrambler/encryption */
#define RIG_FUNC_SLICE CONSTANT_64BIT_FLAG (41) /*!< \c Rig slice selection -- Flex */
#define RIG_FUNC_TRANSCEIVE CONSTANT_64BIT_FLAG (42) /*!< \c TRANSCEIVE -- Send radio state changes automatically ON/OFF */
#define RIG_FUNC_SPECTRUM CONSTANT_64BIT_FLAG (43) /*!< \c SPECTRUM -- Spectrum scope data output ON/OFF */
#define RIG_FUNC_SPECTRUM_HOLD CONSTANT_64BIT_FLAG (44) /*!< \c SPECTRUM_HOLD -- Pause spectrum scope updates ON/OFF */
#if 0
static struct
{
quint64 func;
const char* str;
} rig_func_str[] =
{
{ RIG_FUNC_FAGC, "FAGC" },
{ RIG_FUNC_NB, "NB" },
{ RIG_FUNC_COMP, "COMP" },
{ RIG_FUNC_VOX, "VOX" },
{ RIG_FUNC_TONE, "TONE" },
{ RIG_FUNC_TSQL, "TSQL" },
{ RIG_FUNC_SBKIN, "SBKIN" },
{ RIG_FUNC_FBKIN, "FBKIN" },
{ RIG_FUNC_ANF, "ANF" },
{ RIG_FUNC_NR, "NR" },
{ RIG_FUNC_AIP, "AIP" },
{ RIG_FUNC_APF, "APF" },
{ RIG_FUNC_MON, "MON" },
{ RIG_FUNC_MN, "MN" },
{ RIG_FUNC_RF, "RF" },
{ RIG_FUNC_ARO, "ARO" },
{ RIG_FUNC_LOCK, "LOCK" },
{ RIG_FUNC_MUTE, "MUTE" },
{ RIG_FUNC_VSC, "VSC" },
{ RIG_FUNC_REV, "REV" },
{ RIG_FUNC_SQL, "SQL" },
{ RIG_FUNC_ABM, "ABM" },
{ RIG_FUNC_BC, "BC" },
{ RIG_FUNC_MBC, "MBC" },
{ RIG_FUNC_RIT, "RIT" },
{ RIG_FUNC_AFC, "AFC" },
{ RIG_FUNC_SATMODE, "SATMODE" },
{ RIG_FUNC_SCOPE, "SCOPE" },
{ RIG_FUNC_RESUME, "RESUME" },
{ RIG_FUNC_TBURST, "TBURST" },
{ RIG_FUNC_TUNER, "TUNER" },
{ RIG_FUNC_XIT, "XIT" },
{ RIG_FUNC_NB2, "NB2" },
{ RIG_FUNC_DSQL, "DSQL" },
{ RIG_FUNC_AFLT, "AFLT" },
{ RIG_FUNC_ANL, "ANL" },
{ RIG_FUNC_BC2, "BC2" },
{ RIG_FUNC_DUAL_WATCH, "DUAL_WATCH"},
{ RIG_FUNC_DIVERSITY, "DIVERSITY"},
{ RIG_FUNC_CSQL, "CSQL" },
{ RIG_FUNC_SCEN, "SCEN" },
{ RIG_FUNC_TRANSCEIVE, "TRANSCEIVE" },
{ RIG_FUNC_SPECTRUM, "SPECTRUM" },
{ RIG_FUNC_SPECTRUM_HOLD, "SPECTRUM_HOLD" },
{ RIG_FUNC_NONE, "" },
};
static struct
{
quint64 level;
const char* str;
} rig_level_str[] =
{
{ RIG_LEVEL_PREAMP, "PREAMP" },
{ RIG_LEVEL_ATT, "ATT" },
{ RIG_LEVEL_VOXDELAY, "VOXDELAY" },
{ RIG_LEVEL_AF, "AF" },
{ RIG_LEVEL_RF, "RF" },
{ RIG_LEVEL_SQL, "SQL" },
{ RIG_LEVEL_IF, "IF" },
{ RIG_LEVEL_APF, "APF" },
{ RIG_LEVEL_NR, "NR" },
{ RIG_LEVEL_PBT_IN, "PBT_IN" },
{ RIG_LEVEL_PBT_OUT, "PBT_OUT" },
{ RIG_LEVEL_CWPITCH, "CWPITCH" },
{ RIG_LEVEL_RFPOWER, "RFPOWER" },
{ RIG_LEVEL_MICGAIN, "MICGAIN" },
{ RIG_LEVEL_KEYSPD, "KEYSPD" },
{ RIG_LEVEL_NOTCHF, "NOTCHF" },
{ RIG_LEVEL_COMP, "COMP" },
{ RIG_LEVEL_AGC, "AGC" },
{ RIG_LEVEL_BKINDL, "BKINDL" },
{ RIG_LEVEL_BALANCE, "BAL" },
{ RIG_LEVEL_METER, "METER" },
{ RIG_LEVEL_VOXGAIN, "VOXGAIN" },
{ RIG_LEVEL_ANTIVOX, "ANTIVOX" },
{ RIG_LEVEL_SLOPE_LOW, "SLOPE_LOW" },
{ RIG_LEVEL_SLOPE_HIGH, "SLOPE_HIGH" },
{ RIG_LEVEL_BKIN_DLYMS, "BKIN_DLYMS" },
{ RIG_LEVEL_RAWSTR, "RAWSTR" },
{ RIG_LEVEL_SWR, "SWR" },
{ RIG_LEVEL_ALC, "ALC" },
{ RIG_LEVEL_STRENGTH, "STRENGTH" },
{ RIG_LEVEL_RFPOWER_METER, "RFPOWER_METER" },
{ RIG_LEVEL_COMP_METER, "COMP_METER" },
{ RIG_LEVEL_VD_METER, "VD_METER" },
{ RIG_LEVEL_ID_METER, "ID_METER" },
{ RIG_LEVEL_NOTCHF_RAW, "NOTCHF_RAW" },
{ RIG_LEVEL_MONITOR_GAIN, "MONITOR_GAIN" },
{ RIG_LEVEL_NB, "NB" },
{ RIG_LEVEL_RFPOWER_METER_WATTS, "RFPOWER_METER_WATTS" },
{ RIG_LEVEL_SPECTRUM_MODE, "SPECTRUM_MODE" },
{ RIG_LEVEL_SPECTRUM_SPAN, "SPECTRUM_SPAN" },
{ RIG_LEVEL_SPECTRUM_EDGE_LOW, "SPECTRUM_EDGE_LOW" },
{ RIG_LEVEL_SPECTRUM_EDGE_HIGH, "SPECTRUM_EDGE_HIGH" },
{ RIG_LEVEL_SPECTRUM_SPEED, "SPECTRUM_SPEED" },
{ RIG_LEVEL_SPECTRUM_REF, "SPECTRUM_REF" },
{ RIG_LEVEL_SPECTRUM_AVG, "SPECTRUM_AVG" },
{ RIG_LEVEL_SPECTRUM_ATT, "SPECTRUM_ATT" },
{ RIG_LEVEL_TEMP_METER, "TEMP_METER" },
{ RIG_LEVEL_NONE, "" },
};
#endif
struct cal_table {
int size; /*!< number of plots in the table */
struct {
int raw; /*!< raw (A/D) value, as returned by \a RIG_LEVEL_RAWSTR */
int val; /*!< associated value, basically the measured dB value */
} table[32]; /*!< table of plots */
};
typedef struct cal_table cal_table_t;
#define IC7610_STR_CAL { 16, \
{ \
{ 0, -54 }, /* S0 */ \
{ 11, -48 }, \
{ 21, -42 }, \
{ 34, -36 }, \
{ 50, -30 }, \
{ 59, -24 }, \
{ 75, -18 }, \
{ 93, -12 }, \
{ 103, -6 }, \
{ 124, 0 }, /* S9 */ \
{ 145, 10 }, \
{ 160, 20 }, \
{ 183, 30 }, \
{ 204, 40 }, \
{ 222, 50 }, \
{ 246, 60 } /* S9+60dB */ \
} }
#define IC7850_STR_CAL { 3, \
{ \
{ 0, -54 }, /* S0 */ \
{ 120, 0 }, /* S9 */ \
{ 241, 60 } /* S9+60 */ \
} }
#define IC7300_STR_CAL { 7, \
{ \
{ 0, -54 }, \
{ 10, -48 }, \
{ 30, -36 }, \
{ 60, -24 }, \
{ 90, -12 }, \
{ 120, 0 }, \
{ 241, 64 } \
} }
class rigCtlD : public QTcpServer
{
Q_OBJECT
public:
explicit rigCtlD(QObject *parent=Q_NULLPTR);
explicit rigCtlD(QObject *parent=nullptr);
virtual ~rigCtlD();
int startServer(qint16 port);
@ -30,18 +337,43 @@ signals:
void onStarted();
void onStopped();
void sendData(QString data);
void setFrequency(freqt freq);
void setFrequency(quint8 vfo, freqt freq);
void setPTT(bool state);
void setMode(unsigned char mode, unsigned char modeFilter);
void setMode(quint8 mode, quint8 modeFilter);
void setDataMode(bool dataOn, quint8 modeFilter);
void setVFO(quint8 vfo);
void setSplit(quint8 split);
void setDuplexMode(duplexMode dm);
void stateUpdated();
// Power
void sendPowerOn();
void sendPowerOff();
// Att/preamp
void setAttenuator(quint8 att);
void setPreamp(quint8 pre);
//Level set
void setRfGain(quint8 level);
void setAfGain(quint8 level);
void setSql(quint8 level);
void setMicGain(quint8);
void setCompLevel(quint8);
void setTxPower(quint8);
void setMonitorGain(quint8);
void setVoxGain(quint8);
void setAntiVoxGain(quint8);
void setSpectrumRefLevel(int);
public slots:
virtual void incomingConnection(qintptr socketDescriptor);
void receiveRigCaps(rigCapabilities caps);
void receiveStateInfo(rigStateStruct* state);
void receiveFrequency(freqt freq);
void receiveStateInfo(rigstate* state);
// void receiveFrequency(freqt freq);
private:
rigStateStruct* rigState = Q_NULLPTR;
rigstate* rigState = Q_NULLPTR;
};
@ -51,7 +383,7 @@ class rigCtlClient : public QObject
public:
explicit rigCtlClient(int socket, rigCapabilities caps, rigStateStruct *state, rigCtlD* parent = Q_NULLPTR);
explicit rigCtlClient(int socket, rigCapabilities caps, rigstate *state, rigCtlD* parent = Q_NULLPTR);
int getSocketId();
@ -67,14 +399,24 @@ protected:
QString commandBuffer;
private:
void dumpCaps(QString sep);
rigCapabilities rigCaps;
rigStateStruct* rigState = Q_NULLPTR;
rigstate* rigState = Q_NULLPTR;
rigCtlD* parent;
QString getMode(unsigned char mode, bool datamode);
unsigned char getMode(QString modeString);
QString getFilter(unsigned char mode, unsigned char filter);
bool chkVfoEecuted=false;
unsigned long crcTable[256];
unsigned long doCrc(unsigned char* p, size_t n);
void genCrc(unsigned long crcTable[]);
QString getMode(quint8 mode, bool datamode);
quint8 getMode(QString modeString);
QString getFilter(quint8 mode, quint8 filter);
quint8 getAntennas();
quint64 getRadioModes(QString mode = "");
QString getAntName(quint8 ant);
quint8 antFromName(QString name);
quint8 vfoFromName(QString vfo);
QString getVfoName(quint8 vfo);
int getCalibratedValue(quint8 meter,cal_table_t cal);
};

Wyświetl plik

@ -1,81 +1,13 @@
#include "rigidentities.h"
#include "logcategories.h"
// Copytight 2017-2021 Elliott H. Liggett
// Copyright 2017-2021 Elliott H. Liggett
model_kind determineRadioModel(unsigned char rigID)
{
model_kind rig;
switch(rigID)
{
case model7100:
rig = model7100;
break;
case model7200:
rig = model7200;
break;
case model7300:
rig = model7300;
break;
case modelR8600:
rig = modelR8600;
break;
case model7000:
rig = model7000;
break;
case model7410:
rig = model7410;
break;
case model7600:
rig = model7600;
break;
case model7610:
rig = model7610;
break;
case model7700:
rig = model7700;
break;
case model7800:
rig = model7800;
break;
case model7850:
rig = model7850;
break;
case model9700:
rig = model9700;
break;
case model706:
rig = model706;
break;
case model705:
rig = model705;
break;
case model718:
rig = model718;
break;
case model910h:
rig = model910h;
break;
case model756pro:
rig = model756pro;
break;
case model756proii:
rig = model756proii;
break;
case model756proiii:
rig = model756proiii;
break;
default:
rig = modelUnknown;
break;
}
rig = (model_kind)rigID;
return rig;
}

Wyświetl plik

@ -7,12 +7,14 @@
#include <vector>
#include "freqmemory.h"
#include "packettypes.h"
// Credit for parts of CIV list:
// http://www.docksideradio.com/Icom%20Radio%20Hex%20Addresses.htm
// 7850 and 7851 have the same commands and are essentially identical
enum model_kind {
model7100 = 0x88,
model7200 = 0x76,
@ -26,13 +28,21 @@ enum model_kind {
model7410 = 0x80,
model7850 = 0x8E,
model9700 = 0xA2,
model703 = 0x68,
model705 = 0xA4,
model706 = 0x58,
model718 = 0x5E,
model736 = 0x40,
model737 = 0x3C,
model738 = 0x44,
model746 = 0x56,
model756 = 0x50,
model756pro = 0x5C,
model756proii = 0x64,
model756proiii = 0x6E,
model905 = 0xAC,
model910h = 0x60,
model9100 = 0x7C,
modelUnknown = 0xFF
};
@ -46,7 +56,12 @@ enum rigInput{ inputMic=0,
inputUnknown=0xff
};
enum bandType { band23cm=0,
enum availableBands {
band3cm = 0,
band6cm,
band9cm,
band13cm,
band23cm,
band70cm,
band2m,
bandAir,
@ -78,7 +93,10 @@ enum centerSpansType {
cs250k = 6,
cs500k = 7,
cs1M = 8,
cs2p5M = 9
cs2p5M = 9,
cs5M = 10,
cs10M = 11,
cs25M = 12,
};
struct centerSpanData {
@ -86,14 +104,25 @@ struct centerSpanData {
QString name;
};
struct bandType {
bandType(availableBands band, quint64 lowFreq, quint64 highFreq, mode_kind defaultMode) :
band(band), lowFreq(lowFreq), highFreq(highFreq), defaultMode(defaultMode) {}
bandType() {}
availableBands band;
quint64 lowFreq;
quint64 highFreq;
mode_kind defaultMode;
};
model_kind determineRadioModel(unsigned char rigID);
struct rigCapabilities {
model_kind model;
quint8 civ;
quint8 modelID;
int rigctlModel;
QString modelName;
bool hasLan; // OEM ethernet or wifi connection
@ -103,33 +132,54 @@ struct rigCapabilities {
QVector<rigInput> inputs;
bool hasSpectrum;
bool hasSpectrum=true;
quint8 spectSeqMax;
quint16 spectAmpMax;
quint16 spectLenMax;
bool hasNB = false;
QByteArray nbCommand;
bool hasDD;
bool hasDV;
bool hasATU;
bool hasCTCSS;
bool hasDTCS;
bool hasRepeaterModes = false;
bool hasTransmit;
bool hasPTTCommand;
bool useRTSforPTT;
bool hasAttenuator;
bool hasPreamp;
bool hasAntennaSel;
bool hasDataModes;
bool hasIFShift;
bool hasTBPF;
bool hasRXAntenna;
bool hasSpecifyMainSubCmd = false; // 0x29
bool hasVFOMS = false;
bool hasVFOAB = true; // 0x07 [00||01]
bool hasAdvancedRptrToneCmds = false;
bool hasQuickSplitCommand = false;
QByteArray quickSplitCommand;
std::vector <unsigned char> attenuators;
std::vector <unsigned char> preamps;
std::vector <unsigned char> antennas;
std::vector <centerSpanData> scopeCenterSpans;
std::vector <bandType> bands;
unsigned char bsr[20] = {0};
unsigned char bsr[24] = {0};
std::vector <mode_info> modes;
QByteArray transceiveCommand;
quint8 guid[GUIDLEN] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
quint32 baudRate;
};

140
rigstate.h 100644
Wyświetl plik

@ -0,0 +1,140 @@
#ifndef RIGSTATEH
#define RIGSTATEH
#include <QObject>
#include <QMutex>
#include <QDateTime>
#include <QVariant>
#include <QMap>
#include <QCache>
#include "rigcommander.h"
#include "rigidentities.h"
// Meters at the end as they are ALWAYS updated from the rig!
enum stateTypes { VFOAFREQ, VFOBFREQ, CURRENTVFO, PTT, MODE, FILTER, PASSBAND, DUPLEX, DATAMODE, ANTENNA, RXANTENNA, CTCSS, TSQL, DTCS, CSQL,
PREAMP, AGC, ATTENUATOR, MODINPUT, AFGAIN, RFGAIN, SQUELCH, RFPOWER, MICGAIN, COMPLEVEL, MONITORLEVEL, BAL, KEYSPD,
VOXGAIN, ANTIVOXGAIN, CWPITCH, NOTCHF, IF, PBTIN, PBTOUT, APF, NR, NB, NBDEPTH, NBWIDTH, RIGINPUT, POWERONOFF, RITVALUE,
FAGCFUNC, NBFUNC, COMPFUNC, VOXFUNC, TONEFUNC, TSQLFUNC, SBKINFUNC, FBKINFUNC, ANFFUNC, NRFUNC, AIPFUNC, APFFUNC, MONFUNC, MNFUNC,RFFUNC,
AROFUNC, MUTEFUNC, VSCFUNC, REVFUNC, SQLFUNC, ABMFUNC, BCFUNC, MBCFUNC, RITFUNC, AFCFUNC, SATMODEFUNC, SCOPEFUNC,
ANN, APO, BACKLIGHT, BEEP, TIME, BAT, KEYLIGHT,
RESUMEFUNC, TBURSTFUNC, TUNERFUNC, LOCKFUNC, SMETER, POWERMETER, SWRMETER, ALCMETER, COMPMETER, VOLTAGEMETER, CURRENTMETER,
};
struct value {
quint64 _value=0;
bool _valid = false;
bool _updated = false;
QDateTime _dateUpdated;
};
class rigstate
{
public:
void invalidate(stateTypes s) { map[s]._valid = false; }
bool isValid(stateTypes s) { return map[s]._valid; }
bool isUpdated(stateTypes s) { return map[s]._updated; }
QDateTime whenUpdated(stateTypes s) { return map[s]._dateUpdated; }
void set(stateTypes s, quint64 x, bool u) {
if ((x != (quint64)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
void set(stateTypes s, qint32 x, bool u) {
if ((x != (qint32)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
void set(stateTypes s, qint16 x, bool u) {
if ((x != (qint16)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
void set(stateTypes s, quint16 x, bool u) {
if ((x != (quint16)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
void set(stateTypes s, quint8 x, bool u) {
if ((x != (quint8)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
void set(stateTypes s, bool x, bool u) {
if ((x != (bool)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
void set(stateTypes s, duplexMode x, bool u) {
if ((x != (duplexMode)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
void set(stateTypes s, rigInput x, bool u) {
if ((x != map[s]._value) && ((!u && !map[s]._updated) || (u))) {
_mutex.lock();
map[s]._value = quint64(x);
map[s]._valid = true;
map[s]._updated = u;
map[s]._dateUpdated = QDateTime::currentDateTime();
_mutex.unlock();
}
}
bool getBool(stateTypes s) { return map[s]._value != 0; }
quint8 getChar(stateTypes s) { return quint8(map[s]._value); }
qint16 getInt16(stateTypes s) { return qint16(map[s]._value); }
quint16 getUInt16(stateTypes s) { return quint16(map[s]._value); }
qint32 getInt32(stateTypes s) { return qint32(map[s]._value); }
quint32 getUInt32(stateTypes s) { return quint32(map[s]._value); }
quint64 getInt64(stateTypes s) { return map[s]._value; }
duplexMode getDuplex(stateTypes s) { return duplexMode(map[s]._value); }
rigInput getInput(stateTypes s) { return rigInput(map[s]._value); }
QMap<stateTypes, value> map;
private:
//std::map<stateTypes, std::unique_ptr<valueBase> > values;
QMutex _mutex;
};
#endif

Wyświetl plik

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Trevor Wilson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Wyświetl plik

@ -1,10 +0,0 @@
# Ring Library
## Overview
This library provides source for a multi-producer multi-consumer lock-free ring buffer. It provides a very simple interface for writing and reading from the buffer. The source includes a `Ring_` class, that provides the raw implementation and C-like facilities, as well as a templated `Ring<T>` class for typed reads and writes.
## Contact
If you have any questions, concerns, or recommendations please feel free to e-mail me at kmdreko@gmail.com. If you notice a bug or defect, create an issue to report it.

Wyświetl plik

@ -1,290 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// FILE: ring.cpp
// DATE: 2016-02-25
// AUTH: Trevor Wilson
// DESC: Implements a lock-free, multi-consumer, multi-producer ring buffer
// class
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Trevor Wilson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "ring.h"
using namespace wilt;
#include <cstring>
// - std::memcpy
Ring_::Ring_()
: beg_(nullptr)
, end_(nullptr)
{
std::atomic_init(&used_, static_cast<std::ptrdiff_t>(0));
std::atomic_init(&free_, static_cast<std::ptrdiff_t>(0));
std::atomic_init(&rbuf_, static_cast<char*>(0));
std::atomic_init(&rptr_, static_cast<char*>(0));
std::atomic_init(&wptr_, static_cast<char*>(0));
std::atomic_init(&wbuf_, static_cast<char*>(0));
}
Ring_::Ring_(std::size_t size)
: beg_(new char[size])
, end_(beg_ + size)
{
std::atomic_init(&used_, static_cast<std::ptrdiff_t>(0));
std::atomic_init(&free_, static_cast<std::ptrdiff_t>(size));
std::atomic_init(&rbuf_, beg_);
std::atomic_init(&rptr_, beg_);
std::atomic_init(&wptr_, beg_);
std::atomic_init(&wbuf_, beg_);
}
Ring_::Ring_(Ring_&& ring)
: beg_(ring.beg_)
, end_(ring.end_)
{
std::atomic_init(&used_, ring.used_.load());
std::atomic_init(&free_, ring.free_.load());
std::atomic_init(&rbuf_, ring.rbuf_.load());
std::atomic_init(&rptr_, ring.rptr_.load());
std::atomic_init(&wptr_, ring.wptr_.load());
std::atomic_init(&wbuf_, ring.wbuf_.load());
ring.beg_ = nullptr;
ring.end_ = nullptr;
ring.used_.store(0);
ring.free_.store(0);
ring.rbuf_.store(nullptr);
ring.rptr_.store(nullptr);
ring.wptr_.store(nullptr);
ring.wbuf_.store(nullptr);
}
Ring_& Ring_::operator= (Ring_&& ring)
{
delete[] beg_;
beg_ = ring.beg_;
end_ = ring.end_;
used_.store(ring.used_.load());
free_.store(ring.free_.load());
rbuf_.store(ring.rbuf_.load());
rptr_.store(ring.rptr_.load());
wptr_.store(ring.wptr_.load());
wbuf_.store(ring.wbuf_.load());
ring.beg_ = nullptr;
ring.end_ = nullptr;
ring.used_.store(0);
ring.free_.store(0);
ring.rbuf_.store(nullptr);
ring.rptr_.store(nullptr);
ring.wptr_.store(nullptr);
ring.wbuf_.store(nullptr);
return *this;
}
Ring_::~Ring_()
{
delete[] beg_;
}
std::size_t Ring_::size() const
{
// The 'used' space can be negative in an over-reserved case, but it can be
// clamped to 0 for simplicity.
auto s = used_.load();
return s < 0 ? 0 : static_cast<std::size_t>(s);
}
std::size_t Ring_::capacity() const
{
return static_cast<std::size_t>(end_ - beg_);
}
void Ring_::read(void* data, std::size_t length) noexcept
{
auto block = acquire_read_block_(length);
copy_read_block_(block, (char*)data, length);
release_read_block_(block, length);
}
void Ring_::write(const void* data, std::size_t length) noexcept
{
auto block = acquire_write_block_(length);
copy_write_block_(block, (const char*)data, length);
release_write_block_(block, length);
}
bool Ring_::try_read(void* data, std::size_t length) noexcept
{
auto block = try_acquire_read_block_(length);
if (block == nullptr)
return false;
copy_read_block_(block, (char*)data, length);
release_read_block_(block, length);
return true;
}
bool Ring_::try_write(const void* data, std::size_t length) noexcept
{
auto block = try_acquire_write_block_(length);
if (block == nullptr)
return false;
copy_write_block_(block, (const char*)data, length);
release_write_block_(block, length);
return true;
}
char* Ring_::normalize_(char* ptr)
{
return ptr < end_ ? ptr : ptr - capacity();
}
char* Ring_::acquire_read_block_(std::size_t length)
{
auto size = static_cast<std::ptrdiff_t>(length);
while (true) // loop while conflict
{
auto old_rptr = rptr_.load(std::memory_order_consume); // read rptr
while (used_.load(std::memory_order_consume) < size) // check for data
; // spin until success
auto new_rptr = normalize_(old_rptr + size); // get block end
used_.fetch_sub(size); // reserve
if (rptr_.compare_exchange_strong(old_rptr, new_rptr)) // try commit
return old_rptr; // committed
used_.fetch_add(size, std::memory_order_relaxed); // un-reserve
}
}
char* Ring_::try_acquire_read_block_(std::size_t length)
{
auto size = static_cast<std::ptrdiff_t>(length);
while (true) // loop while conflict
{
auto old_rptr = rptr_.load(std::memory_order_consume); // read rptr
if (used_.load(std::memory_order_consume) < size) // check for data
return nullptr; // return failure
auto new_rptr = normalize_(old_rptr + size); // get block end
used_.fetch_sub(size); // reserve
if (rptr_.compare_exchange_strong(old_rptr, new_rptr)) // try commit
return old_rptr; // committed
used_.fetch_add(size, std::memory_order_relaxed); // un-reserve
}
}
void Ring_::copy_read_block_(const char* block, char* data, std::size_t length)
{
if (block + length < end_)
{
std::memcpy(data, block, length);
}
else
{
auto first = end_ - block;
std::memcpy(data, block, first);
std::memcpy(data + first, beg_, length - first);
}
}
void Ring_::release_read_block_(char* old_rptr, std::size_t length)
{
auto new_rptr = normalize_(old_rptr + length); // get block end
while (rbuf_.load() != old_rptr) // check for earlier reads
; // spin until reads complete
rbuf_.store(new_rptr); // finish commit
free_.fetch_add(length, std::memory_order_relaxed); // add to free space
}
char* Ring_::acquire_write_block_(std::size_t length)
{
auto size = static_cast<std::ptrdiff_t>(length);
while (true) // loop while conflict
{
auto old_wbuf = wbuf_.load(std::memory_order_consume); // read wbuf
while (free_.load(std::memory_order_consume) < size) // check for space
; // spin until success
auto new_wbuf = normalize_(old_wbuf + size); // get block end
free_.fetch_sub(size); // reserve
if (wbuf_.compare_exchange_strong(old_wbuf, new_wbuf)) // try commit
return old_wbuf; // committed
free_.fetch_add(size, std::memory_order_relaxed); // un-reserve
}
}
char* Ring_::try_acquire_write_block_(std::size_t length)
{
auto size = static_cast<std::ptrdiff_t>(length);
while (true) // loop while conflict
{
auto old_wbuf = wbuf_.load(std::memory_order_consume); // read wbuf
if (free_.load(std::memory_order_consume) < size) // check for space
return nullptr; // return failure
auto new_wbuf = normalize_(old_wbuf + size); // get block end
free_.fetch_sub(size); // reserve
if (wbuf_.compare_exchange_strong(old_wbuf, new_wbuf)) // try commit
return old_wbuf; // committed
free_.fetch_add(size, std::memory_order_relaxed); // un-reserve
}
}
void Ring_::copy_write_block_(char* block, const char* data, std::size_t length)
{
if (block + length < end_)
{
std::memcpy(block, data, length);
}
else
{
auto first = end_ - block;
std::memcpy(block, data, first);
std::memcpy(beg_, data + first, length - first);
}
}
void Ring_::release_write_block_(char* old_wbuf, std::size_t length)
{
auto new_wbuf = normalize_(old_wbuf + length); // get block end
while (wptr_.load() != old_wbuf) // wait for earlier writes
; // spin until writes complete
wptr_.store(new_wbuf); // finish commit
used_.fetch_add(length, std::memory_order_relaxed); // add to used space
}

Wyświetl plik

@ -1,440 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// FILE: ring.h
// DATE: 2016-02-25
// AUTH: Trevor Wilson
// DESC: Defines a lock-free, multi-consumer, multi-producer ring buffer class
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Trevor Wilson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef WILT_RING_H
#define WILT_RING_H
#include <atomic>
// - std::atomic
#include <cstddef>
// - std::size_t
// - std::ptrdiff_t
#include <new>
// - ::new(ptr)
#include <type_traits>
// - std::is_nothrow_copy_constructible
// - std::is_nothrow_move_constructible
// - std::is_nothrow_move_assignable
// - std::is_nothrow_destructible
#include <utility>
// - std::move
namespace wilt
{
//////////////////////////////////////////////////////////////////////////////
// This structure aims to access elements in a ring buffer from multiple
// concurrent readers and writers in a lock-free manner.
//
// The class works by allocating the array and storing two pointers (for the
// beginning and end of the allocated space). Two atomic pointers are used to
// track the beginning and end of the currently used storage space. To
// facilitate concurrent reads and writes, theres a read buffer pointer before
// the read pointer for data currently being read, and a corresponding write
// buffer pointer beyond the write pointer for data currently being written.
// These buffer pointers cannot overlap. Just using these pointers suffer from
// some minute inefficiencies and a few ABA problems. Therfore, atomic
// integers are used to store the currently used and currently free sizes.
//
// It allows multiple readers and multiple writers by implementing a reserve-
// commit system. A thread wanting to read will check the used size to see if
// there's enough data. If there is, it subtracts from the used size to
// 'reserve' the read. It then does a compare-exchange to 'commit' by
// increasing the read pointer. If that fails, then it backs out ('un-
// reserves') by adding back to the used size and tries again. If it
// succeeds, then it proceeds to read the data. In order to complete, the
// reader must update the read buffer pointer to where it just finished
// reading from. However, because other readers that started before may not be
// done yet, the reader must wait until the read buffer pointer points to
// where the read started. Only, then is the read buffer pointer updated, and
// the free size increased. So while this implementation is lock-free, it is
// not wait-free. This same principle works the same when writing (ammended
// for the appropriate pointers).
//
// If two readers try to read at the same time and there is only enough data
// for one of them. The used size MAY be negative because they both 'reserve'
// the data. This is an over-reserved state. But the compare-exchange will
// only allow one reader to 'commit' to the read and the other will 'un-
// reserve' the read.
//
// |beg |rptr used=5 |wbuf - unused
// |----|----|++++|====|====|====|====|====|++++|----| + modifying
// free=3 |rbuf |wptr |end = used
//
// The diagram above shows a buffer of size 10 storing 5 bytes with a reader
// reading one byte and one writer reading one byte.
//
// Out of the box, the class works by reading and writing raw bytes from POD
// data types and arrays. A wrapper could allow for a nicer interface for
// pushing and popping elements. As it stands, this structure cannot be easily
// modified to store types of variable size.
class Ring_
{
private:
////////////////////////////////////////////////////////////////////////////
// TYPE DEFINITIONS
////////////////////////////////////////////////////////////////////////////
typedef char* data_ptr;
typedef std::atomic<std::ptrdiff_t> size_type;
typedef std::atomic<char*> atom_ptr;
private:
////////////////////////////////////////////////////////////////////////////
// PRIVATE MEMBERS
////////////////////////////////////////////////////////////////////////////
// Beginning and end pointers don't need to be atomic because they don't
// change. used_ and free_ can be negative in certain cases (and that's ok).
data_ptr beg_; // pointer to beginning of data block
data_ptr end_; // pointer to end of data block
alignas(64)
size_type used_; // size of unreserved used space
alignas(64)
size_type free_; // size of unreserved free space
alignas(64)
atom_ptr rbuf_; // pointer to beginning of data being read
atom_ptr rptr_; // pointer to beginning of data
alignas(64)
atom_ptr wptr_; // pointer to end of data
atom_ptr wbuf_; // pointer to end of data being written
public:
////////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS AND DESTRUCTORS
////////////////////////////////////////////////////////////////////////////
// Constructs a ring without a buffer (capacity() == 0)
Ring_();
// Constructs a ring with a buffer with a size
Ring_(std::size_t size);
// Moves the buffer between rings, assumes no concurrent operations
Ring_(Ring_&& ring);
// Moves the buffer between rings, assumes no concurrent operations on
// either ring. Deallocates the buffer
Ring_& operator= (Ring_&& ring);
// No copying
Ring_(const Ring_&) = delete;
Ring_& operator= (const Ring_&) = delete;
// Deallocates the buffer
~Ring_();
public:
////////////////////////////////////////////////////////////////////////////
// QUERY FUNCTIONS
////////////////////////////////////////////////////////////////////////////
// Functions only report on the state of the ring
// Returns the current amount of non-reserved used space (amount of written
// data that a read hasn't yet reserved). Over-reserved scenarios mean this
// number is not the ultimate source of truth with concurrent operations,
// but its the closest safe approximation. This, of course, doesn't report
// writes that have not completed.
std::size_t size() const;
// Maximum amount of data that can be held
std::size_t capacity() const;
public:
////////////////////////////////////////////////////////////////////////////
// ACCESSORS AND MODIFIERS
////////////////////////////////////////////////////////////////////////////
// All operations assume object has not been moved. Blocking operations run
// until operation is completed. Non-blocking operations fail if there is
// not enough space
void read(void* data, std::size_t length) noexcept;
void write(const void* data, std::size_t length) noexcept;
bool try_read(void* data, std::size_t length) noexcept;
bool try_write(const void* data, std::size_t length) noexcept;
protected:
////////////////////////////////////////////////////////////////////////////
// PROTECTED FUNCTIONS
////////////////////////////////////////////////////////////////////////////
// Helper functions
// Wraps a pointer within the array. Assumes 'beg_ <= ptr < end_+capacity()'
char* normalize_(char*);
char* acquire_read_block_(std::size_t length);
char* try_acquire_read_block_(std::size_t length);
void copy_read_block_(const char* block, char* data, std::size_t length);
void release_read_block_(char* block, std::size_t length);
char* acquire_write_block_(std::size_t length);
char* try_acquire_write_block_(std::size_t length);
void copy_write_block_(char* block, const char* data, std::size_t length);
void release_write_block_(char* block, std::size_t length);
char* begin_alloc_() { return beg_; }
const char* begin_alloc_() const { return beg_; }
char* end_alloc_() { return end_; }
const char* end_alloc_() const { return end_; }
char* begin_data_() { return rptr_; }
const char* begin_data_() const { return rptr_; }
char* end_data_() { return wptr_; }
const char* end_data_() const { return wptr_; }
}; // class Ring_
template <class T>
class Ring : protected Ring_
{
public:
////////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS AND DESTRUCTORS
////////////////////////////////////////////////////////////////////////////
// Constructs a ring without a buffer (capacity() == 0)
Ring();
// Constructs a ring with a buffer with a size
Ring(std::size_t size);
// Moves the buffer between rings, assumes no concurrent operations
Ring(Ring<T>&& ring);
// Moves the buffer between rings, assumes no concurrent operations on
// either ring. Deallocates the buffer
Ring<T>& operator= (Ring<T>&& ring);
// No copying
Ring(const Ring_&) = delete;
Ring& operator= (const Ring_&) = delete;
// Deallocates the buffer, destructs stored data.
~Ring();
public:
////////////////////////////////////////////////////////////////////////////
// QUERY FUNCTIONS
////////////////////////////////////////////////////////////////////////////
// Functions only report on the state of the ring
// Returns the current amount of non-reserved used space (amount of written
// data that a read hasn't yet reserved). Over-reserved scenarios mean this
// number is not the ultimate source of truth with concurrent operations,
// but its the closest safe approximation. This, of course, doesn't report
// writes that have not completed.
std::size_t size() const;
// Maximum amount of data that can be held
std::size_t capacity() const;
public:
////////////////////////////////////////////////////////////////////////////
// ACCESSORS AND MODIFIERS
////////////////////////////////////////////////////////////////////////////
// All operations assume object has not been moved. Blocking operations run
// until operation is completed. Non-blocking operations fail if there is
// not enough space
void read(T& data) noexcept; // blocking read
void write(const T& data) noexcept; // blocking write
void write(T&& data) noexcept; // blocking write
bool try_read(T& data) noexcept; // non-blocking read
bool try_write(const T& data) noexcept; // non-blocking write
bool try_write(T&& data) noexcept; // non-blocking write
private:
////////////////////////////////////////////////////////////////////////////
// PRIVATE HELPER FUNCTIONS
////////////////////////////////////////////////////////////////////////////
void destruct_();
}; // class Ring<T>
template <class T>
Ring<T>::Ring()
: Ring_()
{ }
template <class T>
Ring<T>::Ring(std::size_t size)
: Ring_(size * sizeof(T))
{ }
template <class T>
Ring<T>::Ring(Ring<T>&& ring)
: Ring_(std::move(ring))
{ }
template <class T>
Ring<T>& Ring<T>::operator= (Ring<T>&& ring)
{
destruct_();
Ring_::operator= (ring);
return *this;
}
template <class T>
Ring<T>::~Ring()
{
destruct_();
}
template <class T>
void Ring<T>::destruct_()
{
if (size() == 0)
return;
auto itr = begin_data_();
auto end = end_data_();
do
{
auto t = reinterpret_cast<T*>(itr);
t->~T();
itr = normalize_(itr + sizeof(T));
} while (itr != end);
}
template <class T>
std::size_t Ring<T>::size() const
{
return Ring_::size() / sizeof(T);
}
template <class T>
std::size_t Ring<T>::capacity() const
{
return Ring_::capacity() / sizeof(T);
}
template <class T>
void Ring<T>::read(T& data) noexcept
{
static_assert(std::is_nothrow_move_assignable<T>::value, "T move assignment must not throw");
static_assert(std::is_nothrow_destructible<T>::value, "T destructor must not throw");
auto block = acquire_read_block_(sizeof(T));
// critical section
auto t = reinterpret_cast<T*>(block);
data = std::move(*t);
t->~T();
release_read_block_(block, sizeof(T));
}
template <class T>
void Ring<T>::write(const T& data) noexcept
{
static_assert(std::is_nothrow_copy_constructible<T>::value, "T copy constructor must not throw");
auto block = acquire_write_block_(sizeof(T));
// critical section
new(block) T(data);
release_write_block_(block, sizeof(T));
}
template <class T>
void Ring<T>::write(T&& data) noexcept
{
static_assert(std::is_nothrow_move_constructible<T>::value, "T move constructor must not throw");
auto block = acquire_write_block_(sizeof(T));
// critical section
new(block) T(std::move(data));
release_write_block_(block, sizeof(T));
}
template <class T>
bool Ring<T>::try_read(T& data) noexcept
{
static_assert(std::is_nothrow_move_assignable<T>::value, "T move assignment must not throw");
static_assert(std::is_nothrow_destructible<T>::value, "T destructor must not throw");
auto block = try_acquire_read_block_(sizeof(T));
if (block == nullptr)
return false;
// critical section
auto t = reinterpret_cast<T*>(block);
data = std::move(*t);
t->~T();
release_read_block_(block, sizeof(T));
return true;
}
template <class T>
bool Ring<T>::try_write(const T& data) noexcept
{
static_assert(std::is_nothrow_copy_constructible<T>::value, "T copy constructor must not throw");
auto block = try_acquire_write_block_(sizeof(T));
if (block == nullptr)
return false;
// critical section
new(block) T(data);
release_write_block_(block, sizeof(T));
return true;
}
template <class T>
bool Ring<T>::try_write(T&& data) noexcept
{
static_assert(std::is_nothrow_move_constructible<T>::value, "T move constructor must not throw");
auto block = try_acquire_write_block_(sizeof(T));
if (block == nullptr)
return false;
// critical section
new(block) T(std::move(data));
release_write_block_(block, sizeof(T));
return true;
}
} // namespace wilt
#endif // !WILT_RING_H

@ -1 +0,0 @@
Subproject commit c9bf99d414cf81d19ef0ddd00212a4a58ccd99c6

401
rthandler.cpp 100644
Wyświetl plik

@ -0,0 +1,401 @@
#include "rthandler.h"
#include "logcategories.h"
#if defined(Q_OS_WIN)
#include <objbase.h>
#endif
#undef RT_EXCEPTION
rtHandler::rtHandler(QObject* parent)
{
Q_UNUSED(parent)
}
rtHandler::~rtHandler()
{
if (converterThread != Q_NULLPTR) {
converterThread->quit();
converterThread->wait();
}
if (isInitialized) {
#ifdef RT_EXCEPTION
try {
#endif
audio->abortStream();
audio->closeStream();
#ifdef RT_EXCEPTION
}
catch (RtAudioError& e) {
qInfo(logAudio()) << "Error closing stream:" << aParams.deviceId << ":" << QString::fromStdString(e.getMessage());
}
#endif
delete audio;
}
}
bool rtHandler::init(audioSetup setup)
{
if (isInitialized) {
return false;
}
this->setup = setup;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "RTAudio handler starting:" << setup.name;
if (setup.portInt==-1)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "No audio device was found.";
return false;
}
radioFormat = toQAudioFormat(setup.codec, setup.sampleRate);
qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name <<
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
", bits" << radioFormat.sampleSize() <<
#else
", format" << radioFormat.sampleFormat() <<
#endif
", codec" << setup.codec <<
", latency" << setup.latency <<
", localAFGain" << setup.localAFgain <<
", radioChan" << radioFormat.channelCount() <<
", resampleQuality" << setup.resampleQuality <<
", samplerate" << radioFormat.sampleRate() <<
", uLaw" << setup.ulaw;
#if !defined(Q_OS_MACX)
options.flags = ((!RTAUDIO_HOG_DEVICE) | (RTAUDIO_MINIMIZE_LATENCY));
//options.flags = RTAUDIO_MINIMIZE_LATENCY;
#endif
#if defined(Q_OS_LINUX)
audio = new RtAudio(RtAudio::Api::LINUX_ALSA);
#elif defined(Q_OS_WIN)
audio = new RtAudio(RtAudio::Api::WINDOWS_WASAPI);
#elif defined(Q_OS_MACX)
audio = new RtAudio(RtAudio::Api::MACOSX_CORE);
#endif
codecType codec = LPCM;
if (setup.codec == 0x01 || setup.codec == 0x20)
codec = PCMU;
else if (setup.codec == 0x40 || setup.codec == 0x40)
codec = OPUS;
options.numberOfBuffers = int(setup.latency/setup.blockSize);
if (setup.portInt > 0) {
aParams.deviceId = setup.portInt;
}
else if (setup.isinput) {
aParams.deviceId = audio->getDefaultInputDevice();
}
else {
aParams.deviceId = audio->getDefaultOutputDevice();
}
aParams.firstChannel = 0;
#ifdef RT_EXCEPTION
try {
#endif
info = audio->getDeviceInfo(aParams.deviceId);
#ifdef RT_EXCEPTION
}
catch (RtAudioError e) {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Device exception:" << aParams.deviceId << ":" << QString::fromStdString(e.getMessage());
goto errorHandler;
}
#endif
#ifdef RT_EXCEPTION
if (info.probed)
{
#endif
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") successfully probed";
RtAudioFormat sampleFormat;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
nativeFormat.setByteOrder(QAudioFormat::LittleEndian);
nativeFormat.setCodec("audio/pcm");
#endif
if (info.nativeFormats == 0)
{
qCritical(logAudio()) << " No natively supported data formats!";
goto errorHandler;
}
else {
qDebug(logAudio()) << " Supported formats:" <<
(info.nativeFormats & RTAUDIO_SINT8 ? "8-bit int," : "") <<
(info.nativeFormats & RTAUDIO_SINT16 ? "16-bit int," : "") <<
(info.nativeFormats & RTAUDIO_SINT24 ? "24-bit int," : "") <<
(info.nativeFormats & RTAUDIO_SINT32 ? "32-bit int," : "") <<
(info.nativeFormats & RTAUDIO_FLOAT32 ? "32-bit float," : "") <<
(info.nativeFormats & RTAUDIO_FLOAT64 ? "64-bit float," : "");
qInfo(logAudio()) << " Preferred sample rate:" << info.preferredSampleRate;
if (setup.isinput) {
nativeFormat.setChannelCount(info.inputChannels);
}
else {
nativeFormat.setChannelCount(info.outputChannels);
}
qInfo(logAudio()) << " Channels:" << nativeFormat.channelCount();
if (nativeFormat.channelCount() > 2) {
nativeFormat.setChannelCount(2);
}
else if (nativeFormat.channelCount() < 1)
{
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "No channels found, aborting setup.";
goto errorHandler;
}
if (nativeFormat.channelCount() == 1 && radioFormat.channelCount() == 2) {
nativeFormat.setChannelCount(2);
}
aParams.nChannels = nativeFormat.channelCount();
nativeFormat.setSampleRate(info.preferredSampleRate);
if (nativeFormat.sampleRate() < 44100) {
nativeFormat.setSampleRate(48000);
}
if (info.nativeFormats & RTAUDIO_FLOAT32) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
nativeFormat.setSampleType(QAudioFormat::Float);
nativeFormat.setSampleSize(32);
#else
nativeFormat.setSampleFormat(QAudioFormat::Float);
#endif
sampleFormat = RTAUDIO_FLOAT32;
}
else if (info.nativeFormats & RTAUDIO_SINT32) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
nativeFormat.setSampleType(QAudioFormat::SignedInt);
nativeFormat.setSampleSize(32);
#else
nativeFormat.setSampleFormat(QAudioFormat::Int32);
#endif
sampleFormat = RTAUDIO_SINT32;
}
else if (info.nativeFormats & RTAUDIO_SINT16) {
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
nativeFormat.setSampleType(QAudioFormat::SignedInt);
nativeFormat.setSampleSize(16);
#else
nativeFormat.setSampleFormat(QAudioFormat::Int16);
#endif
sampleFormat = RTAUDIO_SINT16;
}
else {
qCritical(logAudio()) << "Cannot find supported sample format!";
goto errorHandler;
}
}
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << nativeFormat.sampleSize() << "Channel Count" << nativeFormat.channelCount() <<
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << nativeFormat.codec() << "Sample Type" << nativeFormat.sampleType();
#else
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleFormat" << nativeFormat.sampleFormat() << "Channel Count" << nativeFormat.channelCount() <<
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec;
#endif
// We "hopefully" now have a valid format that is supported so try connecting
converter = new audioConverter();
converterThread = new QThread(this);
if (setup.isinput) {
converterThread->setObjectName("audioConvIn()");
}
else {
converterThread->setObjectName("audioConvOut()");
}
converter->moveToThread(converterThread);
connect(this, SIGNAL(setupConverter(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)), converter, SLOT(init(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)));
connect(converterThread, SIGNAL(finished()), converter, SLOT(deleteLater()));
connect(this, SIGNAL(sendToConverter(audioPacket)), converter, SLOT(convert(audioPacket)));
converterThread->start(QThread::TimeCriticalPriority);
// Per channel chunk size.
this->chunkSize = nativeFormat.framesForDuration(setup.blockSize * 1000);
#ifdef RT_EXCEPTION
try {
#endif
if (setup.isinput) {
audio->openStream(NULL, &aParams, sampleFormat, nativeFormat.sampleRate(), &this->chunkSize, &staticWrite, this, &options);
emit setupConverter(nativeFormat, codecType::LPCM, radioFormat, codec, 7, setup.resampleQuality);
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedInput(audioPacket)));
}
else {
audio->openStream(&aParams, NULL, sampleFormat, nativeFormat.sampleRate(), &this->chunkSize, &staticRead, this , &options);
emit setupConverter(radioFormat, codec, nativeFormat, codecType::LPCM, 7, setup.resampleQuality);
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedOutput(audioPacket)));
}
audio->startStream();
isInitialized = true;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "device successfully opened";
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "detected latency:" << audio->getStreamLatency();
#ifdef RT_EXCEPTION
}
catch (RtAudioError& e) {
qInfo(logAudio()) << "Error opening:" << QString::fromStdString(e.getMessage());
// Try again?
goto errorHandler;
}
#endif
#ifdef RT_EXCEPTION
}
else
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") could not be probed, check audio configuration!";
goto errorHandler;
}
#endif
this->setVolume(setup.localAFgain);
return isInitialized;
errorHandler:
if (retryConnectCount < 10) {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "*** Attempting to reconnect to audio device in 500ms";
QTimer::singleShot(500, this, std::bind(&rtHandler::init, this, setup));
retryConnectCount++;
}
else
{
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "*** Retry count exceeded, giving up!";
}
return false;
}
void rtHandler::setVolume(unsigned char volume)
{
this->volume = audiopot[volume];
}
void rtHandler::incomingAudio(audioPacket packet)
{
packet.volume = volume;
emit sendToConverter(packet);
return;
}
int rtHandler::readData(void* outputBuffer, void* inputBuffer,
unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
{
Q_UNUSED(inputBuffer);
Q_UNUSED(streamTime);
int nBytes = nFrames * nativeFormat.bytesPerFrame();
//lastSentSeq = packet.seq;
if (arrayBuffer.length() >= nBytes) {
if (audioMutex.tryLock(0)) {
std::memcpy(outputBuffer, arrayBuffer.constData(), nBytes);
arrayBuffer.remove(0, nBytes);
audioMutex.unlock();
}
}
if (status == RTAUDIO_INPUT_OVERFLOW) {
isUnderrun = true;
}
else if (status == RTAUDIO_OUTPUT_UNDERFLOW) {
isOverrun = true;
}
else
{
isUnderrun = false;
isOverrun = false;
}
return 0;
}
int rtHandler::writeData(void* outputBuffer, void* inputBuffer,
unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
{
Q_UNUSED(outputBuffer);
Q_UNUSED(streamTime);
Q_UNUSED(status);
audioPacket packet;
packet.time = QTime::currentTime();
packet.sent = 0;
packet.volume = volume;
memcpy(&packet.guid, setup.guid, GUIDLEN);
packet.data.append((char*)inputBuffer, nFrames * nativeFormat.bytesPerFrame());
emit sendToConverter(packet);
if (status == RTAUDIO_INPUT_OVERFLOW) {
isUnderrun = true;
}
else if (status == RTAUDIO_OUTPUT_UNDERFLOW) {
isOverrun = true;
}
else
{
isUnderrun = false;
isOverrun = false;
}
return 0;
}
void rtHandler::convertedOutput(audioPacket packet)
{
audioMutex.lock();
arrayBuffer.append(packet.data);
audioMutex.unlock();
amplitude = packet.amplitudePeak;
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (nativeFormat.durationForBytes(audio->getStreamLatency() * nativeFormat.bytesPerFrame()) / 1000);
emit haveLevels(getAmplitude(), packet.amplitudeRMS, setup.latency, currentLatency, isUnderrun, isOverrun);
}
void rtHandler::convertedInput(audioPacket packet)
{
if (packet.data.size() > 0) {
emit haveAudioData(packet);
amplitude = packet.amplitudePeak;
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (nativeFormat.durationForBytes(audio->getStreamLatency() * nativeFormat.bytesPerFrame()) / 1000);
emit haveLevels(getAmplitude(), static_cast<quint16>(packet.amplitudeRMS * 255.0), setup.latency, currentLatency, isUnderrun, isOverrun);
}
}
void rtHandler::changeLatency(const quint16 newSize)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << setup.latency;
}
int rtHandler::getLatency()
{
return currentLatency;
}
quint16 rtHandler::getAmplitude()
{
return static_cast<quint16>(amplitude * 255.0);
}

115
rthandler.h 100644
Wyświetl plik

@ -0,0 +1,115 @@
#ifndef rtHandler_H
#define rtHandler_H
#include <QObject>
#include <QByteArray>
#include <QThread>
#include <QMutex>
#ifndef Q_OS_LINUX
#include "RtAudio.h"
#else
#include "rtaudio/RtAudio.h"
#endif
#include <QAudioFormat>
#include <QTime>
#include <QMap>
#include <QTimer>
/* wfview Packet types */
#include "packettypes.h"
/* Logarithmic taper for volume control */
#include "audiotaper.h"
#include "audiohandler.h"
/* Audio converter class*/
#include "audioconverter.h"
#include <QDebug>
class rtHandler : public audioHandler
{
Q_OBJECT
public:
rtHandler(QObject* parent = 0);
~rtHandler();
int getLatency();
using audioHandler::getNextAudioChunk;
void getNextAudioChunk(QByteArray& data);
quint16 getAmplitude();
public slots:
bool init(audioSetup setup);
void changeLatency(const quint16 newSize);
void setVolume(unsigned char volume);
void convertedInput(audioPacket audio);
void convertedOutput(audioPacket audio);
void incomingAudio(const audioPacket data);
private slots:
signals:
void audioMessage(QString message);
void sendLatency(quint16 newSize);
void haveAudioData(const audioPacket& data);
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS, quint16 latency, quint16 current, bool under, bool over);
void setupConverter(QAudioFormat in, codecType codecIn, QAudioFormat out, codecType codecOut, quint8 opus, quint8 resamp);
void sendToConverter(audioPacket audio);
private:
int readData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status);
static int staticRead(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
return static_cast<rtHandler*>(userData)->readData(outputBuffer, inputBuffer, nFrames, streamTime, status);
}
int writeData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status);
static int staticWrite(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
return static_cast<rtHandler*>(userData)->writeData(outputBuffer, inputBuffer, nFrames, streamTime, status);
}
bool isInitialized = false;
RtAudio* audio = Q_NULLPTR;
int audioDevice = 0;
RtAudio::StreamParameters aParams;
RtAudio::StreamOptions options;
RtAudio::DeviceInfo info;
quint16 audioLatency;
unsigned int chunkSize;
quint32 lastSeq;
quint32 lastSentSeq = 0;
quint16 currentLatency;
float amplitude = 0.0;
qreal volume = 1.0;
audioSetup setup;
QAudioFormat radioFormat;
QAudioFormat nativeFormat;
audioConverter* converter = Q_NULLPTR;
QThread* converterThread = Q_NULLPTR;
QByteArray arrayBuffer;
bool isUnderrun = false;
bool isOverrun = false;
QMutex audioMutex;
int retryConnectCount = 0;
};
#endif // rtHandler_H

85
selectradio.cpp 100644
Wyświetl plik

@ -0,0 +1,85 @@
#include "logcategories.h"
#include "selectradio.h"
#include "ui_selectradio.h"
selectRadio::selectRadio(QWidget* parent) :
QDialog(parent),
ui(new Ui::selectRadio)
{
ui->setupUi(this);
}
selectRadio::~selectRadio()
{
delete ui;
}
void selectRadio::populate(QList<radio_cap_packet> radios)
{
ui->table->clearContents();
for (int row = ui->table->rowCount() - 1;row>=0; row--) {
ui->table->removeRow(row);
}
for (int row = 0; row < radios.count(); row++) {
ui->table->insertRow(ui->table->rowCount());
ui->table->setItem(row, 0, new QTableWidgetItem(QString(radios[row].name)));
ui->table->setItem(row, 1, new QTableWidgetItem(QString("%1").arg((unsigned char)radios[row].civ, 2, 16, QLatin1Char('0')).toUpper()));
ui->table->setItem(row, 2, new QTableWidgetItem(QString::number(qFromBigEndian(radios[row].baudrate))));
}
if (radios.count() > 1) {
this->setVisible(true);
}
}
void selectRadio::setInUse(quint8 radio, quint8 busy, QString user, QString ip)
{
//if ((radio > 0)&& !this->isVisible()) {
// qInfo() << "setInUse: radio:" << radio <<"busy" << busy << "user" << user << "ip"<<ip;
// this->setVisible(true);
//}
ui->table->setItem(radio, 3, new QTableWidgetItem(user));
ui->table->setItem(radio, 4, new QTableWidgetItem(ip));
for (int f = 0; f < 5; f++) {
if (busy == 1)
{
ui->table->item(radio, f)->setBackground(Qt::darkGreen);
}
else if (busy == 2)
{
ui->table->item(radio, f)->setBackground(Qt::red);
}
else
{
ui->table->item(radio, f)->setBackground(Qt::black);
}
}
}
void selectRadio::on_table_cellClicked(int row, int col) {
qInfo() << "Clicked on " << row << "," << col;
#if (QT_VERSION < QT_VERSION_CHECK(5,11,0))
if (ui->table->item(row, col)->backgroundColor() != Qt::darkGreen) {
#else
if (ui->table->item(row, col)->background() != Qt::darkGreen) {
#endif
ui->table->selectRow(row);
emit selectedRadio(row);
this->setVisible(false);
}
}
void selectRadio::on_cancelButton_clicked() {
this->setVisible(false);
}
void selectRadio::audioOutputLevel(quint16 level) {
ui->afLevel->setValue(level);
}
void selectRadio::audioInputLevel(quint16 level) {
ui->modLevel->setValue(level);
}

38
selectradio.h 100644
Wyświetl plik

@ -0,0 +1,38 @@
#ifndef SELECTRADIO_H
#define SELECTRADIO_H
#include <QDialog>
#include <QList>
#include <QtEndian>
#include <QHostInfo>
#include "packettypes.h"
namespace Ui {
class selectRadio;
}
class selectRadio : public QDialog
{
Q_OBJECT
public:
explicit selectRadio(QWidget* parent = 0);
~selectRadio();
void populate(QList<radio_cap_packet> radios);
void audioOutputLevel(quint16 level);
void audioInputLevel(quint16 level);
public slots:
void on_table_cellClicked(int row, int col);
void setInUse(quint8 radio, quint8 busy, QString user, QString ip);
void on_cancelButton_clicked();
signals:
void selectedRadio(quint8 radio);
private:
Ui::selectRadio* ui;
};
#endif // SELECTRADIO_H

157
selectradio.ui 100644
Wyświetl plik

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>selectRadio</class>
<widget class="QDialog" name="selectRadio">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>590</width>
<height>206</height>
</rect>
</property>
<property name="windowTitle">
<string>Select Radio From List</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableWidget" name="table">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Rig Name</string>
</property>
</column>
<column>
<property name="text">
<string>CI-V</string>
</property>
</column>
<column>
<property name="text">
<string>Baud Rate</string>
</property>
</column>
<column>
<property name="text">
<string>Current User</string>
</property>
</column>
<column>
<property name="text">
<string>User IP Address</string>
</property>
</column>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>AF</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="afLevel">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>MOD</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="modLevel">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

646
servermain.cpp 100644
Wyświetl plik

@ -0,0 +1,646 @@
#include "servermain.h"
#include "commhandler.h"
#include "rigidentities.h"
#include "logcategories.h"
#include <iostream>
// This code is copyright 2017-2020 Elliott H. Liggett
// All rights reserved
servermain::servermain(const QString settingsFile)
{
qRegisterMetaType <udpPreferences>(); // Needs to be registered early.
qRegisterMetaType <rigCapabilities>();
qRegisterMetaType <duplexMode>();
qRegisterMetaType <rptAccessTxRx>();
qRegisterMetaType <rptrAccessData_t>();
qRegisterMetaType <rptAccessTxRx>();
qRegisterMetaType <rigInput>();
qRegisterMetaType <meterKind>();
qRegisterMetaType <spectrumMode>();
qRegisterMetaType <freqt>();
qRegisterMetaType <mode_info>();
qRegisterMetaType <audioPacket>();
qRegisterMetaType <audioSetup>();
qRegisterMetaType <SERVERCONFIG>();
qRegisterMetaType <timekind>();
qRegisterMetaType <datekind>();
qRegisterMetaType<rigstate*>();
qRegisterMetaType<QList<radio_cap_packet>>();
qRegisterMetaType<networkStatus>();
qRegisterMetaType<codecType>();
qRegisterMetaType<errorType>();
setDefPrefs();
getSettingsFilePath(settingsFile);
loadSettings(); // Look for saved preferences
audioDev = new audioDevices(prefs.audioSystem, QFontMetrics(QFont()));
connect(audioDev, SIGNAL(updated()), this, SLOT(updateAudioDevices()));
audioDev->enumerate();
setInitialTiming();
openRig();
setServerToPrefs();
amTransmitting = false;
}
servermain::~servermain()
{
for (RIGCONFIG* radio : serverConfig.rigs)
{
if (radio->rigThread != Q_NULLPTR)
{
radio->rigThread->quit();
radio->rigThread->wait();
}
delete radio; // This has been created by new in loadSettings();
}
serverConfig.rigs.clear();
if (serverThread != Q_NULLPTR) {
serverThread->quit();
serverThread->wait();
}
if (audioDev != Q_NULLPTR) {
delete audioDev;
}
delete settings;
#if defined(PORTAUDIO)
Pa_Terminate();
#endif
}
void servermain::openRig()
{
// This function is intended to handle opening a connection to the rig.
// the connection can be either serial or network,
// and this function is also responsible for initiating the search for a rig model and capabilities.
// Any errors, such as unable to open connection or unable to open port, are to be reported to the user.
makeRig();
for (RIGCONFIG* radio : serverConfig.rigs)
{
//qInfo(logSystem()) << "Opening rig";
if (radio->rigThread != Q_NULLPTR)
{
//qInfo(logSystem()) << "Got rig";
QMetaObject::invokeMethod(radio->rig, [=]() {
radio->rig->commSetup(radio->civAddr, radio->serialPort, radio->baudRate, QString("none"),0 ,radio->waterfallFormat);
}, Qt::QueuedConnection);
}
}
}
void servermain::makeRig()
{
for (RIGCONFIG* radio : serverConfig.rigs)
{
if (radio->rigThread == Q_NULLPTR)
{
qInfo(logSystem()) << "Creating new rigThread()";
radio->rig = new rigCommander(radio->guid);
radio->rigThread = new QThread(this);
radio->rigThread->setObjectName("rigCommander()");
// Thread:
radio->rig->moveToThread(radio->rigThread);
connect(radio->rigThread, SIGNAL(started()), radio->rig, SLOT(process()));
connect(radio->rigThread, SIGNAL(finished()), radio->rig, SLOT(deleteLater()));
radio->rigThread->start();
// Rig status and Errors:
connect(radio->rig, SIGNAL(havePortError(errorType)), this, SLOT(receivePortError(errorType)));
connect(radio->rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus)));
// Rig comm setup:
connect(this, SIGNAL(setRTSforPTT(bool)), radio->rig, SLOT(setRTSforPTT(bool)));
connect(radio->rig, SIGNAL(haveBaudRate(quint32)), this, SLOT(receiveBaudRate(quint32)));
connect(this, SIGNAL(sendCloseComm()), radio->rig, SLOT(closeComm()));
connect(this, SIGNAL(sendChangeLatency(quint16)), radio->rig, SLOT(changeLatency(quint16)));
//connect(this, SIGNAL(getRigCIV()), radio->rig, SLOT(findRigs()));
//connect(this, SIGNAL(setRigID(unsigned char)), radio->rig, SLOT(setRigID(unsigned char)));
connect(radio->rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities)));
connect(radio->rig, SIGNAL(commReady()), this, SLOT(receiveCommReady()));
connect(this, SIGNAL(requestRigState()), radio->rig, SLOT(sendState()));
connect(this, SIGNAL(stateUpdated()), radio->rig, SLOT(stateUpdated()));
connect(radio->rig, SIGNAL(stateInfo(rigstate*)), this, SLOT(receiveStateInfo(rigstate*)));
//Other connections
connect(this, SIGNAL(setCIVAddr(unsigned char)), radio->rig, SLOT(setCIVAddr(unsigned char)));
connect(radio->rig, SIGNAL(havePTTStatus(bool)), this, SLOT(receivePTTstatus(bool)));
connect(this, SIGNAL(setPTT(bool)), radio->rig, SLOT(setPTT(bool)));
connect(this, SIGNAL(getPTT()), radio->rig, SLOT(getPTT()));
connect(this, SIGNAL(getDebug()), radio->rig, SLOT(getDebug()));
if (radio->rigThread->isRunning()) {
qInfo(logSystem()) << "Rig thread is running";
}
else {
qInfo(logSystem()) << "Rig thread is not running";
}
}
}
}
void servermain::removeRig()
{
for (RIGCONFIG* radio : serverConfig.rigs)
{
if (radio->rigThread != Q_NULLPTR)
{
radio->rigThread->disconnect();
radio->rig->disconnect();
delete radio->rigThread;
delete radio->rig;
radio->rig = Q_NULLPTR;
}
}
}
void servermain::findSerialPort()
{
// Find the ICOM radio connected, or, if none, fall back to OS default.
// qInfo(logSystem()) << "Searching for serial port...";
QDirIterator it73("/dev/serial/by-id", QStringList() << "*IC-7300*", QDir::Files, QDirIterator::Subdirectories);
QDirIterator it97("/dev/serial", QStringList() << "*IC-9700*A*", QDir::Files, QDirIterator::Subdirectories);
QDirIterator it785x("/dev/serial", QStringList() << "*IC-785*A*", QDir::Files, QDirIterator::Subdirectories);
QDirIterator it705("/dev/serial", QStringList() << "*IC-705*A", QDir::Files, QDirIterator::Subdirectories);
QDirIterator it7610("/dev/serial", QStringList() << "*IC-7610*A", QDir::Files, QDirIterator::Subdirectories);
QDirIterator itR8600("/dev/serial", QStringList() << "*IC-R8600*A", QDir::Files, QDirIterator::Subdirectories);
if(!it73.filePath().isEmpty())
{
// IC-7300
serialPortRig = it73.filePath(); // first
} else if(!it97.filePath().isEmpty())
{
// IC-9700
serialPortRig = it97.filePath();
} else if(!it785x.filePath().isEmpty())
{
// IC-785x
serialPortRig = it785x.filePath();
} else if(!it705.filePath().isEmpty())
{
// IC-705
serialPortRig = it705.filePath();
} else if(!it7610.filePath().isEmpty())
{
// IC-7610
serialPortRig = it7610.filePath();
} else if(!itR8600.filePath().isEmpty())
{
// IC-R8600
serialPortRig = itR8600.filePath();
} else {
//fall back:
qInfo(logSystem()) << "Could not find Icom serial port. Falling back to OS default. Use --port to specify, or modify preferences.";
#ifdef Q_OS_MAC
serialPortRig = QString("/dev/tty.SLAB_USBtoUART");
#endif
#ifdef Q_OS_LINUX
serialPortRig = QString("/dev/ttyUSB0");
#endif
#ifdef Q_OS_WIN
serialPortRig = QString("COM1");
#endif
}
}
void servermain::receiveStatusUpdate(networkStatus status)
{
if (status.message != lastMessage) {
std::cout << status.message.toLocal8Bit().toStdString() << "\n";
lastMessage = status.message;
}
}
void servermain::receiveCommReady()
{
rigCommander* sender = qobject_cast<rigCommander*>(QObject::sender());
// Use the GUID to determine which radio the response is from
for (RIGCONFIG* radio : serverConfig.rigs)
{
if (sender != Q_NULLPTR && radio->rig != Q_NULLPTR && !memcmp(sender->getGUID(), radio->guid, GUIDLEN))
{
qInfo(logSystem()) << "Received CommReady!! ";
if (radio->civAddr == 0)
{
// tell rigCommander to broadcast a request for all rig IDs.
// qInfo(logSystem()) << "Beginning search from wfview for rigCIV (auto-detection broadcast)";
if (!radio->rigAvailable) {
if (radio->connectTimer == Q_NULLPTR) {
radio->connectTimer = new QTimer();
connect(radio->connectTimer, &QTimer::timeout, this, std::bind(&servermain::connectToRig, this, radio));
}
radio->connectTimer->start(500);
}
}
else {
// don't bother, they told us the CIV they want, stick with it.
// We still query the rigID to find the model, but at least we know the CIV.
qInfo(logSystem()) << "Skipping automatic CIV, using user-supplied value of " << radio->civAddr;
QMetaObject::invokeMethod(radio->rig, [=]() {
radio->rig->setRigID(radio->civAddr);
}, Qt::QueuedConnection);
}
}
}
}
void servermain::connectToRig(RIGCONFIG* rig)
{
if (!rig->rigAvailable) {
qDebug(logSystem()) << "Searching for rig on" << rig->serialPort;
QMetaObject::invokeMethod(rig->rig, [=]() {
rig->rig->findRigs();
}, Qt::QueuedConnection);
}
else {
rig->connectTimer->stop();
}
}
void servermain::receiveFoundRigID(rigCapabilities rigCaps)
{
// Entry point for unknown rig being identified at the start of the program.
//now we know what the rig ID is:
rigCommander* sender = qobject_cast<rigCommander*>(QObject::sender());
// Use the GUID to determine which radio the response is from
for (RIGCONFIG* radio : serverConfig.rigs)
{
if (sender != Q_NULLPTR && radio->rig != Q_NULLPTR && !radio->rigAvailable && !memcmp(sender->getGUID(), radio->guid, GUIDLEN))
{
qDebug(logSystem()) << "Rig name: " << rigCaps.modelName;
qDebug(logSystem()) << "Has LAN capabilities: " << rigCaps.hasLan;
qDebug(logSystem()) << "Rig ID received into servermain: spectLenMax: " << rigCaps.spectLenMax;
qDebug(logSystem()) << "Rig ID received into servermain: spectAmpMax: " << rigCaps.spectAmpMax;
qDebug(logSystem()) << "Rig ID received into servermain: spectSeqMax: " << rigCaps.spectSeqMax;
qDebug(logSystem()) << "Rig ID received into servermain: hasSpectrum: " << rigCaps.hasSpectrum;
qDebug(logSystem()).noquote() << QString("Rig ID received into servermain: GUID: {%1%2%3%4-%5%6-%7%8-%9%10-%11%12%13%14%15%16}")
.arg(rigCaps.guid[0], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[1], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[2], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[3], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[4], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[5], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[6], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[7], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[8], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[9], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[10], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[11], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[12], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[13], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[14], 2, 16, QLatin1Char('0'))
.arg(rigCaps.guid[15], 2, 16, QLatin1Char('0'))
;
radio->rigCaps = rigCaps;
// Added so that server receives rig capabilities.
emit sendRigCaps(rigCaps);
}
}
return;
}
void servermain::receivePortError(errorType err)
{
qInfo(logSystem()) << "servermain: received error for device: " << err.device << " with message: " << err.message;
}
void servermain::getSettingsFilePath(QString settingsFile)
{
if (settingsFile.isNull()) {
settings = new QSettings();
}
else
{
QString file = settingsFile;
QFile info(settingsFile);
QString path="";
if (!QFileInfo(info).isAbsolute())
{
path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if (path.isEmpty())
{
path = QDir::homePath();
}
path = path + "/";
file = info.fileName();
}
qInfo(logSystem()) << "Loading settings from:" << path + file;
settings = new QSettings(path + file, QSettings::Format::IniFormat);
}
}
void servermain::setInitialTiming()
{
loopTickCounter = 0;
pttTimer = new QTimer(this);
pttTimer->setInterval(180*1000); // 3 minute max transmit time in ms
pttTimer->setSingleShot(true);
connect(pttTimer, SIGNAL(timeout()), this, SLOT(handlePttLimit()));
}
void servermain::setServerToPrefs()
{
// Start server if enabled in config
if (serverThread != Q_NULLPTR) {
serverThread->quit();
serverThread->wait();
serverThread = Q_NULLPTR;
udp = Q_NULLPTR;
}
udp = new udpServer(&serverConfig);
serverThread = new QThread(this);
serverThread->setObjectName("udpServer()");
udp->moveToThread(serverThread);
connect(this, SIGNAL(initServer()), udp, SLOT(init()));
connect(serverThread, SIGNAL(finished()), udp, SLOT(deleteLater()));
// Step through all radios and connect them to the server,
// server will then use GUID to determine which actual radio it belongs to.
for (RIGCONFIG* radio : serverConfig.rigs)
{
if (radio->rigThread != Q_NULLPTR)
{
if (radio->rig != Q_NULLPTR) {
connect(radio->rig, SIGNAL(haveAudioData(audioPacket)), udp, SLOT(receiveAudioData(audioPacket)));
connect(radio->rig, SIGNAL(haveDataForServer(QByteArray)), udp, SLOT(dataForServer(QByteArray)));
//connect(udp, SIGNAL(haveDataFromServer(QByteArray)), radio->rig, SLOT(dataFromServer(QByteArray)));
connect(this, SIGNAL(sendRigCaps(rigCapabilities)), udp, SLOT(receiveRigCaps(rigCapabilities)));
}
}
}
connect(udp, SIGNAL(haveNetworkStatus(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus)));
serverThread->start();
emit initServer();
}
void servermain::setDefPrefs()
{
defPrefs.radioCIVAddr = 0x00; // previously was 0x94 for 7300.
defPrefs.CIVisRadioModel = false;
defPrefs.forceRTSasPTT = false;
defPrefs.serialPortRadio = QString("auto");
defPrefs.serialPortBaud = 115200;
defPrefs.localAFgain = 255;
defPrefs.tcpPort = 0;
defPrefs.audioSystem = qtAudio;
defPrefs.rxAudio.name = QString("default");
defPrefs.txAudio.name = QString("default");
udpDefPrefs.ipAddress = QString("");
udpDefPrefs.controlLANPort = 50001;
udpDefPrefs.serialLANPort = 50002;
udpDefPrefs.audioLANPort = 50003;
udpDefPrefs.username = QString("");
udpDefPrefs.password = QString("");
udpDefPrefs.clientName = QHostInfo::localHostName();
}
void servermain::loadSettings()
{
qInfo(logSystem()) << "Loading settings from " << settings->fileName();
prefs.audioSystem = static_cast<audioType>(settings->value("AudioSystem", defPrefs.audioSystem).toInt());
int numRadios = settings->beginReadArray("Radios");
if (numRadios == 0) {
settings->endArray();
// We assume that QSettings is empty as there are no radios configured, create new:
qInfo(logSystem()) << "Creating new settings file " << settings->fileName();
settings->setValue("AudioSystem", defPrefs.audioSystem);
numRadios = 1;
settings->beginWriteArray("Radios");
for (int i = 0; i < numRadios; i++)
{
settings->setArrayIndex(i);
settings->setValue("RigCIVuInt", defPrefs.radioCIVAddr);
settings->setValue("ForceRTSasPTT", defPrefs.forceRTSasPTT);
settings->setValue("SerialPortRadio", defPrefs.serialPortRadio);
settings->setValue("RigName", "<NONE>");
settings->setValue("SerialPortBaud", defPrefs.serialPortBaud);
settings->setValue("AudioInput", "default");
settings->setValue("AudioOutput", "default");
settings->setValue("WaterfallFormat", 0);
}
settings->endArray();
settings->beginGroup("Server");
settings->setValue("ServerEnabled", true);
settings->setValue("ServerControlPort", udpDefPrefs.controlLANPort);
settings->setValue("ServerCivPort", udpDefPrefs.serialLANPort);
settings->setValue("ServerAudioPort", udpDefPrefs.audioLANPort);
settings->beginWriteArray("Users");
settings->setArrayIndex(0);
settings->setValue("Username", "user");
QByteArray pass;
passcode("password", pass);
settings->setValue("Password", QString(pass));
settings->setValue("UserType", 0);
settings->endArray();
settings->endGroup();
settings->sync();
} else {
settings->endArray();
}
numRadios = settings->beginReadArray("Radios");
int tempNum = numRadios;
for (int i = 0; i < numRadios; i++) {
settings->setArrayIndex(i);
RIGCONFIG* tempPrefs = new RIGCONFIG();
tempPrefs->civAddr = (unsigned char)settings->value("RigCIVuInt", defPrefs.radioCIVAddr).toInt();
tempPrefs->forceRTSasPTT = (bool)settings->value("ForceRTSasPTT", defPrefs.forceRTSasPTT).toBool();
tempPrefs->serialPort = settings->value("SerialPortRadio", defPrefs.serialPortRadio).toString();
tempPrefs->rigName = settings->value("RigName", "<NONE>").toString();
tempPrefs->baudRate = (quint32)settings->value("SerialPortBaud", defPrefs.serialPortBaud).toInt();
tempPrefs->rxAudioSetup.name = settings->value("AudioInput", "default").toString();
tempPrefs->txAudioSetup.name = settings->value("AudioOutput", "default").toString();
tempPrefs->waterfallFormat = settings->value("WaterfallFormat", 0).toInt();
tempPrefs->rxAudioSetup.type = prefs.audioSystem;
tempPrefs->txAudioSetup.type = prefs.audioSystem;
if (tempPrefs->serialPort == "auto") {
foreach(const QSerialPortInfo & serialPortInfo, QSerialPortInfo::availablePorts())
{
qDebug(logSystem()) << "Serial Port found: " << serialPortInfo.portName() << "Manufacturer:" << serialPortInfo.manufacturer() << "Product ID" << serialPortInfo.description() << "S/N" << serialPortInfo.serialNumber();
if (serialPortInfo.serialNumber().startsWith("IC-") && tempPrefs->serialPort == "auto") {
tempPrefs->rigName = serialPortInfo.serialNumber();
tempPrefs->serialPort = serialPortInfo.portName();
}
}
}
QString guid = settings->value("GUID", "").toString();
if (guid.isEmpty()) {
guid = QUuid::createUuid().toString();
settings->setValue("GUID", guid);
}
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
memcpy(tempPrefs->guid, QUuid::fromString(guid).toRfc4122().constData(), GUIDLEN);
#endif
tempPrefs->rxAudioSetup.isinput = true;
tempPrefs->txAudioSetup.isinput = false;
tempPrefs->rxAudioSetup.localAFgain = 255;
tempPrefs->txAudioSetup.localAFgain = 255;
tempPrefs->rxAudioSetup.resampleQuality = 4;
tempPrefs->txAudioSetup.resampleQuality = 4;
tempPrefs->rig = Q_NULLPTR;
tempPrefs->rigThread = Q_NULLPTR;
serverConfig.rigs.append(tempPrefs);
if (tempNum == 0) {
settings->endGroup();
}
}
if (tempNum > 0) {
settings->endArray();
}
settings->beginGroup("Server");
serverConfig.enabled = settings->value("ServerEnabled", false).toBool();
serverConfig.controlPort = settings->value("ServerControlPort", 50001).toInt();
serverConfig.civPort = settings->value("ServerCivPort", 50002).toInt();
serverConfig.audioPort = settings->value("ServerAudioPort", 50003).toInt();
serverConfig.users.clear();
int numUsers = settings->beginReadArray("Users");
if (numUsers > 0) {
{
for (int f = 0; f < numUsers; f++)
{
settings->setArrayIndex(f);
SERVERUSER user;
user.username = settings->value("Username", "").toString();
user.password = settings->value("Password", "").toString();
user.userType = settings->value("UserType", 0).toInt();
serverConfig.users.append(user);
}
}
settings->endArray();
}
settings->endGroup();
settings->sync();
#if defined(RTAUDIO)
delete audio;
#endif
}
void servermain::updateAudioDevices()
{
for (RIGCONFIG* rig : serverConfig.rigs)
{
qDebug(logAudio()) << "Rig" << rig->rigName << "configured rxAudio device:" << rig->rxAudioSetup.name;
qDebug(logAudio()) << "Rig" << rig->rigName << "configured txAudio device:" << rig->txAudioSetup.name;
int inputNum = audioDev->findInput(rig->rigName, rig->rxAudioSetup.name);
int outputNum = audioDev->findOutput(rig->rigName, rig->txAudioSetup.name);
if (prefs.audioSystem == qtAudio) {
rig->rxAudioSetup.port = audioDev->getInputDeviceInfo(inputNum);
rig->txAudioSetup.port = audioDev->getOutputDeviceInfo(outputNum);
}
else {
rig->rxAudioSetup.portInt = audioDev->getInputDeviceInt(inputNum);
rig->txAudioSetup.portInt = audioDev->getOutputDeviceInt(outputNum);
}
rig->rxAudioSetup.name = audioDev->getInputName(inputNum);
rig->txAudioSetup.name = audioDev->getOutputName(outputNum);
}
}
void servermain::receivePTTstatus(bool pttOn)
{
// This is the only place where amTransmitting and the transmit button text should be changed:
//qInfo(logSystem()) << "PTT status: " << pttOn;
amTransmitting = pttOn;
}
void servermain::handlePttLimit()
{
// ptt time exceeded!
std::cout << "Transmit timeout at 3 minutes. Sending PTT OFF command now.\n";
emit setPTT(false);
emit getPTT();
}
void servermain::receiveBaudRate(quint32 baud)
{
qInfo() << "Received serial port baud rate from remote server:" << baud;
prefs.serialPortBaud = baud;
}
void servermain::powerRigOn()
{
emit sendPowerOn();
}
void servermain::powerRigOff()
{
emit sendPowerOff();
}
void servermain::receiveStateInfo(rigstate* state)
{
qInfo("Received rig state for wfmain");
Q_UNUSED(state);
//rigState = state;
}

315
servermain.h 100644
Wyświetl plik

@ -0,0 +1,315 @@
#ifndef WFMAIN_H
#define WFMAIN_H
#include <QtCore/QCoreApplication>
#include <QtCore/QDirIterator>
#include <QtCore/QStandardPaths>
#include <QThread>
#include <QString>
#include <QVector>
#include <QTimer>
#include <QSettings>
#include <QShortcut>
#include <QMetaType>
#include "logcategories.h"
#include "commhandler.h"
#include "rigcommander.h"
#include "rigstate.h"
#include "freqmemory.h"
#include "rigidentities.h"
#include "repeaterattributes.h"
#include "audiodevices.h"
#include "udpserver.h"
#include "rigctld.h"
#include "signal.h"
#include <qserialportinfo.h>
#include <deque>
#include <memory>
#include <portaudio.h>
#ifdef Q_OS_WIN
#include "RtAudio.h"
#else
#include "rtaudio/RtAudio.h"
#endif
namespace Ui {
class wfmain;
}
class servermain : public QObject
{
Q_OBJECT
public:
servermain(const QString logFile);
~servermain();
signals:
// Basic to rig:
void setCIVAddr(unsigned char newRigCIVAddr);
void setRigID(unsigned char rigID);
void setRTSforPTT(bool enabled);
// Power
void sendPowerOn();
void sendPowerOff();
// Frequency, mode, band:
void getFrequency();
void setFrequency(unsigned char vfo, freqt freq);
void getMode();
void setMode(unsigned char modeIndex, unsigned char modeFilter);
void setMode(mode_info);
void setDataMode(bool dataOn, unsigned char filter);
void getDataMode();
void getModInput(bool dataOn);
void setModInput(rigInput input, bool dataOn);
void getBandStackReg(char band, char regCode);
void getDebug();
void getRitEnabled();
void getRitValue();
void setRitValue(int ritValue);
void setRitEnable(bool ritEnabled);
// Repeater:
void getDuplexMode();
void getTone();
void getTSQL();
void getDTCS();
void getRptAccessMode();
// Level get:
void getLevels(); // get all levels
void getRfGain();
void getAfGain();
void getSql();
void getIfShift();
void getTPBFInner();
void getTPBFOuter();
void getTxPower();
void getMicGain();
void getSpectrumRefLevel();
void getModInputLevel(rigInput input);
// Level set:
void setRfGain(unsigned char level);
void setAfGain(unsigned char level);
void setSql(unsigned char level);
void setIFShift(unsigned char level);
void setTPBFInner(unsigned char level);
void setTPBFOuter(unsigned char level);
void setIFShiftWindow(unsigned char level);
void setTPBFInnerWindow(unsigned char level);
void setTPBFOuterWindow(unsigned char level);
void setMicGain(unsigned char);
void setCompLevel(unsigned char);
void setTxPower(unsigned char);
void setMonitorLevel(unsigned char);
void setVoxGain(unsigned char);
void setAntiVoxGain(unsigned char);
void setSpectrumRefLevel(int);
void setModLevel(rigInput input, unsigned char level);
void setACCGain(unsigned char level);
void setACCAGain(unsigned char level);
void setACCBGain(unsigned char level);
void setUSBGain(unsigned char level);
void setLANGain(unsigned char level);
void getMeters(meterKind meter);
// PTT, ATU, ATT, Antenna, Preamp:
void getPTT();
void setPTT(bool pttOn);
void getAttenuator();
void getPreamp();
void getAntenna();
void setAttenuator(unsigned char att);
void setPreamp(unsigned char pre);
void setAntenna(unsigned char ant, bool rx);
void startATU();
void setATU(bool atuEnabled);
void getATUStatus();
// Time and date:
void setTime(timekind t);
void setDate(datekind d);
void setUTCOffset(timekind t);
void getRigID(); // this is the model of the rig
void getRigCIV(); // get the rig's CIV addr
void spectOutputEnable();
void spectOutputDisable();
void scopeDisplayEnable();
void scopeDisplayDisable();
void setScopeMode(spectrumMode spectMode);
void setScopeSpan(char span);
void setScopeEdge(char edge);
void setScopeFixedEdge(double startFreq, double endFreq, unsigned char edgeNumber);
void getScopeMode();
void getScopeEdge();
void getScopeSpan();
void sayFrequency();
void sayMode();
void sayAll();
void sendCommSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate,QString vsp, quint16 tcp, quint8 wf);
void sendCommSetup(unsigned char rigCivAddr, udpPreferences prefs, audioSetup rxSetup, audioSetup txSetup, QString vsp, quint16 tcp);
void sendCloseComm();
void sendChangeLatency(quint16 latency);
void initServer();
void sendRigCaps(rigCapabilities caps);
void requestRigState();
void stateUpdated();
private slots:
void receiveCommReady();
void receivePTTstatus(bool pttOn);
void receiveFoundRigID(rigCapabilities rigCaps);
void receivePortError(errorType err);
void receiveBaudRate(quint32 baudrate);
void handlePttLimit();
void receiveStatusUpdate(networkStatus status);
void receiveStateInfo(rigstate* state);
void connectToRig(RIGCONFIG* rig);
void updateAudioDevices();
private:
QSettings *settings=Q_NULLPTR;
void loadSettings();
void openRig();
void powerRigOff();
void powerRigOn();
QStringList portList;
QString serialPortRig;
QTimer * delayedCommand;
QTimer * pttTimer;
uint16_t loopTickCounter;
uint16_t slowCmdNum;
QString lastMessage="";
void makeRig();
void removeRig();
void findSerialPort();
void setServerToPrefs();
void setInitialTiming();
void getSettingsFilePath(QString settingsFile);
QStringList modes;
int currentModeIndex;
QStringList spans;
QStringList edges;
QStringList commPorts;
quint16 spectWidth;
quint16 wfLength;
bool spectrumDrawLock;
QByteArray spectrumPeaks;
QVector <QByteArray> wfimage;
unsigned int wfLengthMax;
bool onFullscreen;
bool drawPeaks;
bool freqTextSelected;
void checkFreqSel();
double oldLowerFreq;
double oldUpperFreq;
freqt freq;
float tsKnobMHz;
unsigned char setModeVal=0;
unsigned char setFilterVal=0;
bool usingLAN = false;
struct preferences {
unsigned char radioCIVAddr;
bool CIVisRadioModel;
bool forceRTSasPTT;
QString serialPortRadio;
quint32 serialPortBaud;
unsigned char localAFgain;
audioSetup rxAudio;
audioSetup txAudio;
rigCapabilities rigCaps;
bool haveRigCaps = false;
quint16 tcpPort;
audioType audioSystem;
} prefs;
preferences defPrefs;
udpPreferences udpPrefs;
udpPreferences udpDefPrefs;
// Configuration for audio output and input.
audioSetup rxSetup;
audioSetup txSetup;
audioSetup serverRxSetup;
audioSetup serverTxSetup;
void setDefPrefs(); // populate default values to default prefs
bool amTransmitting;
bool usingDataMode = false;
unsigned char micGain=0;
unsigned char accAGain=0;
unsigned char accBGain=0;
unsigned char accGain=0;
unsigned char usbGain=0;
unsigned char lanGain=0;
udpServer* udp = Q_NULLPTR;
rigCtlD* rigCtl = Q_NULLPTR;
QThread* serverThread = Q_NULLPTR;
rigstate* rigState = Q_NULLPTR;
audioDevices* audioDev = Q_NULLPTR;
SERVERCONFIG serverConfig;
};
Q_DECLARE_METATYPE(struct rigCapabilities)
Q_DECLARE_METATYPE(struct freqt)
Q_DECLARE_METATYPE(struct mode_info)
Q_DECLARE_METATYPE(struct udpPreferences)
Q_DECLARE_METATYPE(struct audioPacket)
Q_DECLARE_METATYPE(struct audioSetup)
Q_DECLARE_METATYPE(struct SERVERCONFIG)
Q_DECLARE_METATYPE(struct timekind)
Q_DECLARE_METATYPE(struct datekind)
Q_DECLARE_METATYPE(struct networkStatus)
Q_DECLARE_METATYPE(enum rigInput)
Q_DECLARE_METATYPE(QList<radio_cap_packet>)
Q_DECLARE_METATYPE(enum meterKind)
Q_DECLARE_METATYPE(enum spectrumMode)
Q_DECLARE_METATYPE(rigstate*)
Q_DECLARE_METATYPE(codecType)
Q_DECLARE_METATYPE(errorType)
Q_DECLARE_METATYPE(enum duplexMode)
Q_DECLARE_METATYPE(enum rptAccessTxRx)
Q_DECLARE_METATYPE(struct rptrTone_t)
Q_DECLARE_METATYPE(struct rptrAccessData_t)
#endif // WFMAIN_H

Wyświetl plik

39
sidebandchooser.h 100644
Wyświetl plik

@ -0,0 +1,39 @@
#ifndef SIDEBANDCHOOSER_H
#define SIDEBANDCHOOSER_H
#include "wfviewtypes.h"
class sidebandChooser
{
public:
sidebandChooser();
static inline mode_kind getMode(freqt f, mode_kind currentMode = modeUSB) {
if((currentMode == modeLSB) || (currentMode == modeUSB) )
{
if(f.Hz < 5000000)
{
return modeLSB;
}
if( (f.Hz >= 5000000) && (f.Hz < 5600000) )
{
return modeUSB;
}
if( (f.Hz >= 5600000) && (f.Hz < 10000000) )
{
return modeLSB;
}
return modeUSB;
} else {
return currentMode;
}
}
private:
};
#endif // SIDEBANDCHOOSER_H

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