From ec40ef5c59fc2e598d4afaf99a9963bfaba342fd Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 28 Sep 2018 16:12:09 +0100 Subject: [PATCH 01/52] Improve handling of country/prefix information appended to decoded CQ messages The use of QTextEdit::toPlainText() converts non-break spaces to normal spaces so was breaking the use of that character to delineate appended info. Since using QTextEdit::toPlainText() is an unnecessary operation as the decoded text can be more amenably accessed through the QDocument and QTextBlock interface without any translation, this is an improvement which should have some performance impact when many decodes are stored in the decodes windows. (cherry picked from commit da643fa43ebc4773d43646c8e850ba4fe8330294) --- decodedtext.cpp | 1 + displaytext.cpp | 1 + mainwindow.cpp | 48 +++++++++++++++++++++--------------------------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/decodedtext.cpp b/decodedtext.cpp index 5970080d2..8bf59e715 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -20,6 +20,7 @@ DecodedText::DecodedText (QString const& the_string) , message_ {string_.mid (column_qsoText + padding_).trimmed ()} , is_standard_ {false} { + qDebug () << "DecodedText: the_string:" << the_string << "Nbsp pos:" << the_string.indexOf (QChar::Nbsp); if (message_.length() >= 1) { message0_ = message_.left(36); diff --git a/displaytext.cpp b/displaytext.cpp index b17421a74..664564fad 100644 --- a/displaytext.cpp +++ b/displaytext.cpp @@ -76,6 +76,7 @@ void DisplayText::insertLineSpacer(QString const& line) void DisplayText::appendText(QString const& text, QColor bg, QString const& call1, QString const& call2) { + qDebug () << "DisplayText::appendText: text:" << text << "Nbsp pos:" << text.indexOf (QChar::Nbsp); auto cursor = textCursor (); cursor.movePosition (QTextCursor::End); auto block_format = cursor.blockFormat (); diff --git a/mainwindow.cpp b/mainwindow.cpp index 331ce72a2..713ea4c13 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -6903,27 +6903,28 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de QString format_string {"%1 %2 %3 %4 %5 %6"}; auto const& time_string = time.toString ("~" == mode || "&" == mode ? "hhmmss" : "hhmm"); - auto cqtext = format_string + auto message_line = format_string .arg (time_string) .arg (snr, 3) .arg (delta_time, 4, 'f', 1) .arg (delta_frequency, 4) .arg (mode, -2) .arg (message_text); - auto messages = ui->decodedTextBrowser->toPlainText (); - auto position = messages.lastIndexOf (cqtext); - if (position < 0) + QTextCursor start {ui->decodedTextBrowser->document ()}; + start.movePosition (QTextCursor::End); + auto cursor = ui->decodedTextBrowser->document ()->find (message_line, start, QTextDocument::FindBackward); + if (cursor.isNull ()) { // try again with with -0.0 delta time - position = messages.lastIndexOf (format_string - .arg (time_string) - .arg (snr, 3) - .arg ('-' + QString::number (delta_time, 'f', 1), 4) - .arg (delta_frequency, 4) - .arg (mode, -2) - .arg (message_text)); + cursor = ui->decodedTextBrowser->document ()->find (format_string + .arg (time_string) + .arg (snr, 3) + .arg ('-' + QString::number (delta_time, 'f', 1), 4) + .arg (delta_frequency, 4) + .arg (mode, -2) + .arg (message_text), start, QTextDocument::FindBackward); } - if (position >= 0) + if (!cursor.isNull ()) { if (m_config.udpWindowToFront ()) { @@ -6936,14 +6937,11 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de showNormal (); raise (); } - // find the linefeed at the end of the line - position = ui->decodedTextBrowser->toPlainText().indexOf(QChar::LineFeed,position); if (message_text.contains (QRegularExpression {R"(^(CQ |CQDX |QRZ ))"})) { // a message we are willing to accept and auto reply to m_bDoubleClicked = true; } - auto start = messages.left (position).lastIndexOf (QChar::LineFeed) + 1; - DecodedText message {messages.mid (start, position - start)}; + DecodedText message {message_line}; Qt::KeyboardModifiers kbmod {modifiers << 24}; processMessage (message, kbmod); tx_watchdog (false); @@ -6951,7 +6949,7 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de } else { - qDebug () << "process reply message ignored, decode not found:" << cqtext; + qDebug () << "process reply message ignored, decode not found:" << message_line; } } @@ -6988,10 +6986,12 @@ void MainWindow::replayDecodes () // is not checked // attempt to parse the decoded text - Q_FOREACH (auto const& message - , ui->decodedTextBrowser->toPlainText ().split (QChar::LineFeed, - QString::SkipEmptyParts)) + for (QTextBlock block = ui->decodedTextBrowser->document ()->firstBlock (); block.isValid (); block = block.next ()) { + auto message = block.text (); + message = message.left (message.indexOf (QChar::Nbsp)); // discard + // any + // appended info if (message.size() >= 4 && message.left (4) != "----") { auto const& parts = message.split (' ', QString::SkipEmptyParts); @@ -7001,14 +7001,8 @@ void MainWindow::replayDecodes () } else { - auto eom_pos = message.indexOf (' ', 35); - // we always want at least the characters to position 35 - if (eom_pos < 35) - { - eom_pos = message.size () - 1; - } // TODO - how to skip ISCAT decodes - postDecode (false, message.left (eom_pos + 1)); + postDecode (false, message); } } } From 33c4f56967b824c17fe5d20d44015c8782b7b6c8 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 28 Sep 2018 16:23:44 +0100 Subject: [PATCH 02/52] Bump RC number for next release (cherry picked from commit 32bf7546c597f1b3d2712b64347976b817b8205d) --- Versions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.cmake b/Versions.cmake index 4c319dae9..ea9bd417a 100644 --- a/Versions.cmake +++ b/Versions.cmake @@ -2,5 +2,5 @@ set (WSJTX_VERSION_MAJOR 2) set (WSJTX_VERSION_MINOR 0) set (WSJTX_VERSION_PATCH 0) -set (WSJTX_RC 2) # release candidate number, comment out or zero for development versions +set (WSJTX_RC 3) # release candidate number, comment out or zero for development versions set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build From 2de786329b8c62efa690b8118aa4946f2c40a51b Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 28 Sep 2018 19:22:35 +0100 Subject: [PATCH 03/52] Bumb branch to reflect next planned feature release --- Versions.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Versions.cmake b/Versions.cmake index ea9bd417a..6cb4d89c2 100644 --- a/Versions.cmake +++ b/Versions.cmake @@ -1,6 +1,6 @@ # Version number components set (WSJTX_VERSION_MAJOR 2) set (WSJTX_VERSION_MINOR 0) -set (WSJTX_VERSION_PATCH 0) -set (WSJTX_RC 3) # release candidate number, comment out or zero for development versions +set (WSJTX_VERSION_PATCH 1) +#set (WSJTX_RC 1) # release candidate number, comment out or zero for development versions set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build From 7e02b09920b41af8ebc6084c62a4ffc84c18592a Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Fri, 28 Sep 2018 14:13:58 -0500 Subject: [PATCH 04/52] Beginnings of AP for RU. Not working yet. --- lib/ft8/ft8apset_174_91.f90 | 24 +++++----- lib/ft8/ft8b_2.f90 | 90 +++++++++++++++++++++++++------------ lib/ft8/genft8_174_91.f90 | 2 +- lib/ft8_decode.f90 | 14 +++--- 4 files changed, 83 insertions(+), 47 deletions(-) diff --git a/lib/ft8/ft8apset_174_91.f90 b/lib/ft8/ft8apset_174_91.f90 index 5066e626a..f30e4ecbf 100644 --- a/lib/ft8/ft8apset_174_91.f90 +++ b/lib/ft8/ft8apset_174_91.f90 @@ -1,20 +1,22 @@ -subroutine ft8apset_174_91(mycall12,hiscall12,hisgrid6,ncontest,apsym) +subroutine ft8apset_174_91(mycall12,hiscall12,ncontest,apsym) parameter(NAPM=4,KK=91) character*37 msg,msgsent - character*12 mycall12,hiscall12 - character*6 hisgrid6 - character*4 hisgrid + character*12 mycall12,hiscall12,hiscall integer apsym(77) integer*1 msgbits(77) integer itone(KK) - - if(index(hiscall12," ").eq.0) hiscall12="K9ABC" - msg=trim(mycall12)//' '//trim(hiscall12)//' RRR' - i3=1 - n3=0 -!write(*,*) 'apset msg ',msg + + hiscall=hiscall12 + if(len(trim(hiscall)).eq.0) hiscall="K9ABC" + if(ncontest.eq.0) then + msg=trim(mycall12)//' '//trim(hiscall)//' RRR' + elseif(ncontest.eq.4) then + msg=trim(mycall12)//' '//trim(hiscall)//' 599 NJ' + endif +! write(*,*) 'apset msg ',msg call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) +! write(*,*) 'apset msg sent',msgsent apsym=2*msgbits-1 -!write(*,'(29i1,1x,29i1,1x,19i1)') (apsym(1:77)+1)/2 +! write(*,'(29i1,1x,29i1,1x,19i1)') (apsym(1:77)+1)/2 return end subroutine ft8apset_174_91 diff --git a/lib/ft8/ft8b_2.f90 b/lib/ft8/ft8b_2.f90 index 133a1de8a..3330d1706 100644 --- a/lib/ft8/ft8b_2.f90 +++ b/lib/ft8/ft8b_2.f90 @@ -1,5 +1,5 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & - napwid,lsubtract,nagain,iaptype,mycall12,hiscall12, & + napwid,lsubtract,nagain,ncontest,iaptype,mycall12,hiscall12, & sync0,f1,xdt,xbase,apsym,nharderrors,dmin,nbadcrc,ipass,iera,msg37,xsnr) use crc @@ -16,19 +16,20 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & real a(5) real s8(0:7,NN) real s2(0:511),s2l(0:511) - real bmeta(3*ND),bmetb(3*ND),bmetc(3*ND) - real bmetal(3*ND),bmetbl(3*ND),bmetcl(3*ND) - real llra(3*ND),llrb(3*ND),llrc(3*ND),llrd(3*ND) !Soft symbols - real llral(3*ND),llrbl(3*ND),llrcl(3*ND) !Soft symbols + real bmeta(174),bmetb(174),bmetc(174) + real bmetal(174),bmetbl(174),bmetcl(174) + real llra(174),llrb(174),llrc(174),llrd(174) !Soft symbols + real llral(174),llrbl(174),llrcl(174) !Soft symbols real dd0(15*12000) - integer*1 message77(77),apmask(3*ND),cw(3*ND) + integer*1 message77(77),apmask(174),cw(174) integer*1 msgbits(77) integer apsym(77) - integer mcq(29),mrrr(19),m73(19),mrr73(19) + integer mcq(29),mcqru(29),mrrr(19),m73(19),mrr73(19) integer itone(NN) integer icos7(0:6),ip(1) integer nappasses(0:5) !Number of decoding passes to use for each QSO state integer naptypes(0:5,4) ! (nQSOProgress, decoding pass) maximum of 4 passes for now + integer ncontest,ncontest0 integer*1, target:: i1hiscall(12) logical one(0:511,0:8) integer graymap(0:7) @@ -39,15 +40,18 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & logical first,newdat,lsubtract,lapon,lapcqonly,nagain,unpk77_success data icos7/3,1,4,0,6,5,2/ ! Flipped w.r.t. original FT8 sync array data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ + data mcqru/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0/ data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/ data first/.true./ data graymap/0,1,3,2,5,6,4,7/ - save nappasses,naptypes,one,hiscall12_0 + save nappasses,naptypes,ncontest0,one,hiscall12_0 - if(first) then + + if(first.or.(ncontest.ne.ncontest0)) then mcq=2*mcq-1 + mcqru=2*mcqru-1 mrrr=2*mrrr-1 m73=2*m73-1 mrr73=2*mrr73-1 @@ -81,6 +85,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & enddo enddo first=.false. + ncontest0=ncontest endif if(hiscall12.ne.hiscall12_0) then @@ -211,12 +216,12 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & enddo enddo enddo - call normalizebmet(bmeta,3*ND) -! call normalizebmet(bmetal,3*ND) - call normalizebmet(bmetb,3*ND) -! call normalizebmet(bmetbl,3*ND) - call normalizebmet(bmetc,3*ND) -! call normalizebmet(bmetcl,3*ND) + call normalizebmet(bmeta,174) +! call normalizebmet(bmetal,174) + call normalizebmet(bmetb,174) +! call normalizebmet(bmetbl,174) + call normalizebmet(bmetc,174) +! call normalizebmet(bmetcl,174) scalefac=2.83 llra=scalefac*bmeta @@ -226,7 +231,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & llrc=scalefac*bmetc ! llrcl=scalefac*bmetcl - apmag=maxval(abs(llrb))*1.01 + apmag=maxval(abs(llra))*1.01 ! pass # !------------------------------ @@ -238,7 +243,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & ! 6 ap pass 3 ! 7 ap pass 4 - if(lapon) then + if(lapon.and.(ncontest.eq.0.or.ncontest.eq.4)) then if(.not.lapcqonly) then npasses=3+nappasses(nQSOProgress) else @@ -248,6 +253,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & npasses=3 endif +write(*,*) apmag,lapon,lapcqonly,npasses,nQSOProgress do ipass=1,npasses llrd=llra if(ipass.eq.2) llrd=llrb @@ -265,20 +271,47 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & iaptype=1 endif if(iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle - if(iaptype.eq.1 .or. iaptype.eq.2 ) then ! AP,???,??? + if(iaptype.eq.1) then ! CQ,???,??? or CQ RU,???,??? apmask=0 apmask(1:29)=1 + if( ncontest.eq.0) llrd(1:29)=apmag*mcq(1:29) + if( ncontest.eq.4) llrd(1:29)=apmag*mcqru(1:29) apmask(75:77)=1 - llrd(75:77)=apmag*apsym(75:77) - if(iaptype.eq.1) llrd(1:29)=apmag*mcq(1:29) - if(iaptype.eq.2) llrd(1:29)=apmag*apsym(1:29) + llrd(75:76)=apmag*(-1) + llrd(77)=apmag*(+1) endif - if(iaptype.eq.3) then ! mycall, dxcall, ??? + + if(iaptype.eq.2) then ! MyCall,???,??? apmask=0 - apmask(1:56)=1 - apmask(75:77)=1 - llrd(1:56)=apmag*apsym(1:56) - llrd(75:77)=apmag*apsym(75:77) + if(ncontest.eq.0) then + apmask(1:29)=1 + llrd(1:29)=apmag*apsym(1:29) + apmask(75:77)=1 + llrd(75:76)=apmag*(-1) + llrd(77)=apmag*(+1) + else if(ncontest.eq.4) then + apmask(2:29)=1 + llrd(2:29)=apmag*apsym(2:29) + apmask(75:77)=1 + llrd(75)=apmag*(-1) + llrd(76:77)=apmag*(+1) + endif + endif + if(iaptype.eq.3) then ! MyCall,DxCall,??? + apmask=0 + if(ncontest.eq.0) then + apmask(1:58)=1 + llrd(1:58)=apmag*apsym(1:58) + apmask(75:77)=1 + llrd(75:76)=apmag*(-1) + llrd(77)=apmag*(+1) + else if(ncontest.eq.4) then + apmask(2:57)=1 + llrd(2:57)=apmag*apsym(2:57) + apmask(75:77)=1 + llrd(75)=apmag*(-1) + llrd(76:77)=apmag*(+1) + endif endif if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then apmask=0 @@ -325,7 +358,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & cycle endif nbadcrc=0 ! If we get this far: valid codeword, valid (i3,n3), nonquirky message. - call genft8_174_91(msg37,i3,n3,msgsent37,msgbits,itone) + call genft8_174_91(msg37,i3g,n3g,msgsent37,msgbits,itone) if(lsubtract) call subtractft8(dd0,itone,f1,xdt) xsig=0.0 xnoi=0.0 @@ -338,10 +371,11 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & xsnr2=0.001 arg=xsig/xnoi-1.0 if(arg.gt.0.1) xsnr=arg - arg=xsig/xbase/2.8e6-1.0 + arg=xsig/xbase/2.6e6-1.0 if(arg.gt.0.1) xsnr2=arg xsnr=10.0*log10(xsnr)-27.0 xsnr2=10.0*log10(xsnr2)-27.0 +write(87,'(f10.1,2x,f10.1)') xsnr,xsnr2 if(.not.nagain) then xsnr=xsnr2 endif diff --git a/lib/ft8/genft8_174_91.f90 b/lib/ft8/genft8_174_91.f90 index c9b2a7cd7..7017a84d2 100644 --- a/lib/ft8/genft8_174_91.f90 +++ b/lib/ft8/genft8_174_91.f90 @@ -22,7 +22,7 @@ subroutine genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) read(c77,'(77i1)',err=1) msgbits go to 2 1 write(81,*) msg,c77 ; flush(81) -2 call encode174_91(msgbits,codeword) !Encode the test message +2 call encode174_91(msgbits,codeword) !Encode 77-bit msg into codeword ! Message structure: S7 D29 S7 D29 S7 itone(1:7)=icos7 diff --git a/lib/ft8_decode.f90 b/lib/ft8_decode.f90 index 079e0ffc8..2ed0c3504 100644 --- a/lib/ft8_decode.f90 +++ b/lib/ft8_decode.f90 @@ -70,7 +70,7 @@ contains 1001 format("000000_",i6.6) call ft8apset(mycall12,hiscall12,apsym1) - call ft8apset_174_91(mycall12,hiscall12,hisgrid6,ncontest,apsym2) + call ft8apset_174_91(mycall12,hiscall12,ncontest,apsym2) dd=iwave ndecodes=0 allmessages=' ' @@ -121,7 +121,7 @@ contains nbadcrc,iappass,iera,msg37,xsnr) else call ft8b_2(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lft8apon, & - lapcqonly,napwid,lsubtract,nagain,iaptype,mycall12, & + lapcqonly,napwid,lsubtract,nagain,ncontest,iaptype,mycall12, & hiscall12,sync,f1,xdt,xbase,apsym2,nharderrors,dmin, & nbadcrc,iappass,iera,msg37,xsnr) endif @@ -143,11 +143,11 @@ contains allmessages(ndecodes)=msg37 allsnrs(ndecodes)=nsnr endif -! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, & -! nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), & -! xdt,nint(f1),msg37,isync -!1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a37,i4) -! flush(81) + write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, & + nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), & + xdt,nint(f1),msg37,isync +1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a37,i4) + flush(81) if(.not.ldupe .and. associated(this%callback)) then qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0] call this%callback(sync,nsnr,xdt,f1,msg37,iaptype,qual) From 3b783a083ee26a88ff01b385280d982d4ac82646 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Fri, 28 Sep 2018 16:36:33 -0500 Subject: [PATCH 05/52] Better handling of decodes with unhashed callsigns. --- lib/ft8/ft8b_2.f90 | 2 +- lib/ft8/genft8_174_91.f90 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ft8/ft8b_2.f90 b/lib/ft8/ft8b_2.f90 index 133a1de8a..555b010a8 100644 --- a/lib/ft8/ft8b_2.f90 +++ b/lib/ft8/ft8b_2.f90 @@ -325,7 +325,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & cycle endif nbadcrc=0 ! If we get this far: valid codeword, valid (i3,n3), nonquirky message. - call genft8_174_91(msg37,i3,n3,msgsent37,msgbits,itone) + call get_tones_from_77bits(message77,itone) if(lsubtract) call subtractft8(dd0,itone,f1,xdt) xsig=0.0 xnoi=0.0 diff --git a/lib/ft8/genft8_174_91.f90 b/lib/ft8/genft8_174_91.f90 index c9b2a7cd7..a9e8d7007 100644 --- a/lib/ft8/genft8_174_91.f90 +++ b/lib/ft8/genft8_174_91.f90 @@ -17,11 +17,13 @@ subroutine genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) i3=-1 n3=-1 call pack77(msg,i3,n3,c77) - call unpack77(c77,msgsent,unpk77_success) read(c77,'(77i1)',err=1) msgbits go to 2 1 write(81,*) msg,c77 ; flush(81) + +entry get_tones_from_77bits(msgbits,itone) + 2 call encode174_91(msgbits,codeword) !Encode the test message ! Message structure: S7 D29 S7 D29 S7 From 0049a13df3ac32d526f5a034a56487d86877c954 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Sat, 29 Sep 2018 09:16:56 -0500 Subject: [PATCH 06/52] Cleaned up and simplified AP decoding. Enabled AP decoding for ncontest=0 and ncontest=4 (RU) so far. Missing MyCall or DxCall or nonstandard calls will disable AP passes that wouldn't make sense. --- lib/ft8/ft8apset_174_91.f90 | 55 +++++++++++++++++++++++++------------ lib/ft8/ft8b_2.f90 | 21 ++++++++------ 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/lib/ft8/ft8apset_174_91.f90 b/lib/ft8/ft8apset_174_91.f90 index f30e4ecbf..d979aeac1 100644 --- a/lib/ft8/ft8apset_174_91.f90 +++ b/lib/ft8/ft8apset_174_91.f90 @@ -1,22 +1,43 @@ -subroutine ft8apset_174_91(mycall12,hiscall12,ncontest,apsym) - parameter(NAPM=4,KK=91) - character*37 msg,msgsent +subroutine ft8apset_174_91(mycall12,hiscall12,apsym) + use packjt77 + character*77 c77 + character*37 msg character*12 mycall12,hiscall12,hiscall - integer apsym(77) + integer apsym(58) integer*1 msgbits(77) - integer itone(KK) - + logical nohiscall + + if(len(trim(mycall12)).eq.0) then + apsym=0 + apsym(1)=99 + apsym(30)=99 + return + endif + + nohiscall=.false. hiscall=hiscall12 - if(len(trim(hiscall)).eq.0) hiscall="K9ABC" - if(ncontest.eq.0) then - msg=trim(mycall12)//' '//trim(hiscall)//' RRR' - elseif(ncontest.eq.4) then - msg=trim(mycall12)//' '//trim(hiscall)//' 599 NJ' - endif -! write(*,*) 'apset msg ',msg - call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) -! write(*,*) 'apset msg sent',msgsent - apsym=2*msgbits-1 -! write(*,'(29i1,1x,29i1,1x,19i1)') (apsym(1:77)+1)/2 + if(len(trim(hiscall)).eq.0) then + hiscall="K9ABC" + nohiscall=.true. + endif + +! Encode a dummy standard message: i3=1, 28 1 28 1 1 15 +! + msg=trim(mycall12)//' '//trim(hiscall)//' RRR' + call pack77(msg,i3,n3,c77) + if(i3.ne.1) then + apsym=0 + apsym(1)=99 + apsym(30)=99 + return + endif + + read(c77,'(58i1)',err=1) apsym(1:58) + if(nohiscall) apsym(30)=99 + return + +1 apsym=0 + apsym(1)=99 + apsym(30)=99 return end subroutine ft8apset_174_91 diff --git a/lib/ft8/ft8b_2.f90 b/lib/ft8/ft8b_2.f90 index 2adb37151..f0eac8b4d 100644 --- a/lib/ft8/ft8b_2.f90 +++ b/lib/ft8/ft8b_2.f90 @@ -22,8 +22,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & real llral(174),llrbl(174),llrcl(174) !Soft symbols real dd0(15*12000) integer*1 message77(77),apmask(174),cw(174) - integer*1 msgbits(77) - integer apsym(77) + integer apsym(58) integer mcq(29),mcqru(29),mrrr(19),m73(19),mrr73(19) integer itone(NN) integer icos7(0:6),ip(1) @@ -253,7 +252,6 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & npasses=3 endif -write(*,*) apmag,lapon,lapcqonly,npasses,nQSOProgress do ipass=1,npasses llrd=llra if(ipass.eq.2) llrd=llrb @@ -270,7 +268,11 @@ write(*,*) apmag,lapon,lapcqonly,npasses,nQSOProgress else iaptype=1 endif + if(iaptype.ge.2 .and. apsym(1).gt.1) cycle ! no mycall was entered + if(iaptype.ge.3 .and. apsym(30).gt.1) cycle ! no, or nonstandard dxcall if(iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle + apsym=2*apsym-1 + if(iaptype.eq.1) then ! CQ,???,??? or CQ RU,???,??? apmask=0 apmask(1:29)=1 @@ -291,32 +293,35 @@ write(*,*) apmag,lapon,lapcqonly,npasses,nQSOProgress llrd(77)=apmag*(+1) else if(ncontest.eq.4) then apmask(2:29)=1 - llrd(2:29)=apmag*apsym(2:29) + llrd(2:29)=apmag*apsym(1:28) apmask(75:77)=1 llrd(75)=apmag*(-1) llrd(76:77)=apmag*(+1) endif endif + if(iaptype.eq.3) then ! MyCall,DxCall,??? apmask=0 if(ncontest.eq.0) then apmask(1:58)=1 - llrd(1:58)=apmag*apsym(1:58) + llrd(1:58)=apmag*apsym apmask(75:77)=1 llrd(75:76)=apmag*(-1) llrd(77)=apmag*(+1) else if(ncontest.eq.4) then apmask(2:57)=1 - llrd(2:57)=apmag*apsym(2:57) + llrd(2:29)=apmag*apsym(1:28) + llrd(30:57)=apmag*apsym(30:57) apmask(75:77)=1 llrd(75)=apmag*(-1) llrd(76:77)=apmag*(+1) endif endif + if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then apmask=0 apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73 - llrd(1:58)=apmag*apsym(1:58) + llrd(1:58)=apmag*apsym if(iaptype.eq.4) llrd(59:77)=apmag*mrrr if(iaptype.eq.5) llrd(59:77)=apmag*m73 if(iaptype.eq.6) llrd(59:77)=apmag*mrr73 @@ -375,7 +380,7 @@ write(*,*) apmag,lapon,lapcqonly,npasses,nQSOProgress if(arg.gt.0.1) xsnr2=arg xsnr=10.0*log10(xsnr)-27.0 xsnr2=10.0*log10(xsnr2)-27.0 -write(87,'(f10.1,2x,f10.1)') xsnr,xsnr2 +!write(87,'(f10.1,2x,f10.1)') xsnr,xsnr2 if(.not.nagain) then xsnr=xsnr2 endif From 9cfd61106a0b65d2e25f9aaa0da0cc9f551b09ef Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Sat, 29 Sep 2018 09:18:48 -0500 Subject: [PATCH 07/52] Forgot to add the AP-related changes to ft8_decode.f90. --- lib/ft8_decode.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ft8_decode.f90 b/lib/ft8_decode.f90 index 2ed0c3504..2b34aa617 100644 --- a/lib/ft8_decode.f90 +++ b/lib/ft8_decode.f90 @@ -52,7 +52,7 @@ contains character*12 mycall12,hiscall12,mycall12_0 character*6 hisgrid6 integer*2 iwave(15*12000) - integer apsym1(KK),apsym2(77) + integer apsym1(KK),apsym2(58) character datetime*13,msg37*37 ! character message*22 character*37 allmessages(100) @@ -70,7 +70,7 @@ contains 1001 format("000000_",i6.6) call ft8apset(mycall12,hiscall12,apsym1) - call ft8apset_174_91(mycall12,hiscall12,ncontest,apsym2) + call ft8apset_174_91(mycall12,hiscall12,apsym2) dd=iwave ndecodes=0 allmessages=' ' From 6c4d96b4425cc4a150def085c1177fb4e8a5f6b8 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Sun, 30 Sep 2018 12:02:14 -0500 Subject: [PATCH 08/52] Reconfigure foxgen.f90 for 77bit messages. Fox now transmits only 77bit messages. --- lib/ft8/foxgen.f90 | 61 +++++---------------------------------- lib/ft8/foxgen_wrap.f90 | 2 +- lib/ft8/genft8_174_91.f90 | 3 +- 3 files changed, 11 insertions(+), 55 deletions(-) diff --git a/lib/ft8/foxgen.f90 b/lib/ft8/foxgen.f90 index 18cf3cc1d..128101429 100644 --- a/lib/ft8/foxgen.f90 +++ b/lib/ft8/foxgen.f90 @@ -14,25 +14,20 @@ subroutine foxgen() ! common/foxcom/. The generated wave(NWAVE) is passed back in the same ! common block. - use crc - parameter (NN=79,ND=58,KK=87,NSPS=4*1920) + parameter (NN=79,ND=58,NSPS=4*1920) parameter (NWAVE=NN*NSPS,NFFT=614400,NH=NFFT/2) character*40 cmsg character*37 msg,msgsent - character*87 cbits - character*88 cb88 - integer itone(NN) - integer icos7(0:6) - integer*1 msgbits(KK),codeword(3*ND),msgbits2 + integer itone(79) + integer*1 msgbits(77),msgbits2 integer*1, target:: i1Msg8BitBytes(11) integer*1, target:: mycall real x(NFFT) real*8 dt,twopi,f0,fstep,dfreq,phi,dphi complex cx(0:NH) common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall(12) - common/foxcom2/itone2(NN),msgbits2(KK) + common/foxcom2/itone2(NN),msgbits2(77) equivalence (x,cx),(y,cy) - data icos7/2,5,6,0,4,1,3/ !Costas 7x7 tone pattern fstep=60.d0 dfreq=6.25d0 @@ -43,51 +38,11 @@ subroutine foxgen() wave=0. do n=1,nslots - i3b=i3bit(n) - if(i3b.eq.0) then - msg=cmsg(n)(1:22) !Standard FT8 message - else - i1=index(cmsg(n),' ') !Special Fox message - i2=index(cmsg(n),';') - i3=index(cmsg(n),'<') - i4=index(cmsg(n),'>') - msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' ' - read(cmsg(n)(i4+2:i4+4),*) irpt - endif - call genft8(msg,0,1,1,msgsent,msgbits,itone) -! print*,'Foxgen:',n,cmsg(n),msgsent + msg=cmsg(n)(1:37) + call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) + print*,'Foxgen:',n,msg,msgsent,i3,n3 + write(*,'(77i1)') msgbits - if(i3b.eq.1) then - icrc10=crc10(c_loc(mycall),12) - nrpt=irpt+30 - write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0 -1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12) - read(cbits,1002) msgbits -1002 format(87i1) - - cb88=cbits//'0' - read(cb88,1003) i1Msg8BitBytes(1:11) -1003 format(11b8) - icrc12=crc12(c_loc(i1Msg8BitBytes),11) - - write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12 - read(cbits,1002) msgbits - - call encode174(msgbits,codeword) !Encode the test message - -! Message structure: S7 D29 S7 D29 S7 - itone(1:7)=icos7 - itone(36+1:36+7)=icos7 - itone(NN-6:NN)=icos7 - k=7 - do j=1,ND - i=3*j -2 - k=k+1 - if(j.eq.30) k=k+7 - itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2) - enddo - endif - ! Make copies of itone() and msgbits() for ft8sim itone2=itone msgbits2=msgbits diff --git a/lib/ft8/foxgen_wrap.f90 b/lib/ft8/foxgen_wrap.f90 index dbcb2582f..bc8c430f7 100644 --- a/lib/ft8/foxgen_wrap.f90 +++ b/lib/ft8/foxgen_wrap.f90 @@ -1,6 +1,6 @@ subroutine foxgen_wrap(msg40,msgbits,itone) - parameter (NN=79,ND=58,KK=87,NSPS=4*1920) + parameter (NN=79,ND=58,KK=77,NSPS=4*1920) parameter (NWAVE=NN*NSPS) character*40 msg40,cmsg diff --git a/lib/ft8/genft8_174_91.f90 b/lib/ft8/genft8_174_91.f90 index a9e8d7007..a1aa3fbdf 100644 --- a/lib/ft8/genft8_174_91.f90 +++ b/lib/ft8/genft8_174_91.f90 @@ -17,7 +17,8 @@ subroutine genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) i3=-1 n3=-1 call pack77(msg,i3,n3,c77) - + call unpack77(c77,msgsent,unpk77_success) + read(c77,'(77i1)',err=1) msgbits go to 2 1 write(81,*) msg,c77 ; flush(81) From a6b4e98571fe239107ce3c3941ef7c159924c591 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Sun, 30 Sep 2018 16:58:19 -0500 Subject: [PATCH 09/52] Remove some debug print statements. --- lib/ft8/foxgen.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ft8/foxgen.f90 b/lib/ft8/foxgen.f90 index 128101429..853eabc1a 100644 --- a/lib/ft8/foxgen.f90 +++ b/lib/ft8/foxgen.f90 @@ -40,8 +40,8 @@ subroutine foxgen() do n=1,nslots msg=cmsg(n)(1:37) call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) - print*,'Foxgen:',n,msg,msgsent,i3,n3 - write(*,'(77i1)') msgbits +! print*,'Foxgen:',n,msg,msgsent,i3,n3 +! write(*,'(77i1)') msgbits ! Make copies of itone() and msgbits() for ft8sim itone2=itone From ac94690a9c836baec245a83222e3c723b253004f Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 1 Oct 2018 14:12:44 -0400 Subject: [PATCH 10/52] Disable two diagnostics. Add files to wsjtx.pro. --- decodedtext.cpp | 2 +- displaytext.cpp | 2 +- wsjtx.pro | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/decodedtext.cpp b/decodedtext.cpp index 8bf59e715..f466bb8d9 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -20,7 +20,7 @@ DecodedText::DecodedText (QString const& the_string) , message_ {string_.mid (column_qsoText + padding_).trimmed ()} , is_standard_ {false} { - qDebug () << "DecodedText: the_string:" << the_string << "Nbsp pos:" << the_string.indexOf (QChar::Nbsp); +// qDebug () << "DecodedText: the_string:" << the_string << "Nbsp pos:" << the_string.indexOf (QChar::Nbsp); if (message_.length() >= 1) { message0_ = message_.left(36); diff --git a/displaytext.cpp b/displaytext.cpp index 664564fad..f27e7da43 100644 --- a/displaytext.cpp +++ b/displaytext.cpp @@ -76,7 +76,7 @@ void DisplayText::insertLineSpacer(QString const& line) void DisplayText::appendText(QString const& text, QColor bg, QString const& call1, QString const& call2) { - qDebug () << "DisplayText::appendText: text:" << text << "Nbsp pos:" << text.indexOf (QChar::Nbsp); +// qDebug () << "DisplayText::appendText: text:" << text << "Nbsp pos:" << text.indexOf (QChar::Nbsp); auto cursor = textCursor (); cursor.movePosition (QTextCursor::End); auto block_format = cursor.blockFormat (); diff --git a/wsjtx.pro b/wsjtx.pro index 353bd4aea..3d16edf02 100644 --- a/wsjtx.pro +++ b/wsjtx.pro @@ -67,8 +67,7 @@ SOURCES += \ echoplot.cpp echograph.cpp fastgraph.cpp fastplot.cpp Modes.cpp \ WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\ MultiSettings.cpp PhaseEqualizationDialog.cpp IARURegions.cpp MessageBox.cpp \ - EqualizationToolsDialog.cpp \ - colorhighlighting.cpp + EqualizationToolsDialog.cpp CallsignValidator.cpp colorhighlighting.cpp HEADERS += qt_helpers.hpp \ pimpl_h.hpp pimpl_impl.hpp \ @@ -84,8 +83,7 @@ HEADERS += qt_helpers.hpp \ logbook/logbook.h logbook/countrydat.h logbook/countriesworked.h logbook/adif.h \ messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \ WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp \ - IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp \ - colorhighlighting.h + IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp CallsignValidator.hpp colorhighlighting.h INCLUDEPATH += qmake_only From 1fbc51ddd91bfe8193e966de1e1be18021bb4e74 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 1 Oct 2018 14:14:47 -0400 Subject: [PATCH 11/52] Add exch_valid.f90, a Fortran validator for FD and RU exchanges. --- CMakeLists.txt | 1 + lib/77bit/exch_valid.f90 | 61 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 lib/77bit/exch_valid.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 83100946f..9565c5060 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,6 +411,7 @@ set (wsjt_FSRCS lib/ft8/encode174_91.f90 lib/entail.f90 lib/ephem.f90 + lib/77bit/exch_valid.f90 lib/extract.f90 lib/extract4.f90 lib/extractmessage144.f90 diff --git a/lib/77bit/exch_valid.f90 b/lib/77bit/exch_valid.f90 new file mode 100644 index 000000000..70613fc9a --- /dev/null +++ b/lib/77bit/exch_valid.f90 @@ -0,0 +1,61 @@ +logical*1 function exch_valid(ntype,exch) + + parameter (NSEC=84) !Number of ARRL Sections + parameter (NUSCAN=65) !Number of US states and Canadian provinces + + character*(*) exch + character*3 c3 + character*3 cmult(NUSCAN) + character*3 csec(NSEC) + + data csec/ & + "AB ","AK ","AL ","AR ","AZ ","BC ","CO ","CT ","DE ","EB ", & + "EMA","ENY","EPA","EWA","GA ","GTA","IA ","ID ","IL ","IN ", & + "KS ","KY ","LA ","LAX","MAR","MB ","MDC","ME ","MI ","MN ", & + "MO ","MS ","MT ","NC ","ND ","NE ","NFL","NH ","NL ","NLI", & + "NM ","NNJ","NNY","NT ","NTX","NV ","OH ","OK ","ONE","ONN", & + "ONS","OR ","ORG","PAC","PR ","QC ","RI ","SB ","SC ","SCV", & + "SD ","SDG","SF ","SFL","SJV","SK ","SNJ","STX","SV ","TN ", & + "UT ","VA ","VI ","VT ","WCF","WI ","WMA","WNY","WPA","WTX", & + "WV ","WWA","WY ","DX "/ + data cmult/ & + "AL ","AK ","AZ ","AR ","CA ","CO ","CT ","DE ","FL ","GA ", & + "HI ","ID ","IL ","IN ","IA ","KS ","KY ","LA ","ME ","MD ", & + "MA ","MI ","MN ","MS ","MO ","MT ","NE ","NV ","NH ","NJ ", & + "NM ","NY ","NC ","ND ","OH ","OK ","OR ","PA ","RI ","SC ", & + "SD ","TN ","TX ","UT ","VT ","VA ","WA ","WV ","WI ","WY ", & + "NB ","NS ","QC ","ON ","MB ","SK ","AB ","BC ","NWT","NF ", & + "LB ","NU ","YT ","PEI","DC "/ + + exch_valid=.false. + n=len(trim(exch)) + if(ntype.ne.3 .and. ntype.ne.4) go to 900 + if(ntype.eq.3 .and. (n.lt.2 .or. n.gt.7)) go to 900 + if(ntype.eq.4 .and. (n.lt.2 .or. n.gt.3)) go to 900 + + if(ntype.eq.3) then !Field Day + i1=index(exch,' ') + if(i1.lt.3) go to 900 + read(exch(1:i1-2),*,err=900) ntx + if(ntx.lt.1 .or. ntx.gt.32) go to 900 + if(exch(i1-1:i1-1).lt.'A' .or. exch(i1-1:i1-1).gt.'F') go to 900 + c3=exch(i1+1:)//' ' + do i=1,NSEC + if(csec(i).eq.c3) then + exch_valid=.true. + go to 900 + endif + enddo + + else if(ntype.eq.4) then !RTTY Roundup + c3=exch//' ' + do i=1,NUSCAN + if(cmult(i).eq.c3) then + exch_valid=.true. + go to 900 + endif + enddo + endif + +900 return +end function exch_valid From cd8f13b57d1c35774ec3d3b37119639cc6825341 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 1 Oct 2018 16:48:36 -0400 Subject: [PATCH 12/52] Implement a validator for FD and RTTY exchange entries. --- CMakeLists.txt | 2 +- Configuration.cpp | 5 +-- ExchangeValidator.cpp | 67 ++++++++++++++++++++++++++++++++++++++++ ExchangeValidator.hpp | 19 ++++++++++++ lib/77bit/exch_valid.f90 | 61 ------------------------------------ mainwindow.cpp | 1 + wsjtx.pro | 6 ++-- 7 files changed, 95 insertions(+), 66 deletions(-) create mode 100644 ExchangeValidator.cpp create mode 100644 ExchangeValidator.hpp delete mode 100644 lib/77bit/exch_valid.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9565c5060..b5e872521 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,6 +257,7 @@ set (wsjt_qt_CXXSRCS MultiSettings.cpp MaidenheadLocatorValidator.cpp CallsignValidator.cpp + ExchangeValidator.cpp SplashScreen.cpp EqualizationToolsDialog.cpp DoubleClickablePushButton.cpp @@ -411,7 +412,6 @@ set (wsjt_FSRCS lib/ft8/encode174_91.f90 lib/entail.f90 lib/ephem.f90 - lib/77bit/exch_valid.f90 lib/extract.f90 lib/extract4.f90 lib/extractmessage144.f90 diff --git a/Configuration.cpp b/Configuration.cpp index ba9b74bcd..26425fca0 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -180,6 +180,7 @@ #include "MessageBox.hpp" #include "MaidenheadLocatorValidator.hpp" #include "CallsignValidator.hpp" +#include "ExchangeValidator.hpp" #include "ui_Configuration.h" #include "moc_Configuration.cpp" @@ -997,12 +998,12 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory, // this must be done after the default paths above are set read_settings (); - // // validation - // ui_->callsign_line_edit->setValidator (new CallsignValidator {this}); ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this}); ui_->add_macro_line_edit->setValidator (new QRegExpValidator {message_alphabet, this}); + ui_->FieldDay_Exchange->setValidator(new ExchangeValidator{this}); + ui_->RTTY_Exchange->setValidator(new ExchangeValidator{this}); ui_->udp_server_port_spin_box->setMinimum (1); ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits::max ()); diff --git a/ExchangeValidator.cpp b/ExchangeValidator.cpp new file mode 100644 index 000000000..e825d00ca --- /dev/null +++ b/ExchangeValidator.cpp @@ -0,0 +1,67 @@ +#include +#include "ExchangeValidator.hpp" + +ExchangeValidator::ExchangeValidator (QObject * parent) + : QValidator {parent} +{ +} + +auto ExchangeValidator::validate (QString& input, int& length) const -> State +{ + bool ok=false; + QStringList w=input.split(" "); + int nwords=w.size(); + length=input.size(); + input = input.toUpper (); + + if(nwords==1 and length<=3) { + //ARRL RTTY Roundup +// ntype=4; +// ok=exch_valid_(&ntype, const_cast(input.toLatin1().constData()),length); + QStringList states; + states << "AL" << "AK" << "AZ" << "AR" << "CA" << "CO" + << "CT" << "DE" << "FL" << "GA" << "HI" << "ID" + << "IL" << "IN" << "IA" << "KS" << "KY" << "LA" + << "ME" << "MD" << "MA" << "MI" << "MN" << "MS" + << "MO" << "MT" << "NE" << "NV" << "NH" << "NJ" + << "NM" << "NY" << "NC" << "ND" << "OH" << "OK" + << "OR" << "PA" << "RI" << "SC" << "SD" << "TN" + << "TX" << "UT" << "VT" << "VA" << "WA" << "WV" + << "WI" << "WY" << "NB" << "NS" << "QC" << "ON" + << "MB" << "SK" << "AB" << "BC" << "NWT" << "NF" + << "LB" << "NU" << "YT" << "PEI" << "DC" << "DX"; + if(states.contains(input)) ok=true; + + } + if(nwords==2 and w.at(1).size()<=3) { + //ARRL Field Day + int n=w.at(0).size(); + if(n>3) goto done; + int ntx=w.at(0).left(n-1).toInt(); + if(ntx<1 or ntx>32) goto done; + QString c1=w.at(0).right(1); + if(c1<"A" or c1>"F") goto done; + QStringList sections; + sections << "AB" << "AK" << "AL" << "AR" << "AZ" << "BC" + << "CO" << "CT" << "DE" << "EB" << "EMA" << "ENY" + << "EPA" << "EWA" << "GA" << "GTA" << "IA" << "ID" + << "IL" << "IN" << "KS" << "KY" << "LA" << "LAX" + << "MAR" << "MB" << "MDC" << "ME" << "MI" << "MN" + << "MO" << "MS" << "MT" << "NC" << "ND" << "NE" + << "NFL" << "NH" << "NL" << "NLI" << "NM" << "NNJ" + << "NNY" << "NT" << "NTX" << "NV" << "OH" << "OK" + << "ONE" << "ONN" << "ONS" << "OR" << "ORG" << "PAC" + << "PR" << "QC" << "RI" << "SB" << "SC" << "SCV" + << "SD" << "SDG" << "SF" << "SFL" << "SJV" << "SK" + << "SNJ" << "STX" << "SV" << "TN" << "UT" << "VA" + << "VI" << "VT" << "WCF" << "WI" << "WMA" << "WNY" + << "WPA" << "WTX" << "WV" << "WWA" << "WY" << "DX"; + if(sections.contains(w.at(1))) ok=true; + } + +done: + qDebug() << input << ok; + if(ok) return Acceptable; +// return Invalid; + return Acceptable; +} diff --git a/ExchangeValidator.hpp b/ExchangeValidator.hpp new file mode 100644 index 000000000..1e7b508dc --- /dev/null +++ b/ExchangeValidator.hpp @@ -0,0 +1,19 @@ +#ifndef EXCHANGE_VALIDATOR_HPP__ +#define EXCHANGE_VALIDATOR_HPP__ + +#include + +// ExchangeValidator - QValidator for Field Day and RTTY Roundup exchanges + +class ExchangeValidator final + : public QValidator +{ +public: + ExchangeValidator (QObject * parent = nullptr); + + // QValidator implementation + State validate (QString& input, int& length) const override; + +}; + +#endif diff --git a/lib/77bit/exch_valid.f90 b/lib/77bit/exch_valid.f90 deleted file mode 100644 index 70613fc9a..000000000 --- a/lib/77bit/exch_valid.f90 +++ /dev/null @@ -1,61 +0,0 @@ -logical*1 function exch_valid(ntype,exch) - - parameter (NSEC=84) !Number of ARRL Sections - parameter (NUSCAN=65) !Number of US states and Canadian provinces - - character*(*) exch - character*3 c3 - character*3 cmult(NUSCAN) - character*3 csec(NSEC) - - data csec/ & - "AB ","AK ","AL ","AR ","AZ ","BC ","CO ","CT ","DE ","EB ", & - "EMA","ENY","EPA","EWA","GA ","GTA","IA ","ID ","IL ","IN ", & - "KS ","KY ","LA ","LAX","MAR","MB ","MDC","ME ","MI ","MN ", & - "MO ","MS ","MT ","NC ","ND ","NE ","NFL","NH ","NL ","NLI", & - "NM ","NNJ","NNY","NT ","NTX","NV ","OH ","OK ","ONE","ONN", & - "ONS","OR ","ORG","PAC","PR ","QC ","RI ","SB ","SC ","SCV", & - "SD ","SDG","SF ","SFL","SJV","SK ","SNJ","STX","SV ","TN ", & - "UT ","VA ","VI ","VT ","WCF","WI ","WMA","WNY","WPA","WTX", & - "WV ","WWA","WY ","DX "/ - data cmult/ & - "AL ","AK ","AZ ","AR ","CA ","CO ","CT ","DE ","FL ","GA ", & - "HI ","ID ","IL ","IN ","IA ","KS ","KY ","LA ","ME ","MD ", & - "MA ","MI ","MN ","MS ","MO ","MT ","NE ","NV ","NH ","NJ ", & - "NM ","NY ","NC ","ND ","OH ","OK ","OR ","PA ","RI ","SC ", & - "SD ","TN ","TX ","UT ","VT ","VA ","WA ","WV ","WI ","WY ", & - "NB ","NS ","QC ","ON ","MB ","SK ","AB ","BC ","NWT","NF ", & - "LB ","NU ","YT ","PEI","DC "/ - - exch_valid=.false. - n=len(trim(exch)) - if(ntype.ne.3 .and. ntype.ne.4) go to 900 - if(ntype.eq.3 .and. (n.lt.2 .or. n.gt.7)) go to 900 - if(ntype.eq.4 .and. (n.lt.2 .or. n.gt.3)) go to 900 - - if(ntype.eq.3) then !Field Day - i1=index(exch,' ') - if(i1.lt.3) go to 900 - read(exch(1:i1-2),*,err=900) ntx - if(ntx.lt.1 .or. ntx.gt.32) go to 900 - if(exch(i1-1:i1-1).lt.'A' .or. exch(i1-1:i1-1).gt.'F') go to 900 - c3=exch(i1+1:)//' ' - do i=1,NSEC - if(csec(i).eq.c3) then - exch_valid=.true. - go to 900 - endif - enddo - - else if(ntype.eq.4) then !RTTY Roundup - c3=exch//' ' - do i=1,NUSCAN - if(cmult(i).eq.c3) then - exch_valid=.true. - go to 900 - endif - enddo - endif - -900 return -end function exch_valid diff --git a/mainwindow.cpp b/mainwindow.cpp index 713ea4c13..b13b5b290 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -58,6 +58,7 @@ #include "MultiSettings.hpp" #include "MaidenheadLocatorValidator.hpp" #include "CallsignValidator.hpp" +#include "ExchangeValidator.hpp" #include "EqualizationToolsDialog.hpp" #include "ui_mainwindow.h" diff --git a/wsjtx.pro b/wsjtx.pro index 3d16edf02..5c2124af0 100644 --- a/wsjtx.pro +++ b/wsjtx.pro @@ -67,7 +67,8 @@ SOURCES += \ echoplot.cpp echograph.cpp fastgraph.cpp fastplot.cpp Modes.cpp \ WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\ MultiSettings.cpp PhaseEqualizationDialog.cpp IARURegions.cpp MessageBox.cpp \ - EqualizationToolsDialog.cpp CallsignValidator.cpp colorhighlighting.cpp + EqualizationToolsDialog.cpp CallsignValidator.cpp ExchangeValidator.cpp \ + colorhighlighting.cpp HEADERS += qt_helpers.hpp \ pimpl_h.hpp pimpl_impl.hpp \ @@ -83,7 +84,8 @@ HEADERS += qt_helpers.hpp \ logbook/logbook.h logbook/countrydat.h logbook/countriesworked.h logbook/adif.h \ messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \ WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp \ - IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp CallsignValidator.hpp colorhighlighting.h + IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp CallsignValidator.hpp \ + ExchangeValidator.hpp colorhighlighting.h INCLUDEPATH += qmake_only From 0c9e9aeadc233da756d0f96e60366f2935c92ca7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 10:03:11 -0400 Subject: [PATCH 13/52] Implement a QValidator for the Field Day and RTTY exchanges. --- Configuration.cpp | 28 ++++++++++++++++++++++++++++ Configuration.ui | 10 +++++----- ExchangeValidator.cpp | 4 +--- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Configuration.cpp b/Configuration.cpp index 26425fca0..719fe731d 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -457,6 +457,10 @@ private: Q_SLOT void on_cbx2ToneSpacing_clicked(bool); Q_SLOT void on_cbx4ToneSpacing_clicked(bool); Q_SLOT void on_rbNone_toggled(bool); + Q_SLOT void on_rbFieldDay_toggled(); + Q_SLOT void on_rbRTTYroundup_toggled(); + Q_SLOT void on_FieldDay_Exchange_textChanged(); + Q_SLOT void on_RTTY_Exchange_textChanged(); // typenames used as arguments must match registered type names :( Q_SIGNAL void start_transceiver (unsigned seqeunce_number) const; @@ -2348,6 +2352,20 @@ void Configuration::impl::on_add_macro_line_edit_editingFinished () ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ()); } +void Configuration::impl::on_FieldDay_Exchange_textChanged() +{ + bool b=ui_->FieldDay_Exchange->hasAcceptableInput() or !ui_->rbFieldDay->isChecked(); + if(b) ui_->FieldDay_Exchange->setStyleSheet("color: black"); + if(!b) ui_->FieldDay_Exchange->setStyleSheet("color: red"); +} + +void Configuration::impl::on_RTTY_Exchange_textChanged() +{ + bool b=ui_->RTTY_Exchange->hasAcceptableInput() or !ui_->rbRTTYroundup->isChecked(); + if(b) ui_->RTTY_Exchange->setStyleSheet("color: black"); + if(!b) ui_->RTTY_Exchange->setStyleSheet("color: red"); +} + void Configuration::impl::on_delete_macro_push_button_clicked (bool /* checked */) { auto selection_model = ui_->macros_list_view->selectionModel (); @@ -2612,6 +2630,16 @@ void Configuration::impl::on_rbNone_toggled(bool b) if(!b) ui_->cbGenerate77->setChecked(true); } +void Configuration::impl::on_rbFieldDay_toggled() +{ + on_FieldDay_Exchange_textChanged(); +} + +void Configuration::impl::on_rbRTTYroundup_toggled() +{ + on_RTTY_Exchange_textChanged(); +} + void Configuration::impl::on_cbx2ToneSpacing_clicked(bool b) { if(b) ui_->cbx4ToneSpacing->setChecked(false); diff --git a/Configuration.ui b/Configuration.ui index 34366a1a0..47cd2147c 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -2805,7 +2805,7 @@ Right click for insert and delete options. - + Exch: @@ -2859,7 +2859,7 @@ Right click for insert and delete options. - + Exch: @@ -3106,12 +3106,12 @@ soundcard changes - + - - + + diff --git a/ExchangeValidator.cpp b/ExchangeValidator.cpp index e825d00ca..92c77e6aa 100644 --- a/ExchangeValidator.cpp +++ b/ExchangeValidator.cpp @@ -60,8 +60,6 @@ auto ExchangeValidator::validate (QString& input, int& length) const -> State } done: - qDebug() << input << ok; if(ok) return Acceptable; -// return Invalid; - return Acceptable; + return Intermediate; } From 29862476c6be9771e3d5e8cc5b3619c04678104b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 11:48:12 -0400 Subject: [PATCH 14/52] Option to AutoLog in contests; display to "Fox and Contest Log" window. --- Configuration.cpp | 18 ++++++++++++++++++ Configuration.hpp | 1 + Configuration.ui | 45 ++++++++++++++++++++++++++------------------- logqso.cpp | 5 +++-- logqso.h | 3 ++- mainwindow.cpp | 25 ++++++++++++++----------- mainwindow.ui | 10 +++++----- 7 files changed, 69 insertions(+), 38 deletions(-) diff --git a/Configuration.cpp b/Configuration.cpp index 719fe731d..d9be02e71 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -461,6 +461,8 @@ private: Q_SLOT void on_rbRTTYroundup_toggled(); Q_SLOT void on_FieldDay_Exchange_textChanged(); Q_SLOT void on_RTTY_Exchange_textChanged(); + Q_SLOT void on_prompt_to_log_check_box_clicked(bool); + Q_SLOT void on_cbAutoLog_clicked(bool); // typenames used as arguments must match registered type names :( Q_SIGNAL void start_transceiver (unsigned seqeunce_number) const; @@ -579,6 +581,7 @@ private: bool log_as_RTTY_; bool report_in_comments_; bool prompt_to_log_; + bool autoLog_; bool insert_blank_; bool DXCC_; bool ppfx_; @@ -692,6 +695,7 @@ bool Configuration::monitor_last_used () const {return m_->rig_is_dummy_ || m_-> bool Configuration::log_as_RTTY () const {return m_->log_as_RTTY_;} bool Configuration::report_in_comments () const {return m_->report_in_comments_;} bool Configuration::prompt_to_log () const {return m_->prompt_to_log_;} +bool Configuration::autoLog() const {return m_->autoLog_;} bool Configuration::insert_blank () const {return m_->insert_blank_;} bool Configuration::DXCC () const {return m_->DXCC_;} bool Configuration::ppfx() const {return m_->ppfx_;} @@ -1213,6 +1217,7 @@ void Configuration::impl::initialize_models () ui_->log_as_RTTY_check_box->setChecked (log_as_RTTY_); ui_->report_in_comments_check_box->setChecked (report_in_comments_); ui_->prompt_to_log_check_box->setChecked (prompt_to_log_); + ui_->cbAutoLog->setChecked(autoLog_); ui_->insert_blank_check_box->setChecked (insert_blank_); ui_->DXCC_check_box->setChecked (DXCC_); ui_->ppfx_check_box->setChecked (ppfx_); @@ -1466,6 +1471,7 @@ void Configuration::impl::read_settings () rig_params_.ptt_port = settings_->value ("PTTport").toString (); data_mode_ = settings_->value ("DataMode", QVariant::fromValue (data_mode_none)).value (); prompt_to_log_ = settings_->value ("PromptToLog", false).toBool (); + autoLog_ = settings_->value ("AutoLog", false).toBool (); insert_blank_ = settings_->value ("InsertBlank", false).toBool (); DXCC_ = settings_->value ("DXCCEntity", false).toBool (); ppfx_ = settings_->value ("PrincipalPrefix", false).toBool (); @@ -1578,6 +1584,7 @@ void Configuration::impl::write_settings () settings_->setValue ("CATHandshake", QVariant::fromValue (rig_params_.handshake)); settings_->setValue ("DataMode", QVariant::fromValue (data_mode_)); settings_->setValue ("PromptToLog", prompt_to_log_); + settings_->setValue ("AutoLog", autoLog_); settings_->setValue ("InsertBlank", insert_blank_); settings_->setValue ("DXCCEntity", DXCC_); settings_->setValue ("PrincipalPrefix", ppfx_); @@ -1999,6 +2006,7 @@ void Configuration::impl::accept () log_as_RTTY_ = ui_->log_as_RTTY_check_box->isChecked (); report_in_comments_ = ui_->report_in_comments_check_box->isChecked (); prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked (); + autoLog_ = ui_->cbAutoLog->isChecked(); insert_blank_ = ui_->insert_blank_check_box->isChecked (); DXCC_ = ui_->DXCC_check_box->isChecked (); ppfx_ = ui_->ppfx_check_box->isChecked (); @@ -2596,6 +2604,16 @@ void Configuration::impl::on_calibration_slope_ppm_spin_box_valueChanged (double rig_active_ = false; // force reset } +void Configuration::impl::on_prompt_to_log_check_box_clicked(bool checked) +{ + if(checked) ui_->cbAutoLog->setChecked(false); +} + +void Configuration::impl::on_cbAutoLog_clicked(bool checked) +{ + if(checked) ui_->prompt_to_log_check_box->setChecked(false); +} + void Configuration::impl::on_cbFox_clicked (bool checked) { if(checked) { diff --git a/Configuration.hpp b/Configuration.hpp index c7372f1b4..f697ed4a3 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -115,6 +115,7 @@ public: bool log_as_RTTY () const; bool report_in_comments () const; bool prompt_to_log () const; + bool autoLog() const; bool insert_blank () const; bool DXCC () const; bool ppfx() const; diff --git a/Configuration.ui b/Configuration.ui index 47cd2147c..5e2993de9 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -1702,24 +1702,7 @@ QListView::item:hover { - - - - <html><head/><body><p>The callsign of the operator, if different from the station callsign.</p></body></html> - - - - - - - Some logging programs will not accept JT-65 or JT9 as a recognized mode. - - - Con&vert mode to RTTY - - - - + Some logging programs will not accept the type of reports @@ -1732,7 +1715,7 @@ comments field. - + Check this option to force the clearing of the DX Call @@ -1743,6 +1726,30 @@ and DX Grid fields when a 73 or free text message is sent. + + + + Some logging programs will not accept JT-65 or JT9 as a recognized mode. + + + Con&vert mode to RTTY + + + + + + + <html><head/><body><p>The callsign of the operator, if different from the station callsign.</p></body></html> + + + + + + + Log automatically + + + diff --git a/logqso.cpp b/logqso.cpp index 980cdcef2..e66f2e696 100644 --- a/logqso.cpp +++ b/logqso.cpp @@ -59,7 +59,8 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid, - bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, QString const& opCall) + bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, + bool bAutoLog, QString const& opCall) { if(!isHidden()) return; ui->call->setText(hisCall); @@ -87,7 +88,7 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString m_myGrid=myGrid; ui->band->setText (m_config->bands ()->find (dialFreq)); ui->loggedOperator->setText(opCall); - if(bFox) { + if(bFox or bAutoLog) { accept(); } else { show (); diff --git a/logqso.h b/logqso.h index fb92201e1..971117dd8 100644 --- a/logqso.h +++ b/logqso.h @@ -33,7 +33,8 @@ public: QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid, - bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, QString const& opCall); + bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, + bool bAutoLog, QString const& opCall); public slots: void accept(); diff --git a/mainwindow.cpp b/mainwindow.cpp index b13b5b290..c6231b9f2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -2407,13 +2407,12 @@ void MainWindow::on_actionColors_triggered() void MainWindow::on_actionMessage_averaging_triggered() { - if (!m_msgAvgWidget) - { - m_msgAvgWidget.reset (new MessageAveraging {m_settings, m_config.decoded_text_font ()}); + if(!m_msgAvgWidget) { + m_msgAvgWidget.reset (new MessageAveraging {m_settings, m_config.decoded_text_font ()}); - // Connect signals from Message Averaging window - connect (this, &MainWindow::finished, m_msgAvgWidget.data (), &MessageAveraging::close); - } + // Connect signals from Message Averaging window + connect (this, &MainWindow::finished, m_msgAvgWidget.data (), &MessageAveraging::close); + } m_msgAvgWidget->showNormal(); m_msgAvgWidget->raise (); m_msgAvgWidget->activateWindow (); @@ -3630,8 +3629,8 @@ void MainWindow::guiUpdate() if(m_config.id_after_73 ()) { icw[0] = m_ncw; } - if (m_config.prompt_to_log () && !m_tune) { - logQSOTimer.start (0); + if ((m_config.prompt_to_log() or m_config.autoLog()) && !m_tune) { + logQSOTimer.start(0); } } @@ -3754,7 +3753,7 @@ void MainWindow::guiUpdate() //Once per second: if(nsec != m_sec0) { -// qDebug() << "OneSec:"; +// qDebug() << "OneSec:" << m_config.autoLog(); if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { if(!m_bVHFwarned) vhfWarning(); @@ -5185,11 +5184,12 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button if (dateTimeQSOOff < m_dateTimeQSOOn) dateTimeQSOOff = m_dateTimeQSOOn; QString grid=m_hisGrid; if(grid=="....") grid=""; + bool bAutoLog=m_config.autoLog() and m_nContest>0; m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + ui->TxFreqSpinBox->value(), m_config.my_callsign(), m_config.my_grid(), m_noSuffix, m_config.log_as_RTTY(), m_config.report_in_comments(), - m_config.bFox(), m_opCall); + m_config.bFox(), bAutoLog, m_opCall); if(m_nContest!=NONE) { if(m_nContest==NA_VHF) { m_xSent=m_config.my_grid().left(4); @@ -5217,6 +5217,9 @@ void MainWindow::cabLog() QTextStream out(&f); out << t << endl; f.close(); + if(m_msgAvgWidget != NULL and m_msgAvgWidget->isVisible()) { + m_msgAvgWidget->foxAddLog(t); + } } else { MessageBox::warning_message (this, tr("File Open Error"), tr("Cannot open \"%1\" for append: %2").arg(f.fileName()).arg(f.errorString())); @@ -6773,7 +6776,7 @@ void::MainWindow::VHF_features_enabled(bool b) ui->actionMessage_averaging->setEnabled(b); ui->actionEnable_AP_DXcall->setVisible (m_mode=="QRA64"); ui->actionEnable_AP_JT65->setVisible (b && m_mode=="JT65"); - if(!b && m_msgAvgWidget and !m_config.bFox()) { + if(!b && m_msgAvgWidget and !m_config.bFox() and !m_config.autoLog()) { if(m_msgAvgWidget->isVisible()) m_msgAvgWidget->close(); } } diff --git a/mainwindow.ui b/mainwindow.ui index 5b6dc38b0..afab96456 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -656,7 +656,7 @@ QLabel[oob="true"] { - 20 + 50 20 @@ -700,7 +700,7 @@ QLabel[oob="true"] { - 20 + 50 20 @@ -3275,13 +3275,13 @@ QPushButton[state="ok"] { - Fox Log + Fox or Contest Log - Fox Log + Fox or Contest Log - Fox Log + Fox or Contest Log From cc7d42407876f8a6dc1ea6d095954a3c6330a839 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 12:14:17 -0400 Subject: [PATCH 15/52] Contest log to the "fox log" window. --- mainwindow.cpp | 6 ++++-- mainwindow.h | 4 +++- mainwindow.ui | 5 +++++ messageaveraging.cpp | 18 ++++++++++++++++-- messageaveraging.h | 3 ++- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index c6231b9f2..f0f8210cb 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1199,6 +1199,8 @@ void MainWindow::setContestType() if(m_config.bEU_VHF_Contest()) m_nContest=EU_VHF; if(m_config.bFieldDay()) m_nContest=FIELD_DAY; if(m_config.bRTTYroundup()) m_nContest=RTTY; + if(m_config.bFox()) m_nContest=FOX; + if(m_config.bHound()) m_nContest=HOUND; } void MainWindow::set_application_font (QFont const& font) @@ -2388,7 +2390,7 @@ void MainWindow::on_actionAstronomical_data_toggled (bool checked) void MainWindow::on_actionFox_Log_triggered() { on_actionMessage_averaging_triggered(); - m_msgAvgWidget->foxLogSetup(); + m_msgAvgWidget->foxLogSetup(m_nContest); } void MainWindow::on_actionColors_triggered() @@ -3753,7 +3755,7 @@ void MainWindow::guiUpdate() //Once per second: if(nsec != m_sec0) { -// qDebug() << "OneSec:" << m_config.autoLog(); + qDebug() << "OneSec:" << m_nContest; if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { if(!m_bVHFwarned) vhfWarning(); diff --git a/mainwindow.h b/mainwindow.h index 94f009871..607c832bd 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -518,7 +518,9 @@ private: NA_VHF, EU_VHF, FIELD_DAY, - RTTY + RTTY, + FOX, + HOUND } m_nContest; //Contest type enum {CALL, GRID, DXCC, MULT}; diff --git a/mainwindow.ui b/mainwindow.ui index afab96456..b93653962 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -3304,6 +3304,11 @@ QPushButton[state="ok"] { Color highlighting scheme + + + Contest Log + + diff --git a/messageaveraging.cpp b/messageaveraging.cpp index 052de7273..0711d93b6 100644 --- a/messageaveraging.cpp +++ b/messageaveraging.cpp @@ -88,9 +88,23 @@ void MessageAveraging::displayAvg(QString const& t) ui->msgAvgPlainTextEdit->setPlainText(t); } -void MessageAveraging::foxLogSetup() +void MessageAveraging::foxLogSetup(int nContest) { - m_title_=QApplication::applicationName () + " - Fox Log"; + if(nContest==5) { + m_title_=QApplication::applicationName () + " - Fox Log"; + setWindowTitle(m_title_); + ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); + } + if(nContest>0 and nContest<5) { + m_title_=QApplication::applicationName () + " - Contest Log"; + setWindowTitle(m_title_); + ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); + } +} + +void MessageAveraging::contestLogSetup() +{ + m_title_=QApplication::applicationName () + " - Contest Log"; setWindowTitle(m_title_); ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); } diff --git a/messageaveraging.h b/messageaveraging.h index ea8e06b9e..6705bceed 100644 --- a/messageaveraging.h +++ b/messageaveraging.h @@ -17,7 +17,8 @@ public: ~MessageAveraging(); void displayAvg(QString const&); void changeFont (QFont const&); - void foxLogSetup(); + void foxLogSetup(int nContest); + void contestLogSetup(); void foxLabCallers(int n); void foxLabQueued(int n); void foxLabRate(int n); From 87f197ad4eedc6a86644c66cd3d6790fa5521e4c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 12:54:23 -0400 Subject: [PATCH 16/52] Cleanup. --- lib/77bit/t1.f90 | 54 ------------------------------------------------ lib/77bit/t3.f90 | 25 ---------------------- 2 files changed, 79 deletions(-) delete mode 100644 lib/77bit/t1.f90 delete mode 100644 lib/77bit/t3.f90 diff --git a/lib/77bit/t1.f90 b/lib/77bit/t1.f90 deleted file mode 100644 index 28c99292e..000000000 --- a/lib/77bit/t1.f90 +++ /dev/null @@ -1,54 +0,0 @@ -program t1 - - real x(13) - real(KIND=16) :: dlong,dlong0 - character wd*13,w*13,error*5 - character c*44 !NB: 44^13 = 2^(70.973) - data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?@$'/ - - nargs=iargc() - if(nargs.ne.1) then - print*,'Usage: t1 "FreeText13"' - print*,' t1 ' - go to 999 - endif - call getarg(1,w) - iters=1 - read(w,*,err=10) iters -10 continue - - do iter=1,iters - if(iters.gt.1) then -! Create a random free-text word - call random_number(x) - do i=1,13 - j=44*x(i) + 1 - w(i:i)=c(j:j) - enddo - endif -! Encode a 13-character free-text message into a 71-bit integer. - dlong=0.d0 - do i=1,13 - n=index(c,w(i:i))-1 - dlong=44.d0*dlong + n - enddo - dlong0=dlong - - ! Decode a a 71-bit integer into a 13-character free-text message. - do i=13,1,-1 - j=mod(dlong,44.d0)+1.d0 - wd(i:i)=c(j:j) - dlong=dlong/44.d0 - enddo - - - error=' ' - if(wd.ne.w) then - error='ERROR' - write(*,1010) w,dlong0,wd,error -1010 format('"',a13,'"',f25.1,2x,'"',a13'"',2x,a5) - endif - if(mod(iter,1000).eq.0) print*,iter - enddo - -999 end program t1 diff --git a/lib/77bit/t3.f90 b/lib/77bit/t3.f90 deleted file mode 100644 index 0b074c5a1..000000000 --- a/lib/77bit/t3.f90 +++ /dev/null @@ -1,25 +0,0 @@ -program t3 - character*3 csec - character*70 line - logical eof - - eof=.false. - j=1 - do i=1,83 - read(*,1001,end=1) csec -1001 format(a3) - go to 2 -1 eof=.true. -2 line(j:j+5)='"'//csec//'",' - j=j+6 - if(j.gt.60 .or. i.eq.83 .or.eof) then - line(j:j+2)=' &' - line(j+3:)=' ' - write(*,1010) line -1010 format(a70) - j=1 - endif - if(eof) go to 999 - enddo - -999 end program t3 From 8d8811c6e15c08df97cac033b4944fcb67be6f69 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 12:55:17 -0400 Subject: [PATCH 17/52] We might possibly want to use "emedop" again... --- lib/emedop.dat | 8 ++++++ lib/emedop.f90 | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 lib/emedop.dat create mode 100644 lib/emedop.f90 diff --git a/lib/emedop.dat b/lib/emedop.dat new file mode 100644 index 000000000..c37d5b85c --- /dev/null +++ b/lib/emedop.dat @@ -0,0 +1,8 @@ +Lat_A 40.35417 +WLong_A 75.62500 +Lat_B 45.1875 +WLong_B -1.541667 +TxFreqMHz 143.05 +StartTime 20180907 08:00:00 +StopTime 20180907 09:00:00 +StepSec 60.0 diff --git a/lib/emedop.f90 b/lib/emedop.f90 new file mode 100644 index 000000000..4a95fb87a --- /dev/null +++ b/lib/emedop.f90 @@ -0,0 +1,67 @@ +program emedop + + real*8 txfreq8 + real*8 rxfreq8 + real*4 LST + real*4 lat_a + real*4 lat_b + character*80 infile + character*256 jpleph_file_name + common/jplcom/jpleph_file_name + data jpleph_file_name/'JPLEPH'/ + + nargs=iargc() + if(nargs.ne.1) then + print*,'Usage: emedop ' + go to 999 + endif + + call getarg(1,infile) + open(10,file=infile,status='old',err=900) + read(10,1001) lat_a +1001 format(10x,f12.0) + read(10,1001) wlon_a + read(10,1001) lat_b + read(10,1001) wlon_b + read(10,1001) txfreq8 + read(10,1002) nyear,month,nday,ih,im,is +1002 format(10x,i4,2i2,1x,i2,1x,i2,1x,i2) + sec_start=3600.0*ih + 60.0*im + is + read(10,1002) nyear,month,nday,ih,im,is + sec_stop=3600.0*ih + 60.0*im + is + read(10,1001) sec_step + + write(*,1005) +1005 format(' Date UTC Tx Freq Rx Freq Doppler'/ & + '------------------------------------------------------') + + sec=sec_start + ncalc=(sec_stop - sec_start)/sec_step + + do icalc=1,ncalc + uth=sec/3600.0 + call MoonDopJPL(nyear,month,nday,uth,-wlon_a,lat_a,RAMoon,DecMoon, & + LST,HA,AzMoon,ElMoon,vr_a,techo) + + call MoonDopJPL(nyear,month,nday,uth,-wlon_b,lat_b,RAMoon,DecMoon, & + LST,HA,AzMoon,ElMoon,vr_b,techo) + + dop_a=-txfreq8*vr_a/2.99792458e5 !One-way Doppler from a + dop_b=-txfreq8*vr_b/2.99792458e5 !One-way Doppler to b + doppler=1.e6*(dop_a + dop_b) + rxfreq8=txfreq8 + dop_a + dop_b + + ih=sec/3600.0 + im=(sec-ih*3600.0)/60.0 + is=nint(mod(sec,60.0)) + write(*,1010) nyear,month,nday,ih,im,is,txFreq8,rxFreq8,doppler +1010 format(i4,2i2.2,2x,i2.2,':',i2.2,':',i2.2,2f13.7,f8.1) + + sec=sec + sec_step + enddo + go to 999 +900 print*,'Cannot open file ',trim(infile) +999 end program emedop + + + From 58cbf3abbdcbe52635208f6b64b70ef0457bc303 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 12:57:40 -0400 Subject: [PATCH 18/52] Turn off a qDebug(). --- mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index f0f8210cb..5ba216c4a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -3755,7 +3755,7 @@ void MainWindow::guiUpdate() //Once per second: if(nsec != m_sec0) { - qDebug() << "OneSec:" << m_nContest; +// qDebug() << "OneSec:" << m_nContest; if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { if(!m_bVHFwarned) vhfWarning(); From 48f4b9d82482121b6a403f0158ba7848b5414c6c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 13:23:46 -0400 Subject: [PATCH 19/52] Add suitable labels for logging to the real-time logging window. --- mainwindow.cpp | 4 ++++ messageaveraging.cpp | 11 +++-------- messageaveraging.h | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 5ba216c4a..4bf103cec 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5220,6 +5220,10 @@ void MainWindow::cabLog() out << t << endl; f.close(); if(m_msgAvgWidget != NULL and m_msgAvgWidget->isVisible()) { + QString band; + band.sprintf(" %5d ",nfreq); + t=QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hhmm ") + band + + m_hisCall.leftJustified(13,' ') + m_xSent.leftJustified(14,' ') + m_xRcvd; m_msgAvgWidget->foxAddLog(t); } } else { diff --git a/messageaveraging.cpp b/messageaveraging.cpp index 0711d93b6..b73a5a9d9 100644 --- a/messageaveraging.cpp +++ b/messageaveraging.cpp @@ -20,6 +20,8 @@ MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWid read_settings (); if(m_title_.contains("Fox")) { ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); + } else if(m_title_.contains("Contest")) { + ui->header_label->setText(" Date UTC Band Call Sent Rcvd"); } else { ui->header_label->setText(" UTC Sync DT Freq "); ui->lab1->setVisible(false); @@ -98,17 +100,10 @@ void MessageAveraging::foxLogSetup(int nContest) if(nContest>0 and nContest<5) { m_title_=QApplication::applicationName () + " - Contest Log"; setWindowTitle(m_title_); - ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); + ui->header_label->setText(" Date UTC Band Call Sent Rcvd"); } } -void MessageAveraging::contestLogSetup() -{ - m_title_=QApplication::applicationName () + " - Contest Log"; - setWindowTitle(m_title_); - ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); -} - void MessageAveraging::foxLabCallers(int n) { QString t; diff --git a/messageaveraging.h b/messageaveraging.h index 6705bceed..05358db89 100644 --- a/messageaveraging.h +++ b/messageaveraging.h @@ -18,7 +18,6 @@ public: void displayAvg(QString const&); void changeFont (QFont const&); void foxLogSetup(int nContest); - void contestLogSetup(); void foxLabCallers(int n); void foxLabQueued(int n); void foxLabRate(int n); From 154a6f2ca3112e83eee7f4ca8ef30f63e80ea8d7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 14:04:57 -0400 Subject: [PATCH 20/52] Clean up the AutoLog implementation. --- mainwindow.cpp | 2 +- messageaveraging.cpp | 18 ++++++++++++++++++ messageaveraging.h | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 4bf103cec..ecfefbcd2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5224,7 +5224,7 @@ void MainWindow::cabLog() band.sprintf(" %5d ",nfreq); t=QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hhmm ") + band + m_hisCall.leftJustified(13,' ') + m_xSent.leftJustified(14,' ') + m_xRcvd; - m_msgAvgWidget->foxAddLog(t); + m_msgAvgWidget->contestAddLog(m_nContest,t); } } else { MessageBox::warning_message (this, tr("File Open Error"), diff --git a/messageaveraging.cpp b/messageaveraging.cpp index b73a5a9d9..0045c4f58 100644 --- a/messageaveraging.cpp +++ b/messageaveraging.cpp @@ -22,6 +22,10 @@ MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWid ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); } else if(m_title_.contains("Contest")) { ui->header_label->setText(" Date UTC Band Call Sent Rcvd"); + ui->lab1->setText("QSOs: 0"); + ui->lab2->setText("Mults: 0"); + ui->lab3->setText("Score: 0"); + ui->lab4->setText("Rate: 0"); } else { ui->header_label->setText(" UTC Sync DT Freq "); ui->lab1->setVisible(false); @@ -29,6 +33,7 @@ MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWid ui->lab3->setVisible(false); ui->lab4->setVisible(false); } + setWindowTitle(m_title_); m_nLogged_=0; } @@ -76,6 +81,7 @@ void MessageAveraging::read_settings () SettingsGroup group {settings_, "MessageAveraging"}; restoreGeometry (settings_->value ("window/geometry").toByteArray ()); m_title_=settings_->value("window/title","Message Averaging").toString(); + m_nContest_=settings_->value("nContest",0).toInt(); } void MessageAveraging::write_settings () @@ -83,6 +89,7 @@ void MessageAveraging::write_settings () SettingsGroup group {settings_, "MessageAveraging"}; settings_->setValue ("window/geometry", saveGeometry ()); settings_->setValue("window/title",m_title_); + settings_->setValue("nContest",m_nContest_); } void MessageAveraging::displayAvg(QString const& t) @@ -102,6 +109,7 @@ void MessageAveraging::foxLogSetup(int nContest) setWindowTitle(m_title_); ui->header_label->setText(" Date UTC Band Call Sent Rcvd"); } + m_nContest_=nContest; } void MessageAveraging::foxLabCallers(int n) @@ -133,3 +141,13 @@ void MessageAveraging::foxAddLog(QString logLine) t.sprintf("Logged: %d",m_nLogged_); ui->lab3->setText(t); } + +void MessageAveraging::contestAddLog(qint32 nContest, QString logLine) +{ + m_nContest_=nContest; + ui->msgAvgPlainTextEdit->appendPlainText(logLine); + m_nLogged_++; + QString t; + t.sprintf("QSOs: %d",m_nLogged_); + ui->lab1->setText(t); +} diff --git a/messageaveraging.h b/messageaveraging.h index 05358db89..9e7f84122 100644 --- a/messageaveraging.h +++ b/messageaveraging.h @@ -22,6 +22,7 @@ public: void foxLabQueued(int n); void foxLabRate(int n); void foxAddLog(QString logLine); + void contestAddLog(qint32 nContest, QString logLine); protected: void closeEvent (QCloseEvent *) override; @@ -33,6 +34,7 @@ private: QSettings * settings_; QString m_title_; qint32 m_nLogged_; + qint32 m_nContest_; QScopedPointer ui; }; From 66ef044da0c9ed96592ab536fcbc15556b876f31 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 14:16:49 -0400 Subject: [PATCH 21/52] Basif framework for computing and displaying contest score. Not complete! --- messageaveraging.cpp | 7 +++++++ messageaveraging.h | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/messageaveraging.cpp b/messageaveraging.cpp index 0045c4f58..496249ae3 100644 --- a/messageaveraging.cpp +++ b/messageaveraging.cpp @@ -150,4 +150,11 @@ void MessageAveraging::contestAddLog(qint32 nContest, QString logLine) QString t; t.sprintf("QSOs: %d",m_nLogged_); ui->lab1->setText(t); + if(m_mult_<1) m_mult_=1; + t.sprintf("Mults: %d",m_mult_); + ui->lab2->setText(t); + int score=m_mult_*m_nLogged_; + t.sprintf("Score: %d",score); + ui->lab3->setText(t); + qDebug() << m_nLogged_ << m_mult_ << score; } diff --git a/messageaveraging.h b/messageaveraging.h index 9e7f84122..390a4249b 100644 --- a/messageaveraging.h +++ b/messageaveraging.h @@ -33,7 +33,8 @@ private: void setContentFont (QFont const&); QSettings * settings_; QString m_title_; - qint32 m_nLogged_; + qint32 m_nLogged_=0; + qint32 m_mult_=0; qint32 m_nContest_; QScopedPointer ui; From 1170c4054a43fda5814e02b692846451fa3aab18 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 2 Oct 2018 15:52:25 -0400 Subject: [PATCH 22/52] Save contest exchange to ADIF log. (Not finished...) --- logbook/adif.cpp | 38 +++++++++++++++----------------------- logbook/adif.h | 11 ++++++----- logqso.cpp | 11 ++++++++--- logqso.h | 6 +++++- mainwindow.cpp | 34 +++++++++++++++++++++++----------- messageaveraging.cpp | 1 - 6 files changed, 57 insertions(+), 44 deletions(-) diff --git a/logbook/adif.cpp b/logbook/adif.cpp index d4878d5d7..a804e6992 100644 --- a/logbook/adif.cpp +++ b/logbook/adif.cpp @@ -180,11 +180,12 @@ int ADIF::getCount() const return _data.size(); } -QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode - , QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn - , QDateTime const& dateTimeOff, QString const& band, QString const& comments - , QString const& name, QString const& strDialFreq, QString const& m_myCall - , QString const& m_myGrid, QString const& m_txPower, QString const& operator_call) +QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, + QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, + QDateTime const& dateTimeOff, QString const& band, QString const& comments, + QString const& name, QString const& strDialFreq, QString const& m_myCall, + QString const& m_myGrid, QString const& m_txPower, QString const& operator_call, + QString const& xSent, QString const& xRcvd) { QString t; t = "" + hisCall; @@ -198,26 +199,17 @@ QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QStri t += " " + dateTimeOff.time().toString("hhmmss"); t += " " + band; t += " " + strDialFreq; - t += " " + - m_myCall; - t += " " + - m_myGrid; - if (m_txPower != "") - t += " " + m_txPower; - if (comments != "") - t += " " + comments; - if (name != "") - t += " " + name; - if (operator_call!="") - t+=" " + operator_call; - return t.toLatin1 (); + t += " " + m_myCall; + t += " " + m_myGrid; + if(m_txPower!="") t += " " + m_txPower; + if(comments!="") t += " " + comments; + if(name!="") t += " " + name; + if(operator_call!="") t+=" " + operator_call; + if(xSent!="") t += " " + xSent; + if(xRcvd!="") t += " " + xRcvd; + return t.toLatin1(); } - // open ADIF file and append the QSO details. Return true on success bool ADIF::addQSOToFile(QByteArray const& ADIF_record) { diff --git a/logbook/adif.h b/logbook/adif.h index 384ba4924..d203227f1 100644 --- a/logbook/adif.h +++ b/logbook/adif.h @@ -33,11 +33,12 @@ class ADIF // open ADIF file and append the QSO details. Return true on success bool addQSOToFile(QByteArray const& ADIF_record); - QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent - , QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff - , QString const& band, QString const& comments, QString const& name - , QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid - , QString const& m_txPower, QString const& operator_call); + QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, + QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, + QDateTime const& dateTimeOff, QString const& band, QString const& comments, + QString const& name, QString const& strDialFreq, QString const& m_myCall, + QString const& m_myGrid, QString const& m_txPower, QString const& operator_call, + QString const& xSent, QString const& xRcvd); private: struct QSO diff --git a/logqso.cpp b/logqso.cpp index e66f2e696..be3ae2f88 100644 --- a/logqso.cpp +++ b/logqso.cpp @@ -60,9 +60,13 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid, bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, - bool bAutoLog, QString const& opCall) + bool bAutoLog, QString const& opCall, qint32 nContest, + QString xSent, QString xRcvd) { if(!isHidden()) return; + m_nContest=nContest; + m_xSent=xSent; + m_xRcvd=xRcvd; ui->call->setText(hisCall); ui->grid->setText(hisGrid); ui->name->setText(""); @@ -120,8 +124,9 @@ void LogQSO::accept() auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx_log.adi"); adifile.init(adifilePath); - QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band - , comments, name, strDialFreq, m_myCall, m_myGrid, m_txPower, operator_call)}; + QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, rptSent, rptRcvd, + m_dateTimeOn, m_dateTimeOff, band, comments, name, strDialFreq, m_myCall, + m_myGrid, m_txPower, operator_call, m_xSent, m_xRcvd)}; if (!adifile.addQSOToFile (ADIF)) { MessageBox::warning_message (this, tr ("Log file error"), diff --git a/logqso.h b/logqso.h index 971117dd8..f70e297d7 100644 --- a/logqso.h +++ b/logqso.h @@ -34,7 +34,8 @@ public: QDateTime const& dateTimeOff, Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid, bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, - bool bAutoLog, QString const& opCall); + bool bAutoLog, QString const& opCall, qint32 nContest, QString xSent, + QString xRcvd); public slots: void accept(); @@ -62,6 +63,9 @@ private: Radio::Frequency m_dialFreq; QString m_myCall; QString m_myGrid; + QString m_xSent; + QString m_xRcvd; + qint32 m_nContest; QDateTime m_dateTimeOn; QDateTime m_dateTimeOff; }; diff --git a/mainwindow.cpp b/mainwindow.cpp index ecfefbcd2..22cefdfd3 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5186,23 +5186,35 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button if (dateTimeQSOOff < m_dateTimeQSOOn) dateTimeQSOOff = m_dateTimeQSOOn; QString grid=m_hisGrid; if(grid=="....") grid=""; - bool bAutoLog=m_config.autoLog() and m_nContest>0; - m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, - m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + ui->TxFreqSpinBox->value(), - m_config.my_callsign(), m_config.my_grid(), m_noSuffix, - m_config.log_as_RTTY(), m_config.report_in_comments(), - m_config.bFox(), bAutoLog, m_opCall); - if(m_nContest!=NONE) { + if(m_nContest>NONE and m_nContestsbSerialNumber->value(); - ui->sbSerialNumber->setValue(n+1); - cabLog(); //Call the Cabrillo contest logger + if(m_nContest==EU_VHF) { + m_rptSent=m_xSent.split(" ").at(0).left(2); + m_rptRcvd=m_xRcvd.split(" ").at(0).left(2); } + if(m_nContest==FIELD_DAY) { + m_rptSent=m_xSent.split(" ").at(0); + m_rptRcvd=m_xRcvd.split(" ").at(0); + } + if(m_nContest==RTTY) { + m_rptSent=m_xSent.split(" ").at(0); + m_rptRcvd=m_xRcvd.split(" ").at(0); + } + int n=ui->sbSerialNumber->value(); + ui->sbSerialNumber->setValue(n+1); + cabLog(); //Call the Cabrillo contest logger } + + bool bAutoLog=m_config.autoLog() and m_nContest>0; + m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, + m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + + ui->TxFreqSpinBox->value(), m_config.my_callsign(), + m_config.my_grid(), m_noSuffix, m_config.log_as_RTTY(), + m_config.report_in_comments(), m_config.bFox(), + bAutoLog, m_opCall, m_nContest, m_xSent, m_xRcvd); } void MainWindow::cabLog() diff --git a/messageaveraging.cpp b/messageaveraging.cpp index 496249ae3..bf98fd782 100644 --- a/messageaveraging.cpp +++ b/messageaveraging.cpp @@ -156,5 +156,4 @@ void MessageAveraging::contestAddLog(qint32 nContest, QString logLine) int score=m_mult_*m_nLogged_; t.sprintf("Score: %d",score); ui->lab3->setText(t); - qDebug() << m_nLogged_ << m_mult_ << score; } From ed8f676b1664e34edbddc330c85530c2c8f14a20 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Tue, 2 Oct 2018 16:20:22 -0500 Subject: [PATCH 23/52] First cut at AP decoding for all values of ncontest. --- lib/ft8/ft8b_2.f90 | 73 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/lib/ft8/ft8b_2.f90 b/lib/ft8/ft8b_2.f90 index f0eac8b4d..aa484f030 100644 --- a/lib/ft8/ft8b_2.f90 +++ b/lib/ft8/ft8b_2.f90 @@ -23,7 +23,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & real dd0(15*12000) integer*1 message77(77),apmask(174),cw(174) integer apsym(58) - integer mcq(29),mcqru(29),mrrr(19),m73(19),mrr73(19) + integer mcq(29),mcqru(29),mcqfd(29),mrrr(19),m73(19),mrr73(19) integer itone(NN) integer icos7(0:6),ip(1) integer nappasses(0:5) !Number of decoding passes to use for each QSO state @@ -40,6 +40,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & data icos7/3,1,4,0,6,5,2/ ! Flipped w.r.t. original FT8 sync array data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ data mcqru/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0/ + data mcqfd/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0/ data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/ @@ -70,12 +71,12 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & ! 5 MyCall DxCall 73 (77 ap bits) ! 6 MyCall DxCall RR73 (77 ap bits) - naptypes(0,1:4)=(/1,2,0,0/) - naptypes(1,1:4)=(/2,3,0,0/) - naptypes(2,1:4)=(/2,3,0,0/) - naptypes(3,1:4)=(/3,4,5,6/) - naptypes(4,1:4)=(/3,4,5,6/) - naptypes(5,1:4)=(/3,1,2,0/) + naptypes(0,1:4)=(/1,2,0,0/) ! Tx6 selected (CQ) + naptypes(1,1:4)=(/2,3,0,0/) ! Tx1 + naptypes(2,1:4)=(/2,3,0,0/) ! Tx2 + naptypes(3,1:4)=(/3,4,5,6/) ! Tx3 + naptypes(4,1:4)=(/3,4,5,6/) ! Tx4 + naptypes(5,1:4)=(/3,1,2,0/) ! Tx5 one=.false. do i=0,511 @@ -242,7 +243,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & ! 6 ap pass 3 ! 7 ap pass 4 - if(lapon.and.(ncontest.eq.0.or.ncontest.eq.4)) then + if(lapon) then if(.not.lapcqonly) then npasses=3+nappasses(nQSOProgress) else @@ -273,10 +274,23 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & if(iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle apsym=2*apsym-1 +! ncontest=0 : NONE +! 1 : NA_VHF +! 2 : EU_VHF +! 3 : FIELD DAY +! 4 : RTTY +! 5 : FOX +! 6 : HOUND + + if(iaptype.eq.1.and.ncontest.eq.5) cycle + if(iaptype.eq.1) then ! CQ,???,??? or CQ RU,???,??? apmask=0 apmask(1:29)=1 - if( ncontest.eq.0) llrd(1:29)=apmag*mcq(1:29) + if( ncontest.eq.0.or.ncontest.eq.1 & + .or.ncontest.eq.2.or.ncontest.eq.6 ) & + llrd(1:29)=apmag*mcq(1:29) + if( ncontest.eq.3) llrd(1:29)=apmag*mcqfd(1:29) if( ncontest.eq.4) llrd(1:29)=apmag*mcqru(1:29) apmask(75:77)=1 llrd(75:76)=apmag*(-1) @@ -285,12 +299,17 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & if(iaptype.eq.2) then ! MyCall,???,??? apmask=0 - if(ncontest.eq.0) then + if(ncontest.ge.0.and.ncontest.le.2.or.ncontest.ge.5) then apmask(1:29)=1 llrd(1:29)=apmag*apsym(1:29) apmask(75:77)=1 llrd(75:76)=apmag*(-1) llrd(77)=apmag*(+1) + else if(ncontest.eq.3) then + apmask(1:28)=1 + llrd(1:28)=apmag*apsym(2:29) + apmask(75:77)=1 + llrd(75:77)=apmag*(-1) else if(ncontest.eq.4) then apmask(2:29)=1 llrd(2:29)=apmag*apsym(1:28) @@ -302,13 +321,19 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & if(iaptype.eq.3) then ! MyCall,DxCall,??? apmask=0 - if(ncontest.eq.0) then + if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2) then apmask(1:58)=1 llrd(1:58)=apmag*apsym apmask(75:77)=1 llrd(75:76)=apmag*(-1) llrd(77)=apmag*(+1) - else if(ncontest.eq.4) then + else if(ncontest.eq.3) then ! Field Day + apmask(1:56)=1 + llrd(1:28)=apmag*apsym(1:28) + llrd(29:56)=apmag*apsym(30:57) + apmask(75:77)=1 + llrd(75:77)=apmag*(-1) + else if(ncontest.eq.4) then ! RTTY RU apmask(2:57)=1 llrd(2:29)=apmag*apsym(1:28) llrd(30:57)=apmag*apsym(30:57) @@ -317,14 +342,26 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & llrd(76:77)=apmag*(+1) endif endif + + if(iaptype.ge.4.and.ncontest.eq.5) cycle !Fox doesn't care + if(iaptype.ge.5.and.ncontest.eq.6) cycle !Hound if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then apmask=0 - apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73 - llrd(1:58)=apmag*apsym - if(iaptype.eq.4) llrd(59:77)=apmag*mrrr - if(iaptype.eq.5) llrd(59:77)=apmag*m73 - if(iaptype.eq.6) llrd(59:77)=apmag*mrr73 + if(ncontest.le.4) then + apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73 + llrd(1:58)=apmag*apsym + if(iaptype.eq.4) llrd(59:77)=apmag*mrrr + if(iaptype.eq.5) llrd(59:77)=apmag*m73 + if(iaptype.eq.6) llrd(59:77)=apmag*mrr73 + else if(ncontest.eq.6) then ! Hound listens for MyCall RR73;... + apmask(1:28)=1 + llrd(1:28)=apmag*apsym(1:28) + apmask(72:77)=1 + llrd(72)=apmag*(-1) + llrd(73:74)=apmag*(1) + llrd(75:77)=apmag*(-1) + endif endif endif @@ -339,7 +376,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & if(abs(nfqso-f1).le.napwid .or. abs(nftx-f1).le.napwid) then if((ipass.eq.3 .or. ipass.eq.4) .and. .not.nagain) then ndeep=3 - else + else ndeep=4 endif endif From 1e5c416cc34b2545936a51c62e6d559d9ebd0175 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 3 Oct 2018 16:25:36 -0400 Subject: [PATCH 24/52] Implementing ExportCabrillo. Some work still to do. --- CMakeLists.txt | 2 + ExportCabrillo.cpp | 44 +++++++ ExportCabrillo.h | 29 +++++ ExportCabrillo.ui | 304 +++++++++++++++++++++++++++++++++++++++++++++ mainwindow.cpp | 10 ++ mainwindow.h | 3 + mainwindow.ui | 7 ++ wsjtx.pro | 7 +- 8 files changed, 402 insertions(+), 4 deletions(-) create mode 100644 ExportCabrillo.cpp create mode 100644 ExportCabrillo.h create mode 100644 ExportCabrillo.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index b5e872521..d8d191716 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,6 +309,7 @@ set (wsjtx_CXXSRCS main.cpp wsprnet.cpp WSPRBandHopping.cpp + ExportCabrillo.cpp ) set (wsjt_CXXSRCS @@ -648,6 +649,7 @@ set (wsjtx_UISRCS widegraph.ui logqso.ui Configuration.ui + ExportCabrillo.ui ) set (UDP_library_CXXSRCS diff --git a/ExportCabrillo.cpp b/ExportCabrillo.cpp new file mode 100644 index 000000000..9142e68ad --- /dev/null +++ b/ExportCabrillo.cpp @@ -0,0 +1,44 @@ +#include "ExportCabrillo.h" +#include "ui_exportCabrillo.h" +#include "SettingsGroup.hpp" + +#include +#include +#include + +ExportCabrillo::ExportCabrillo(QSettings *settings, QWidget *parent) : + QDialog(parent), + settings_ {settings}, + ui(new Ui::ExportCabrillo) +{ + ui->setupUi(this); + read_settings(); + setWindowTitle(QApplication::applicationName() + " - Export Cabrillo"); +} + +ExportCabrillo::~ExportCabrillo() +{ + if (isVisible ()) write_settings(); + delete ui; +} + +void ExportCabrillo::read_settings () +{ + SettingsGroup group {settings_, "ExportCabrillo"}; + restoreGeometry (settings_->value ("window/geometry").toByteArray ()); +} + +void ExportCabrillo::write_settings () +{ + SettingsGroup group {settings_, "ExportCabrillo"}; + settings_->setValue ("window/geometry", saveGeometry ()); +} + +void ExportCabrillo::on_pbSaveAs_clicked() +{ + QString fname; + QFileDialog saveAs(this); + saveAs.setFileMode(QFileDialog::AnyFile); + fname=saveAs.getSaveFileName(this, "Save File", "","Cabrillo Log (*.log)"); + qDebug() << "AA" << fname; +} diff --git a/ExportCabrillo.h b/ExportCabrillo.h new file mode 100644 index 000000000..1770e48d0 --- /dev/null +++ b/ExportCabrillo.h @@ -0,0 +1,29 @@ +#ifndef EXPORTCABRILLO_H +#define EXPORTCABRILLO_H + +#include +#include + +namespace Ui { +class ExportCabrillo; +} + +class ExportCabrillo : public QDialog +{ + Q_OBJECT + +public: + explicit ExportCabrillo(QSettings *settings, QWidget *parent = 0); + ~ExportCabrillo(); + +private slots: + void on_pbSaveAs_clicked(); + +private: + QSettings * settings_; + void read_settings(); + void write_settings(); + Ui::ExportCabrillo *ui; +}; + +#endif // EXPORTCABRILLO_H diff --git a/ExportCabrillo.ui b/ExportCabrillo.ui new file mode 100644 index 000000000..3b3f49b3b --- /dev/null +++ b/ExportCabrillo.ui @@ -0,0 +1,304 @@ + + + ExportCabrillo + + + + 0 + 0 + 330 + 407 + + + + Dialog + + + + + + + + Location: + + + + + + + SNJ + + + Qt::AlignCenter + + + + + + + Contest: + + + + + + + ARRL-RTTY + + + Qt::AlignCenter + + + + + + + Callsign: + + + + + + + + + + Qt::AlignCenter + + + + + + + Category-Operator: + + + + + + + SINGLE-OP + + + Qt::AlignCenter + + + + + + + Category-Transmitter: + + + + + + + ONE + + + Qt::AlignCenter + + + + + + + Category-Power: + + + + + + + LOW + + + Qt::AlignCenter + + + + + + + Category-Assisted: + + + + + + + NON-ASSISTED + + + Qt::AlignCenter + + + + + + + Category-Band: + + + + + + + ALL + + + Qt::AlignCenter + + + + + + + Claimed-Score: + + + + + + + + + + Qt::AlignCenter + + + + + + + Operators: + + + + + + + + + + Qt::AlignCenter + + + + + + + Club: + + + + + + + Qt::AlignCenter + + + + + + + Name: + + + + + + + + + + Qt::AlignCenter + + + + + + + Address: + + + + + + + Qt::AlignCenter + + + + + + + Address: + + + + + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Save As + + + + + + + + + buttonBox + accepted() + ExportCabrillo + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ExportCabrillo + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index 22cefdfd3..edb92cd57 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5990,6 +5990,16 @@ void MainWindow::on_actionErase_cabrillo_log_triggered() } } +void MainWindow::on_actionExport_Cabrillo_log_triggered() +{ + if(!m_exportCabrillo) { + m_exportCabrillo.reset(new ExportCabrillo{m_settings}); + } + bool ret=m_exportCabrillo->exec(); + qDebug() << "aa" << ret; +} + + void MainWindow::on_actionErase_wsjtx_log_adi_triggered() { int ret = MessageBox::query_message (this, tr ("Confirm Erase"), diff --git a/mainwindow.h b/mainwindow.h index 607c832bd..1413b8a89 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -36,6 +36,7 @@ #include "astro.h" #include "MessageBox.hpp" #include "NetworkAccessManager.hpp" +#include "exportCabrillo.h" #define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync #define NUM_JT65_SYMBOLS 126 //63 data + 63 sync @@ -202,6 +203,7 @@ private slots: void on_actionErase_FoxQSO_txt_triggered(); void on_actionErase_cabrillo_log_triggered(); void on_actionErase_wsjtx_log_adi_triggered(); + void on_actionExport_Cabrillo_log_triggered(); void startTx2(); void startP1(); void stopTx(); @@ -359,6 +361,7 @@ private: QScopedPointer m_mouseCmnds; QScopedPointer m_msgAvgWidget; QScopedPointer m_colorHighlighting; + QScopedPointer m_exportCabrillo; Transceiver::TransceiverState m_rigState; Frequency m_lastDialFreq; QString m_lastBand; diff --git a/mainwindow.ui b/mainwindow.ui index b93653962..76bafeb0c 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -2625,6 +2625,8 @@ QPushButton[state="ok"] { + + @@ -3309,6 +3311,11 @@ QPushButton[state="ok"] { Contest Log + + + Export Cabrillo log + + diff --git a/wsjtx.pro b/wsjtx.pro index 5c2124af0..a0d267961 100644 --- a/wsjtx.pro +++ b/wsjtx.pro @@ -68,7 +68,7 @@ SOURCES += \ WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\ MultiSettings.cpp PhaseEqualizationDialog.cpp IARURegions.cpp MessageBox.cpp \ EqualizationToolsDialog.cpp CallsignValidator.cpp ExchangeValidator.cpp \ - colorhighlighting.cpp + colorhighlighting.cpp ExportCabrillo.cpp HEADERS += qt_helpers.hpp \ pimpl_h.hpp pimpl_impl.hpp \ @@ -85,7 +85,7 @@ HEADERS += qt_helpers.hpp \ messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \ WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp \ IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp CallsignValidator.hpp \ - ExchangeValidator.hpp colorhighlighting.h + ExchangeValidator.hpp colorhighlighting.h ExportCabrillo.h INCLUDEPATH += qmake_only @@ -97,8 +97,7 @@ HEADERS += OmniRigTransceiver.hpp FORMS += mainwindow.ui about.ui Configuration.ui widegraph.ui astro.ui \ logqso.ui wf_palette_design_dialog.ui messageaveraging.ui echograph.ui \ - fastgraph.ui \ - colorhighlighting.ui + fastgraph.ui colorhighlighting.ui ExportCabrillo.ui RC_FILE = wsjtx.rc RESOURCES = wsjtx.qrc From 7462a1dc657e01173adc7a66c67eb4bc67a34a23 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Thu, 4 Oct 2018 16:40:45 -0500 Subject: [PATCH 25/52] Implement AP for all contest modes and also for Hound mode. AP is always active for Hounds. AP is automatically disabled if MyCall or DxCall are extended callsigns. --- lib/ft8/ft8b_2.f90 | 85 +++++++++++++++++++++++++++++----------------- lib/ft8_decode.f90 | 3 -- 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/lib/ft8/ft8b_2.f90 b/lib/ft8/ft8b_2.f90 index aa484f030..c40ec7e01 100644 --- a/lib/ft8/ft8b_2.f90 +++ b/lib/ft8/ft8b_2.f90 @@ -23,7 +23,8 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & real dd0(15*12000) integer*1 message77(77),apmask(174),cw(174) integer apsym(58) - integer mcq(29),mcqru(29),mcqfd(29),mrrr(19),m73(19),mrr73(19) + integer mcq(29),mcqru(29),mcqfd(29),mcqtest(29),mcqhund(29) + integer mrrr(19),m73(19),mrr73(19) integer itone(NN) integer icos7(0:6),ip(1) integer nappasses(0:5) !Number of decoding passes to use for each QSO state @@ -38,12 +39,14 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & complex cs(0:7,NN) logical first,newdat,lsubtract,lapon,lapcqonly,nagain,unpk77_success data icos7/3,1,4,0,6,5,2/ ! Flipped w.r.t. original FT8 sync array - data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ - data mcqru/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0/ - data mcqfd/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0/ - data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ - data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ - data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/ + data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ + data mcqru/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0/ + data mcqfd/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0/ + data mcqtest/0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0/ + data mcqhund/0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,1,1,0,0/ + data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ + data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ + data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/ data first/.true./ data graymap/0,1,3,2,5,6,4,7/ save nappasses,naptypes,ncontest0,one,hiscall12_0 @@ -51,7 +54,10 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & if(first.or.(ncontest.ne.ncontest0)) then mcq=2*mcq-1 + mcqfd=2*mcqfd-1 mcqru=2*mcqru-1 + mcqtest=2*mcqtest-1 + mcqhund=2*mcqhund-1 mrrr=2*mrrr-1 m73=2*m73-1 mrr73=2*mrr73-1 @@ -243,7 +249,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & ! 6 ap pass 3 ! 7 ap pass 4 - if(lapon) then + if(lapon.or.ncontest.eq.6) then !Hounds always use AP if(.not.lapcqonly) then npasses=3+nappasses(nQSOProgress) else @@ -269,10 +275,6 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & else iaptype=1 endif - if(iaptype.ge.2 .and. apsym(1).gt.1) cycle ! no mycall was entered - if(iaptype.ge.3 .and. apsym(30).gt.1) cycle ! no, or nonstandard dxcall - if(iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle - apsym=2*apsym-1 ! ncontest=0 : NONE ! 1 : NA_VHF @@ -281,17 +283,24 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & ! 4 : RTTY ! 5 : FOX ! 6 : HOUND +! +! Conditions that cause us to bail out of AP decoding + if(ncontest.le.4 .and. iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle + if(ncontest.eq.5) cycle ! No AP for Foxes + if(ncontest.eq.6.and.f1.gt.950.0) cycle ! Hounds use AP only for signals below 950 Hz + if(iaptype.ge.2 .and. apsym(1).gt.1) cycle ! No, or nonstandard, mycall + if(iaptype.ge.3 .and. apsym(30).gt.1) cycle ! No, or nonstandard, dxcall + apsym=2*apsym-1 ! Change from [0,1] to antipodal - if(iaptype.eq.1.and.ncontest.eq.5) cycle - - if(iaptype.eq.1) then ! CQ,???,??? or CQ RU,???,??? + if(iaptype.eq.1) then ! CQ or CQ RU or CQ TEST or CQ FD apmask=0 apmask(1:29)=1 - if( ncontest.eq.0.or.ncontest.eq.1 & - .or.ncontest.eq.2.or.ncontest.eq.6 ) & - llrd(1:29)=apmag*mcq(1:29) - if( ncontest.eq.3) llrd(1:29)=apmag*mcqfd(1:29) - if( ncontest.eq.4) llrd(1:29)=apmag*mcqru(1:29) + if(ncontest.eq.0) llrd(1:29)=apmag*mcq(1:29) + if(ncontest.eq.1) llrd(1:29)=apmag*mcqtest(1:29) + if(ncontest.eq.2) llrd(1:29)=apmag*mcqtest(1:29) + if(ncontest.eq.3) llrd(1:29)=apmag*mcqfd(1:29) + if(ncontest.eq.4) llrd(1:29)=apmag*mcqru(1:29) + if(ncontest.eq.6) llrd(1:29)=apmag*mcqhund(1:29) apmask(75:77)=1 llrd(75:76)=apmag*(-1) llrd(77)=apmag*(+1) @@ -299,15 +308,24 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & if(iaptype.eq.2) then ! MyCall,???,??? apmask=0 - if(ncontest.ge.0.and.ncontest.le.2.or.ncontest.ge.5) then + if(ncontest.eq.0.or.ncontest.eq.1) then apmask(1:29)=1 llrd(1:29)=apmag*apsym(1:29) apmask(75:77)=1 llrd(75:76)=apmag*(-1) llrd(77)=apmag*(+1) + else if(ncontest.eq.2) then + apmask(1:28)=1 + llrd(1:28)=apmag*apsym(1:28) + apmask(72:74)=1 + llrd(72)=apmag*(-1) + llrd(73)=apmag*(+1) + llrd(74)=apmag*(-1) + apmask(75:77)=1 + llrd(75:77)=apmag*(-1) else if(ncontest.eq.3) then apmask(1:28)=1 - llrd(1:28)=apmag*apsym(2:29) + llrd(1:28)=apmag*apsym(1:28) apmask(75:77)=1 llrd(75:77)=apmag*(-1) else if(ncontest.eq.4) then @@ -316,12 +334,19 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & apmask(75:77)=1 llrd(75)=apmag*(-1) llrd(76:77)=apmag*(+1) + else if(ncontest.eq.6) then ! ??? RR73; MyCall ??? + apmask(29:56)=1 + llrd(29:56)=apmag*apsym(1:28) + apmask(72:77)=1 + llrd(72:73)=apmag*(-1) + llrd(74)=apmag*(+1) + llrd(75:77)=apmag*(-1) endif endif if(iaptype.eq.3) then ! MyCall,DxCall,??? apmask=0 - if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2) then + if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2.or.ncontest.eq.6) then apmask(1:58)=1 llrd(1:58)=apmag*apsym apmask(75:77)=1 @@ -331,6 +356,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & apmask(1:56)=1 llrd(1:28)=apmag*apsym(1:28) llrd(29:56)=apmag*apsym(30:57) + apmask(72:74)=1 apmask(75:77)=1 llrd(75:77)=apmag*(-1) else if(ncontest.eq.4) then ! RTTY RU @@ -342,24 +368,22 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & llrd(76:77)=apmag*(+1) endif endif - - if(iaptype.ge.4.and.ncontest.eq.5) cycle !Fox doesn't care - if(iaptype.ge.5.and.ncontest.eq.6) cycle !Hound + if(iaptype.eq.5.and.ncontest.eq.6) cycle !Hound if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then apmask=0 - if(ncontest.le.4) then + if(ncontest.le.4 .or. (ncontest.eq.6.and.iaptype.eq.6)) then apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73 llrd(1:58)=apmag*apsym if(iaptype.eq.4) llrd(59:77)=apmag*mrrr if(iaptype.eq.5) llrd(59:77)=apmag*m73 if(iaptype.eq.6) llrd(59:77)=apmag*mrr73 - else if(ncontest.eq.6) then ! Hound listens for MyCall RR73;... + else if(ncontest.eq.6.and.iaptype.eq.4) then ! Hound listens for MyCall RR73;... apmask(1:28)=1 llrd(1:28)=apmag*apsym(1:28) apmask(72:77)=1 - llrd(72)=apmag*(-1) - llrd(73:74)=apmag*(1) + llrd(72:73)=apmag*(-1) + llrd(74)=apmag*(1) llrd(75:77)=apmag*(-1) endif endif @@ -417,7 +441,6 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & if(arg.gt.0.1) xsnr2=arg xsnr=10.0*log10(xsnr)-27.0 xsnr2=10.0*log10(xsnr2)-27.0 -!write(87,'(f10.1,2x,f10.1)') xsnr,xsnr2 if(.not.nagain) then xsnr=xsnr2 endif diff --git a/lib/ft8_decode.f90 b/lib/ft8_decode.f90 index 2b34aa617..2e6f36464 100644 --- a/lib/ft8_decode.f90 +++ b/lib/ft8_decode.f90 @@ -131,9 +131,6 @@ contains hd=nharderrors+dmin call timer('ft8b ',1) if(nbadcrc.eq.0) then -! call jtmsg(message,iflag) -! This probably needs to be re-visited for the new message type -! if(iand(iflag,31).ne.0) message(22:22)='?' ldupe=.false. do id=1,ndecodes if(msg37.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true. From a87f3d3a2732727cd47ec0a2e9ff13aedf80afdb Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Tue, 13 Nov 2018 18:55:46 +0000 Subject: [PATCH 26/52] Bump RC number to 5 --- Versions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Versions.cmake b/Versions.cmake index c21a34d08..3ba5db895 100644 --- a/Versions.cmake +++ b/Versions.cmake @@ -2,5 +2,5 @@ set (WSJTX_VERSION_MAJOR 2) set (WSJTX_VERSION_MINOR 0) set (WSJTX_VERSION_PATCH 0) -set (WSJTX_RC 4) # release candidate number, comment out or zero for development versions +set (WSJTX_RC 5) # release candidate number, comment out or zero for development versions set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build From dd9da021dde283714c55b1c413191391d1c47357 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Wed, 14 Nov 2018 03:03:12 +0000 Subject: [PATCH 27/52] Fix badly broken worked before database indexing --- logbook/WorkedBefore.cpp | 204 ++++++++++++++++++++++++++------------- qt_helpers.hpp | 21 ++++ 2 files changed, 157 insertions(+), 68 deletions(-) diff --git a/logbook/WorkedBefore.cpp b/logbook/WorkedBefore.cpp index b6cd9eca8..41723e003 100644 --- a/logbook/WorkedBefore.cpp +++ b/logbook/WorkedBefore.cpp @@ -1,18 +1,34 @@ #include "WorkedBefore.hpp" +#include +#include #include +#include #include #include +#include +#include #include #include #include #include #include +#include +#include "qt_helpers.hpp" #include "pimpl_impl.hpp" using namespace boost::multi_index; +// hash function for QString members in hashed indexes +inline +std::size_t hash_value (QString const& s) +{ + return std::hash {} (s); +} + +// // worked before set element +// struct worked_entry { explicit worked_entry (QString const& call, QString const& grid, QString const& band @@ -39,7 +55,52 @@ struct worked_entry int ITU_zone_; }; -// less then predidate for the Continent enum class +bool operator == (worked_entry const& lhs, worked_entry const& rhs) +{ + return + lhs.continent_ == rhs.continent_ // check 1st as it is fast + && lhs.CQ_zone_ == rhs.CQ_zone_ // ditto + && lhs.ITU_zone_ == rhs.ITU_zone_ // ditto + && lhs.call_ == rhs.call_ // check the rest in decreasing + && lhs.grid_ == rhs.grid_ // domain size order to shortcut + && lhs.country_ == rhs.country_ // differences as quickly as possible + && lhs.band_ == rhs.band_ + && lhs.mode_ == rhs.mode_; +} + +std::size_t hash_value (worked_entry const& we) +{ + std::size_t seed {0}; + boost::hash_combine (seed, we.call_); + boost::hash_combine (seed, we.grid_); + boost::hash_combine (seed, we.band_); + boost::hash_combine (seed, we.mode_); + boost::hash_combine (seed, we.country_); + boost::hash_combine (seed, we.continent_); + boost::hash_combine (seed, we.CQ_zone_); + boost::hash_combine (seed, we.ITU_zone_); + return seed; +} + +#if !defined (QT_NO_DEBUG_STREAM) +QDebug operator << (QDebug dbg, worked_entry const& e) +{ + QDebugStateSaver saver {dbg}; + dbg.nospace () << "worked_entry(" + << e.call_ << ", " + << e.grid_ << ", " + << e.band_ << ", " + << e.mode_ << ", " + << e.country_ << ", " + << e.continent_ << ", " + << e.CQ_zone_ << ", " + << e.ITU_zone_ << ')'; + return dbg; +} +#endif + +// less then predidate for the Continent enum class, needed for +// ordered indexes struct Continent_less { bool operator () (AD1CCty::Continent lhs, AD1CCty::Continent rhs) const @@ -48,7 +109,7 @@ struct Continent_less } }; -// tags +// index tags struct call_mode_band {}; struct call_band {}; struct grid_mode_band {}; @@ -62,85 +123,92 @@ struct CQ_zone_band {}; struct ITU_zone_mode_band {}; struct ITU_zone_band {}; -// set with multiple ordered unique indexes that allow for efficient -// determination of various categories of worked before status +// set with multiple ordered unique indexes that allow for optimally +// efficient determination of various categories of worked before +// status typedef multi_index_container< worked_entry, indexed_by< + // basic unordered set constraint - we don't need duplicate worked entries + hashed_unique>, + + // + // The following indexes are used to discover worked before stuff. + // + // They are ordered so as to support partial lookups and + // non-unique because container inserts must be valid for all + // indexes. + // + // call+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // call+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // grid+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // grid+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // country+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // country+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // continent+mode+band - ordered_unique, - composite_key, - member, - member >, - composite_key_compare< - Continent_less, - std::less, - std::less > >, + ordered_non_unique, + composite_key, + member, + member >, + composite_key_compare, std::less > >, // continent+band - ordered_unique, - composite_key, - member >, - composite_key_compare< - Continent_less, - std::less > >, + ordered_non_unique, + composite_key, + member >, + composite_key_compare > >, // CQ-zone+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // CQ-zone+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // ITU-zone+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // ITU-zone+band - ordered_unique, - composite_key, - member > > > - > worked_type; + ordered_non_unique, + composite_key, + member > > > + > worked_before_database_type; namespace { @@ -188,7 +256,7 @@ public: QString path_; AD1CCty prefixes_; - worked_type worked_; + worked_before_database_type worked_; }; WorkedBefore::WorkedBefore () @@ -196,7 +264,7 @@ WorkedBefore::WorkedBefore () QFile inputFile {m_->path_}; if (inputFile.open (QFile::ReadOnly)) { - QTextStream in(&inputFile); + QTextStream in {&inputFile}; QString buffer; bool pre_read {false}; int end_position {-1}; diff --git a/qt_helpers.hpp b/qt_helpers.hpp index 0e9439a8a..b2ec7a49f 100644 --- a/qt_helpers.hpp +++ b/qt_helpers.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -77,6 +78,26 @@ public: } }; +namespace std +{ + // std::hash<> specialization for QString based on the dbj2 + // algorithm http://www.cse.yorku.ca/~oz/hash.html because qHash() + // is poor on 64-bit platforms due to being a 32-bit hash value + template<> + struct hash + { + std::size_t operator () (QString const& s) const noexcept + { + std::size_t hash {5381}; + for (int i = 0; i < s.size (); ++i) + { + hash = ((hash << 5) + hash) + ((s.at (i).row () << 8) | s.at (i).cell ()); + } + return hash; + } + }; +} + // Register some useful Qt types with QMetaType Q_DECLARE_METATYPE (QHostAddress); From 982b76da54fc266feca90938d406cfb07bfeba8a Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Wed, 14 Nov 2018 03:35:36 +0000 Subject: [PATCH 28/52] Update Linux packaging dependencies Notably setting the Qt minimum version to 5.5 and adding the Debian libqt5sql5-sqlite package dependency. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c684ab4aa..39411f8a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1708,11 +1708,11 @@ endif () set (CPACK_DEBIAN_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PROJECT_HOMEPAGE}") -set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.2), libqt5multimedia5-plugins (>=5.2), libqt5widgets5 (>=5.2), libusb-1.0-0, libudev1, libc6 (>=2.19)") +set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.5), libqt5multimedia5-plugins (>=5.5), libqt5widgets5 (>=5.5), libqt5sql5-sqlite (>=5.5), libusb-1.0-0, libudev1, libc6 (>=2.19)") set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set (CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) -set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.2, qt5-qtmultimedia >= 5.2, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2") +set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.5, qt5-qtmultimedia >= 5.5, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2") set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/share/pixmaps /usr/share/applications /usr/share/man /usr/share/man1) configure_file ("${PROJECT_SOURCE_DIR}/CMakeCPackOptions.cmake.in" From b842ab74164d7dc23c4f151ac4f441b16e27185e Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Wed, 14 Nov 2018 07:09:59 -0600 Subject: [PATCH 29/52] Fix a bug that caused many false decodes in JT65 VHF/UHF operation, when AP decoding was enabled. --- lib/sync65.f90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/sync65.f90 b/lib/sync65.f90 index e0bc924a0..4a681a0a7 100644 --- a/lib/sync65.f90 +++ b/lib/sync65.f90 @@ -57,8 +57,9 @@ subroutine sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrobust, & freq=i*df itry=0 ! if(naggressive.gt.0 .and. ntol.lt.1000 .and. ccfmax.ge.thresh0) then - if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then - if(i.ne.ipk) cycle +! if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then + if(bVHF) then + if(i.ne.ipk .or. ccfmax.lt.thresh0) cycle itry=1 ncand=ncand+1 else From 43a5d7b5198acf31c527d3cc43da4264af2cd399 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 14 Nov 2018 10:44:36 -0500 Subject: [PATCH 30/52] Starting branch hotfix-2.0.0-rc5. --- CMakeLists.txt | 4 +- Versions.cmake | 4 +- lib/sync65.f90 | 5 +- logbook/WorkedBefore.cpp | 204 ++++++++++++++++++++++++++------------- qt_helpers.hpp | 21 ++++ 5 files changed, 164 insertions(+), 74 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c684ab4aa..39411f8a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1708,11 +1708,11 @@ endif () set (CPACK_DEBIAN_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PROJECT_HOMEPAGE}") -set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.2), libqt5multimedia5-plugins (>=5.2), libqt5widgets5 (>=5.2), libusb-1.0-0, libudev1, libc6 (>=2.19)") +set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.5), libqt5multimedia5-plugins (>=5.5), libqt5widgets5 (>=5.5), libqt5sql5-sqlite (>=5.5), libusb-1.0-0, libudev1, libc6 (>=2.19)") set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set (CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) -set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.2, qt5-qtmultimedia >= 5.2, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2") +set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.5, qt5-qtmultimedia >= 5.5, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2") set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/share/pixmaps /usr/share/applications /usr/share/man /usr/share/man1) configure_file ("${PROJECT_SOURCE_DIR}/CMakeCPackOptions.cmake.in" diff --git a/Versions.cmake b/Versions.cmake index 6cb4d89c2..3ba5db895 100644 --- a/Versions.cmake +++ b/Versions.cmake @@ -1,6 +1,6 @@ # Version number components set (WSJTX_VERSION_MAJOR 2) set (WSJTX_VERSION_MINOR 0) -set (WSJTX_VERSION_PATCH 1) -#set (WSJTX_RC 1) # release candidate number, comment out or zero for development versions +set (WSJTX_VERSION_PATCH 0) +set (WSJTX_RC 5) # release candidate number, comment out or zero for development versions set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build diff --git a/lib/sync65.f90 b/lib/sync65.f90 index e0bc924a0..4a681a0a7 100644 --- a/lib/sync65.f90 +++ b/lib/sync65.f90 @@ -57,8 +57,9 @@ subroutine sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrobust, & freq=i*df itry=0 ! if(naggressive.gt.0 .and. ntol.lt.1000 .and. ccfmax.ge.thresh0) then - if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then - if(i.ne.ipk) cycle +! if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then + if(bVHF) then + if(i.ne.ipk .or. ccfmax.lt.thresh0) cycle itry=1 ncand=ncand+1 else diff --git a/logbook/WorkedBefore.cpp b/logbook/WorkedBefore.cpp index b6cd9eca8..41723e003 100644 --- a/logbook/WorkedBefore.cpp +++ b/logbook/WorkedBefore.cpp @@ -1,18 +1,34 @@ #include "WorkedBefore.hpp" +#include +#include #include +#include #include #include +#include +#include #include #include #include #include #include +#include +#include "qt_helpers.hpp" #include "pimpl_impl.hpp" using namespace boost::multi_index; +// hash function for QString members in hashed indexes +inline +std::size_t hash_value (QString const& s) +{ + return std::hash {} (s); +} + +// // worked before set element +// struct worked_entry { explicit worked_entry (QString const& call, QString const& grid, QString const& band @@ -39,7 +55,52 @@ struct worked_entry int ITU_zone_; }; -// less then predidate for the Continent enum class +bool operator == (worked_entry const& lhs, worked_entry const& rhs) +{ + return + lhs.continent_ == rhs.continent_ // check 1st as it is fast + && lhs.CQ_zone_ == rhs.CQ_zone_ // ditto + && lhs.ITU_zone_ == rhs.ITU_zone_ // ditto + && lhs.call_ == rhs.call_ // check the rest in decreasing + && lhs.grid_ == rhs.grid_ // domain size order to shortcut + && lhs.country_ == rhs.country_ // differences as quickly as possible + && lhs.band_ == rhs.band_ + && lhs.mode_ == rhs.mode_; +} + +std::size_t hash_value (worked_entry const& we) +{ + std::size_t seed {0}; + boost::hash_combine (seed, we.call_); + boost::hash_combine (seed, we.grid_); + boost::hash_combine (seed, we.band_); + boost::hash_combine (seed, we.mode_); + boost::hash_combine (seed, we.country_); + boost::hash_combine (seed, we.continent_); + boost::hash_combine (seed, we.CQ_zone_); + boost::hash_combine (seed, we.ITU_zone_); + return seed; +} + +#if !defined (QT_NO_DEBUG_STREAM) +QDebug operator << (QDebug dbg, worked_entry const& e) +{ + QDebugStateSaver saver {dbg}; + dbg.nospace () << "worked_entry(" + << e.call_ << ", " + << e.grid_ << ", " + << e.band_ << ", " + << e.mode_ << ", " + << e.country_ << ", " + << e.continent_ << ", " + << e.CQ_zone_ << ", " + << e.ITU_zone_ << ')'; + return dbg; +} +#endif + +// less then predidate for the Continent enum class, needed for +// ordered indexes struct Continent_less { bool operator () (AD1CCty::Continent lhs, AD1CCty::Continent rhs) const @@ -48,7 +109,7 @@ struct Continent_less } }; -// tags +// index tags struct call_mode_band {}; struct call_band {}; struct grid_mode_band {}; @@ -62,85 +123,92 @@ struct CQ_zone_band {}; struct ITU_zone_mode_band {}; struct ITU_zone_band {}; -// set with multiple ordered unique indexes that allow for efficient -// determination of various categories of worked before status +// set with multiple ordered unique indexes that allow for optimally +// efficient determination of various categories of worked before +// status typedef multi_index_container< worked_entry, indexed_by< + // basic unordered set constraint - we don't need duplicate worked entries + hashed_unique>, + + // + // The following indexes are used to discover worked before stuff. + // + // They are ordered so as to support partial lookups and + // non-unique because container inserts must be valid for all + // indexes. + // + // call+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // call+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // grid+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // grid+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // country+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // country+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // continent+mode+band - ordered_unique, - composite_key, - member, - member >, - composite_key_compare< - Continent_less, - std::less, - std::less > >, + ordered_non_unique, + composite_key, + member, + member >, + composite_key_compare, std::less > >, // continent+band - ordered_unique, - composite_key, - member >, - composite_key_compare< - Continent_less, - std::less > >, + ordered_non_unique, + composite_key, + member >, + composite_key_compare > >, // CQ-zone+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // CQ-zone+band - ordered_unique, - composite_key, - member > >, + ordered_non_unique, + composite_key, + member > >, // ITU-zone+mode+band - ordered_unique, - composite_key, - member, - member > >, + ordered_non_unique, + composite_key, + member, + member > >, // ITU-zone+band - ordered_unique, - composite_key, - member > > > - > worked_type; + ordered_non_unique, + composite_key, + member > > > + > worked_before_database_type; namespace { @@ -188,7 +256,7 @@ public: QString path_; AD1CCty prefixes_; - worked_type worked_; + worked_before_database_type worked_; }; WorkedBefore::WorkedBefore () @@ -196,7 +264,7 @@ WorkedBefore::WorkedBefore () QFile inputFile {m_->path_}; if (inputFile.open (QFile::ReadOnly)) { - QTextStream in(&inputFile); + QTextStream in {&inputFile}; QString buffer; bool pre_read {false}; int end_position {-1}; diff --git a/qt_helpers.hpp b/qt_helpers.hpp index 0e9439a8a..b2ec7a49f 100644 --- a/qt_helpers.hpp +++ b/qt_helpers.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -77,6 +78,26 @@ public: } }; +namespace std +{ + // std::hash<> specialization for QString based on the dbj2 + // algorithm http://www.cse.yorku.ca/~oz/hash.html because qHash() + // is poor on 64-bit platforms due to being a 32-bit hash value + template<> + struct hash + { + std::size_t operator () (QString const& s) const noexcept + { + std::size_t hash {5381}; + for (int i = 0; i < s.size (); ++i) + { + hash = ((hash << 5) + hash) + ((s.at (i).row () << 8) | s.at (i).cell ()); + } + return hash; + } + }; +} + // Register some useful Qt types with QMetaType Q_DECLARE_METATYPE (QHostAddress); From dd28dd2670938547f9417afdf77888e15b55623c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 14 Nov 2018 11:33:46 -0500 Subject: [PATCH 31/52] Remove the Mouse Timer. Make the AutoSeq checkbox sticky, again. --- widgets/mainwindow.cpp | 27 +-------------------------- widgets/mainwindow.h | 5 ----- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 19243df09..e7bfc9f7c 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -931,13 +931,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->cbMenus->setChecked(true); ui->cbMenus->setChecked(false); } - - mouseLastPos=QCursor::pos(); - m_mouseIdleSeconds=0; - connect(&mouseTimer, &QTimer::timeout, this, &MainWindow::mouseTimerTick); - mouseTimer.start(1000); - - // this must be the last statement of constructor +// this must be the last statement of constructor if (!m_valid) throw std::runtime_error {"Fatal initialization exception"}; } @@ -962,22 +956,6 @@ void MainWindow::initialize_fonts () setDecodedTextFont (m_config.decoded_text_font ()); } -void MainWindow::mouseTimerTick() -{ - QPoint point = QCursor::pos(); - if(point != mouseLastPos) - m_mouseIdleSeconds = 0; - else - m_mouseIdleSeconds++; - mouseLastPos = point; -//Here we should do what's necessary when mouseIdleSeconds gets too big. -// qDebug() << m_mouseIdleSeconds; - if(ui->cbAutoSeq->isChecked() and m_mouseIdleSeconds>300) { - auto_tx_mode (false); - } -} - - void MainWindow::splash_done () { m_splash && m_splash->close (); @@ -1880,7 +1858,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e) if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) { m_bandEdited = true; band_changed(m_freqNominal-2000); -// qDebug() << "Down" << m_freqNominal; } else { n=11; if(e->modifiers() & Qt::ControlModifier) n+=100; @@ -1895,7 +1872,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e) if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) { m_bandEdited = true; band_changed(m_freqNominal+2000); -// qDebug() << "Up " << m_freqNominal; } else { n=12; if(e->modifiers() & Qt::ControlModifier) n+=100; @@ -5464,7 +5440,6 @@ void MainWindow::displayWidgets(qint64 n) if(i==32) ui->cbCQonly->setVisible(b); j=j>>1; } - if(!ui->cbAutoSeq->isVisible()) ui->cbAutoSeq->setChecked(false); b=SpecOp::EU_VHF==m_config.special_op_id() or (SpecOp::RTTY==m_config.special_op_id() and (m_config.RTTY_Exchange()=="#" or m_config.RTTY_Exchange()=="DX")); ui->sbSerialNumber->setVisible(b); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 2ef380e74..e5b9de9a8 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -446,7 +446,6 @@ private: qint32 m_Nslots=5; qint32 m_nFoxMsgTimes[5]={0,0,0,0,0}; qint32 m_tAutoOn; - qint32 m_mouseIdleSeconds; qint32 m_tFoxTx=0; qint32 m_tFoxTx0=0; qint32 m_maxStrikes=3; //Max # of repeats: 3 strikes and you're out @@ -570,9 +569,6 @@ private: QTimer minuteTimer; QTimer splashTimer; QTimer p1Timer; - QTimer mouseTimer; - - QPoint mouseLastPos; QString m_path; QString m_baseCall; @@ -701,7 +697,6 @@ private: void CQTxFreq(); void useNextCall(); void abortQSO(); - void mouseTimerTick(); bool isWorked(int itype, QString key, float fMHz=0, QString=""); QString save_wave_file (QString const& name From b7b30452b136ff378b102b46ad896d965f27b914 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Thu, 15 Nov 2018 01:28:19 +0000 Subject: [PATCH 32/52] Fix CMake Hamlib package finder on systems that use */lib64 LIBDIRS --- CMake/Modules/Findhamlib.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/Modules/Findhamlib.cmake b/CMake/Modules/Findhamlib.cmake index 1590f051d..7eebf1066 100644 --- a/CMake/Modules/Findhamlib.cmake +++ b/CMake/Modules/Findhamlib.cmake @@ -16,7 +16,7 @@ set (hamlib_LIBRARY_DIRS) # pkg-config? find_path (__hamlib_pc_path NAMES hamlib.pc - PATH_SUFFIXES lib/pkgconfig + PATH_SUFFIXES lib/pkgconfig lib64/pkgconfig ) if (__hamlib_pc_path) set (ENV{PKG_CONFIG_PATH} "${__hamlib_pc_path}" "$ENV{PKG_CONFIG_PATH}") From 44710d13ba5b95fcb3968ad957dd59040d7afc9c Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Thu, 15 Nov 2018 01:31:21 +0000 Subject: [PATCH 33/52] Workaround for a compiler bug on the ancient g++-4.8.5 --- qt_db_helpers.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt_db_helpers.hpp b/qt_db_helpers.hpp index 3f159a889..da823b0cb 100644 --- a/qt_db_helpers.hpp +++ b/qt_db_helpers.hpp @@ -25,7 +25,7 @@ class ConditionalTransaction final { public: explicit ConditionalTransaction (QSqlTableModel& model) - : model_ {model} + : model_ (model) , submitted_ {false} { model_.database ().transaction (); From c3ba6b83b99733693872e497be9678656abcf6d5 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 16 Nov 2018 09:30:40 -0500 Subject: [PATCH 34/52] Add "No own call decodes" checkbox for WSPR mode. --- widgets/mainwindow.cpp | 7 +- widgets/mainwindow.ui | 855 +++++++++++++++++++++-------------------- 2 files changed, 437 insertions(+), 425 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index e7bfc9f7c..186f5f40c 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -1055,6 +1055,7 @@ void MainWindow::writeSettings() m_settings->setValue("RR73",m_send_RR73); m_settings->setValue ("WSPRPreferType1", ui->WSPR_prefer_type_1_check_box->isChecked ()); m_settings->setValue("UploadSpots",m_uploadSpots); + m_settings->setValue("NoOwnCall",ui->cbNoOwnCall->isChecked()); m_settings->setValue ("BandHopping", ui->band_hopping_group_box->isChecked ()); m_settings->setValue ("TRPeriod", ui->sbTR->value ()); m_settings->setValue("FastMode",m_bFastMode); @@ -1146,6 +1147,7 @@ void MainWindow::readSettings() ui->WSPR_prefer_type_1_check_box->setChecked (m_settings->value ("WSPRPreferType1", true).toBool ()); m_uploadSpots=m_settings->value("UploadSpots",false).toBool(); if(!m_uploadSpots) ui->cbUploadWSPR_Spots->setStyleSheet("QCheckBox{background-color: yellow}"); + ui->cbNoOwnCall->setChecked(m_settings->value("NoOwnCall",false).toBool()); ui->band_hopping_group_box->setChecked (m_settings->value ("BandHopping", false).toBool()); // setup initial value of tx attenuator m_block_pwr_tooltip = true; @@ -7241,6 +7243,10 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout QString t1; while(p1.canReadLine()) { QString t(p1.readLine()); + if(ui->cbNoOwnCall->isChecked()) { + if(t.contains(" " + m_config.my_callsign() + " ")) continue; + if(t.contains(" <" + m_config.my_callsign() + "> ")) continue; + } if(t.indexOf("") >= 0) { m_bDecoded = m_nWSPRdecodes > 0; if(!m_diskData) { @@ -7366,7 +7372,6 @@ void MainWindow::WSPR_history(Frequency dialFreq, int ndecodes) } } - void MainWindow::uploadSpots() { // do not spot replays or if rig control not working diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index fe9aa30bc..ee0342cdc 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -573,6 +573,430 @@ QLabel[oob="true"] { + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + <html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html> + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + 252 + 252 + 252 + + + + + + + 159 + 175 + 213 + + + + + + + + + 252 + 252 + 252 + + + + + + + 159 + 175 + 213 + + + + + + + + + 159 + 175 + 213 + + + + + + + 159 + 175 + 213 + + + + + + + + true + + + DX Call + + + Qt::AlignCenter + + + 5 + + + 2 + + + + + + + + 0 + 0 + + + + + + + + + 252 + 252 + 252 + + + + + + + 159 + 175 + 213 + + + + + + + + + 252 + 252 + 252 + + + + + + + 159 + 175 + 213 + + + + + + + + + 159 + 175 + 213 + + + + + + + 159 + 175 + 213 + + + + + + + + true + + + DX Grid + + + Qt::AlignCenter + + + 5 + + + 2 + + + + + + + Callsign of station to be worked + + + + + + Qt::AlignCenter + + + + + + + Search for callsign in database + + + &Lookup + + + + + + + Locator of station to be worked + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + true + + + Az: 251 16553 km + + + Qt::AlignCenter + + + 4 + + + + + + + Add callsign and locator to database + + + Add + + + + + + + + + + Pwr + + + + + + + false + + + <html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode.</p></body></html> + + + QPushButton { + font-family: helvetica; + font-size: 9pt; + font-weight: bold; + background-color: white; + color: black; + border-style: solid; + border-width:1px; + border-radius:10px; + border-color: gray; + max-width:20px; + max-height:20px; + min-width:20px; + min-height:20px; +} +QPushButton[state="error"] { + background-color: red; +} +QPushButton[state="warning"] { + background-color: orange; +} +QPushButton[state="ok"] { + background-color: #00ff00; +} + + + ? + + + + + + + Adjust Tx audio level + + + 450 + + + 0 + + + Qt::Vertical + + + true + + + true + + + QSlider::TicksBelow + + + 50 + + + + + + + <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html> + + + true + + + QComboBox::NoInsert + + + QComboBox::AdjustToMinimumContentsLength + + + + + + + + 0 + 0 + + + + QLabel { + font-family: MS Shell Dlg 2; + font-size: 16pt; + background-color : black; + color : yellow; +} + + + QFrame::StyledPanel + + + QFrame::Sunken + + + 2 + + + 0 + + + <html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html> + + + Qt::AlignCenter + + + 5 + + + @@ -2105,6 +2529,13 @@ list. The list can be maintained in Settings (F2). + + + + No own call decodes + + + @@ -2199,430 +2630,6 @@ list. The list can be maintained in Settings (F2). - - - - - 0 - 0 - - - - - 100 - 16777215 - - - - <html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html> - - - QFrame::Panel - - - QFrame::Sunken - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - - - - - 252 - 252 - 252 - - - - - - - 159 - 175 - 213 - - - - - - - - - 252 - 252 - 252 - - - - - - - 159 - 175 - 213 - - - - - - - - - 159 - 175 - 213 - - - - - - - 159 - 175 - 213 - - - - - - - - true - - - DX Call - - - Qt::AlignCenter - - - 5 - - - 2 - - - - - - - - 0 - 0 - - - - - - - - - 252 - 252 - 252 - - - - - - - 159 - 175 - 213 - - - - - - - - - 252 - 252 - 252 - - - - - - - 159 - 175 - 213 - - - - - - - - - 159 - 175 - 213 - - - - - - - 159 - 175 - 213 - - - - - - - - true - - - DX Grid - - - Qt::AlignCenter - - - 5 - - - 2 - - - - - - - Callsign of station to be worked - - - - - - Qt::AlignCenter - - - - - - - Locator of station to be worked - - - - - - Qt::AlignCenter - - - - - - - Search for callsign in database - - - &Lookup - - - - - - - Add callsign and locator to database - - - Add - - - - - - - - 0 - 0 - - - - true - - - Az: 251 16553 km - - - Qt::AlignCenter - - - 4 - - - - - - - - - - Pwr - - - - - - - false - - - <html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode.</p></body></html> - - - QPushButton { - font-family: helvetica; - font-size: 9pt; - font-weight: bold; - background-color: white; - color: black; - border-style: solid; - border-width:1px; - border-radius:10px; - border-color: gray; - max-width:20px; - max-height:20px; - min-width:20px; - min-height:20px; -} -QPushButton[state="error"] { - background-color: red; -} -QPushButton[state="warning"] { - background-color: orange; -} -QPushButton[state="ok"] { - background-color: #00ff00; -} - - - ? - - - - - - - Adjust Tx audio level - - - 450 - - - 0 - - - Qt::Vertical - - - true - - - true - - - QSlider::TicksBelow - - - 50 - - - - - - - <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html> - - - true - - - QComboBox::NoInsert - - - QComboBox::AdjustToMinimumContentsLength - - - - - - - - 0 - 0 - - - - QLabel { - font-family: MS Shell Dlg 2; - font-size: 16pt; - background-color : black; - color : yellow; -} - - - QFrame::StyledPanel - - - QFrame::Sunken - - - 2 - - - 0 - - - <html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html> - - - Qt::AlignCenter - - - 5 - - - From c4d4097bb3da11f425c7d0e04a66a57823e49813 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Sat, 17 Nov 2018 07:19:08 -0600 Subject: [PATCH 35/52] Tweak a tooltip to remove reference to type 2 callsigns. --- widgets/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index ee0342cdc..8256eb606 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -1269,7 +1269,7 @@ QPushButton[state="ok"] { false - <html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to type 2 compound callsign holders.</p></body></html> + <html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html> From e835adbc1a2341e4cb0e7077819567c866399382 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 19 Nov 2018 09:15:37 -0500 Subject: [PATCH 36/52] Dsable ToolTip on lbNextCall. Add text to the startup message box. --- widgets/mainwindow.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 186f5f40c..baf85ccad 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -735,6 +735,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}"); ui->labNextCall->setText(""); ui->labNextCall->setVisible(false); + ui->labNextCall->setToolTip(""); //### Possibly temporary ? ### for(int i=0; i<28; i++) { //Initialize dBm values float dbm=(10.0*i)/3.0 - 30.0; @@ -942,10 +943,16 @@ void MainWindow::not_GA_warning_message () MessageBox::critical_message (this, "This version of WSJT-X is a beta-level Release Candidate.\n\n" + "In FT8 and MSK144 modes it uses ONLY the new 77-bit\n" + "message formats. It will not decode 75-bit or 72-bit\n" + "messages.\n\n" + "On December 10, 2018, 77-bit messages will become the\n" + "standard. Everyone should upgrade to WSJT-X 2.0 by\n" + "January 1, 2019.\n\n" "On-the-air use carries an obligation to report problems\n" "to the WSJT Development group and to upgrade to a GA\n" "(General Availability) release when it becomes available.\n\n" - "This version cannot be used after December 31, 2018\n\n"); + "This version cannot be used after December 31, 2018.\n\n"); if(now.daysTo(timeout) < 0) Q_EMIT finished(); } From 6f966f613d6cb33b0a38184f3a888f8960e332ec Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Mon, 19 Nov 2018 21:18:41 -0500 Subject: [PATCH 37/52] Display and export contest log times in UTC, not local time --- item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp | 2 +- models/CabrilloLog.cpp | 2 +- widgets/astro.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp b/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp index 66d3b6769..5b7f76eb8 100644 --- a/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp +++ b/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp @@ -28,7 +28,7 @@ public: static QDateTime to_date_time (QVariant const& value) { - return QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull); + return QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC); } QString displayText (QVariant const& value, QLocale const& locale) const override diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index 3e218d643..055f8ae07 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -128,7 +128,7 @@ void CabrilloLog::export_qsos (QTextStream& stream) const frequency = frequency > 50000000ull ? frequency / 1000ull : frequency; stream << QString {"QSO: %1 DG %2 %3 %4 %5 %6\n"} .arg (frequency, 5) - .arg (QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull).toString ("yyyy-MM-dd hhmm")) + .arg (QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull, Qt::UTC).toString ("yyyy-MM-dd hhmm")) .arg (my_call, -12) .arg (m_->export_query_.value (sent_index).toString (), -13) .arg (m_->export_query_.value (call_index).toString (), -12) diff --git a/widgets/astro.cpp b/widgets/astro.cpp index c0e2b1fe3..4ee55da4a 100644 --- a/widgets/astro.cpp +++ b/widgets/astro.cpp @@ -213,7 +213,7 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const // we do the next period if we calculate just before it starts auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2; auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2; - auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, QTimeZone::utc ()); + auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, Qt::UTC); QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()}; QString utc {target_date_time.time().toString().trimmed ()}; int nyear {target_date_time.date().year()}; From 179e093262d87b1ad12b3294c85d6ef1ea596b10 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Tue, 20 Nov 2018 23:43:18 +0000 Subject: [PATCH 38/52] Improve handling of uncaught exceptions by catching them early and displaying in a message box --- main.cpp | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/main.cpp b/main.cpp index 784b709cd..601ae6a7e 100644 --- a/main.cpp +++ b/main.cpp @@ -52,6 +52,38 @@ namespace qsrand (seed); // this is good for rand() as well } } seeding; + + // We can't use the GUI after QApplication::exit() is called so + // uncaught exceptions can get lost on Windows systems where there + // is no console terminal, so here we override + // QApplication::notify() and wrap the base class call with a try + // block to catch and display exceptions in a message box. + class ExceptionCatchingApplication final + : public QApplication + { + public: + explicit ExceptionCatchingApplication (int& argc, char * * argv) + : QApplication {argc, argv} + { + } + bool notify (QObject * receiver, QEvent * e) override + { + try + { + return QApplication::notify (receiver, e); + } + catch (std::exception const& e) + { + MessageBox::critical_message (nullptr, translate ("main", "Fatal error"), e.what ()); + throw; + } + catch (...) + { + MessageBox::critical_message (nullptr, translate ("main", "Unexpected fatal error")); + throw; + } + } + }; } int main(int argc, char *argv[]) @@ -68,7 +100,7 @@ int main(int argc, char *argv[]) // Multiple instances communicate with jt9 via this QSharedMemory mem_jt9; - QApplication a(argc, argv); + ExceptionCatchingApplication a(argc, argv); try { setlocale (LC_NUMERIC, "C"); // ensure number forms are in @@ -339,12 +371,10 @@ int main(int argc, char *argv[]) } catch (std::exception const& e) { - MessageBox::critical_message (nullptr, a.translate ("main", "Fatal error"), e.what ()); std::cerr << "Error: " << e.what () << '\n'; } catch (...) { - MessageBox::critical_message (nullptr, a.translate ("main", "Unexpected fatal error")); std::cerr << "Unexpected fatal error\n"; throw; // hoping the runtime might tell us more about the exception } From 8fce78473fae17d52803a8a09e79b774b7fc32bc Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Tue, 20 Nov 2018 23:47:29 +0000 Subject: [PATCH 39/52] Switch to .cbr as the default Cabrillo file extension Should help to avoid accidents with other .log extension files in the WSJT-X log files directory. --- widgets/ExportCabrillo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/ExportCabrillo.cpp b/widgets/ExportCabrillo.cpp index 928a60dc9..0e61f0f08 100644 --- a/widgets/ExportCabrillo.cpp +++ b/widgets/ExportCabrillo.cpp @@ -76,7 +76,7 @@ void ExportCabrillo::save_log () auto fname = QFileDialog::getSaveFileName (this , tr ("Save Log File") , configuration_->writeable_data_dir ().absolutePath () - , tr ("Cabrillo Log (*.log)")); + , tr ("Cabrillo Log (*.cbr)")); if (fname.size ()) { QFile f {fname}; From a488c64e43d181ec904574cd9e5074de53bb4a98 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Wed, 21 Nov 2018 01:32:31 +0000 Subject: [PATCH 40/52] Partially revert the merge below because of a bad merge of Configuration.ui "Merge tag 'wsjtx-2.0.0-rc3' into develop" This partially reverts commit e3f4efefe6128e586e3c2f31abb3e932e2862d2c, reversing changes made to 388fb94698193f26649cfbc482dde8b9931385f9. --- Configuration.ui | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Configuration.ui b/Configuration.ui index 1e8feae69..7a3ec96be 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -1712,24 +1712,24 @@ QListView::item:hover { - Some logging programs will not accept JT-65 or JT9 as a recognized mode. + Some logging programs will not accept the type of reports +saved by this program. +Check this option to save the sent and received reports in the +comments field. - Con&vert mode to RTTY + d&B reports to comments - <html><head/><body><p>The callsign of the operator, if different from the station callsign.</p></body></html> + Check this option to force the clearing of the DX Call +and DX Grid fields when a 73 or free text message is sent. - - - - - Log automatically + Clear &DX call and grid after logging From eb0930294d115c684610afcd903eba2fc5281f22 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 21 Nov 2018 10:17:16 -0500 Subject: [PATCH 41/52] Add suggested message type i3.n3 = 0.6. --- lib/77bit/77bit.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/77bit/77bit.txt b/lib/77bit/77bit.txt index 0d6c4b733..ef370c111 100644 --- a/lib/77bit/77bit.txt +++ b/lib/77bit/77bit.txt @@ -10,12 +10,12 @@ subtypes. i3.n3 Example message Bits Total Purpose ---------------------------------------------------------------------------------- 0.0 FREE TEXT MSG 71 71 Free text -0.1 K1ABC RR73; W9XYZ -11 28 28 10 5 71 DXpedition Mode +0.1 K1ABC RR73; W9XYZ -12 28 28 10 5 71 DXpedition Mode 0.2 PA3XYZ/P R 590003 IO91NP 28 1 1 3 12 25 70 EU VHF contest 0.3 WA9XYZ KA1ABC R 16A EMA 28 28 1 4 3 7 71 ARRL Field Day 0.4 WA9XYZ KA1ABC R 32A EMA 28 28 1 4 3 7 71 ARRL Field Day 0.5 123456789ABCDEF012 71 71 Telemetry (18 hex) -0.6 ... tbd +0.6 K1ABC RR73; CQ W9XYZ EN37 28 28 15 71 Contesting 0.7 ... tbd 1 WA9XYZ/R KA1ABC/R R FN42 28 1 28 1 1 15 74 Standard msg From c81b3c8e6541cb0cfd4a657e912a92a72dce0ac8 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 23 Nov 2018 01:18:39 +0000 Subject: [PATCH 42/52] Validate contest QSO details before allowing logging Basic validation, must have non-empty exchange sent and received. Abstracted log view window widget behaviour into a base class. Turned on auto resize to row height in log view windows and enabled alternating colours. Convert empty fields to NULL when inserting new log table rows to signify missing data. Trap insert row errors when adding to contest log table so that logging can be held back if constraints are not met. Re-factored log QSO processing to try insert row into log table first and pop up a message box if constraints are not met, this pops up the Log QSO window in case it was initiated by an auto log event. --- CMakeLists.txt | 1 + models/CabrilloLog.cpp | 41 ++++++++++--- models/CabrilloLog.hpp | 2 +- models/FoxLog.cpp | 13 ++++- widgets/AbstractLogWindow.cpp | 76 ++++++++++++++++++++++++ widgets/AbstractLogWindow.hpp | 32 +++++++++++ widgets/CabrilloLogWindow.cpp | 105 ++++++++++++++++------------------ widgets/CabrilloLogWindow.hpp | 26 ++------- widgets/CabrilloLogWindow.ui | 20 ++++++- widgets/FoxLogWindow.cpp | 84 ++++++++------------------- widgets/FoxLogWindow.hpp | 23 ++------ widgets/FoxLogWindow.ui | 20 ++++++- widgets/logqso.cpp | 57 +++++++++++++----- widgets/logqso.h | 6 +- widgets/mainwindow.cpp | 40 +++++++------ widgets/widgets.pri | 10 ++-- 16 files changed, 349 insertions(+), 207 deletions(-) create mode 100644 widgets/AbstractLogWindow.cpp create mode 100644 widgets/AbstractLogWindow.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 39411f8a2..1cf9d88ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,6 +265,7 @@ set (wsjt_qt_CXXSRCS models/DecodeHighlightingModel.cpp widgets/DecodeHighlightingListView.cpp models/FoxLog.cpp + widgets/AbstractLogWindow.cpp widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp item_delegates/CallsignDelegate.cpp diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index 055f8ae07..f447bca79 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -78,19 +78,46 @@ QAbstractItemModel * CabrilloLog::model () return &*m_; } -void CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call +namespace +{ + void set_value_maybe_null (QSqlRecord& record, QString const& name, QString const& value) + { + if (value.size ()) + { + record.setValue (name, value); + } + else + { + record.setNull (name); + } + } +} + +bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call , QString const& exchange_sent, QString const& exchange_received) { ConditionalTransaction transaction {*m_}; auto record = m_->record (); record.setValue ("frequency", frequency / 1000ull); // kHz - record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull); - record.setValue ("call", call); - record.setValue ("exchange_sent", exchange_sent); - record.setValue ("exchange_rcvd", exchange_received); - record.setValue ("band", m_->configuration_->bands ()->find (frequency)); + if (!when.isNull ()) + { + record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull); + } + else + { + record.setNull ("when"); + } + set_value_maybe_null (record, "call", call); + set_value_maybe_null (record, "exchange_sent", exchange_sent); + set_value_maybe_null (record, "exchange_rcvd", exchange_received); + set_value_maybe_null (record, "band", m_->configuration_->bands ()->find (frequency)); SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record); - transaction.submit (); + if (!transaction.submit (false)) + { + transaction.revert (); + return false; + } + return true; } bool CabrilloLog::dupe (Frequency frequency, QString const& call) const diff --git a/models/CabrilloLog.hpp b/models/CabrilloLog.hpp index 9571adeeb..e328d0633 100644 --- a/models/CabrilloLog.hpp +++ b/models/CabrilloLog.hpp @@ -21,7 +21,7 @@ public: ~CabrilloLog (); // returns false if insert fails - void add_QSO (Frequency, QDateTime const&, QString const& call + bool add_QSO (Frequency, QDateTime const&, QString const& call , QString const& report_sent, QString const& report_received); bool dupe (Frequency, QString const& call) const; diff --git a/models/FoxLog.cpp b/models/FoxLog.cpp index 81763d9be..43cdd2b8f 100644 --- a/models/FoxLog.cpp +++ b/models/FoxLog.cpp @@ -88,12 +88,19 @@ bool FoxLog::add_QSO (QDateTime const& when, QString const& call, QString const& { ConditionalTransaction transaction {*m_}; auto record = m_->record (); - record.setValue ("when", when.toMSecsSinceEpoch () / 1000); - record.setValue ("call", call); + if (!when.isNull ()) + { + record.setValue ("when", when.toMSecsSinceEpoch () / 1000); + } + else + { + record.setNull ("when"); + } + set_value_maybe_null (record, "call", call); set_value_maybe_null (record, "grid", grid); set_value_maybe_null (record, "report_sent", report_sent); set_value_maybe_null (record, "report_rcvd", report_received); - record.setValue ("band", band); + set_value_maybe_null (record, "band", band); SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record); if (!transaction.submit (false)) { diff --git a/widgets/AbstractLogWindow.cpp b/widgets/AbstractLogWindow.cpp new file mode 100644 index 000000000..ebc901cd8 --- /dev/null +++ b/widgets/AbstractLogWindow.cpp @@ -0,0 +1,76 @@ +#include "AbstractLogWindow.hpp" + +#include +#include +#include +#include +#include "Configuration.hpp" +#include "SettingsGroup.hpp" +#include "models/FontOverrideModel.hpp" +#include "pimpl_impl.hpp" + +class AbstractLogWindow::impl final +{ +public: + impl (QString const& settings_key, QSettings * settings, Configuration const * configuration) + : settings_key_ {settings_key} + , settings_ {settings} + , configuration_ {configuration} + , log_view_ {nullptr} + { + } + + QString settings_key_; + QSettings * settings_; + Configuration const * configuration_; + QTableView * log_view_; + FontOverrideModel model_; +}; + +AbstractLogWindow::AbstractLogWindow (QString const& settings_key, QSettings * settings + , Configuration const * configuration + , QWidget * parent) + : QWidget {parent} + , m_ {settings_key, settings, configuration} +{ + // ensure view scrolls to latest new row + connect (&m_->model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) { + if (m_->log_view_) m_->log_view_->scrollToBottom (); + }); +} + +AbstractLogWindow::~AbstractLogWindow () +{ + SettingsGroup g {m_->settings_, m_->settings_key_}; + m_->settings_->setValue ("window/geometry", saveGeometry ()); +} + +void AbstractLogWindow::set_log_model (QAbstractItemModel * log_model) +{ + m_->model_.setSourceModel (log_model); +} + +void AbstractLogWindow::set_log_view (QTableView * log_view) +{ + // do this here because we know the UI must be setup before this + SettingsGroup g {m_->settings_, m_->settings_key_}; + restoreGeometry (m_->settings_->value ("window/geometry").toByteArray ()); + + m_->log_view_ = log_view; + m_->log_view_->setModel (&m_->model_); + m_->log_view_->setColumnHidden (0, true); + auto horizontal_header = log_view->horizontalHeader (); + horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); + horizontal_header->setSectionsMovable (true); + m_->log_view_->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); + set_log_view_font (m_->configuration_->decoded_text_font ()); + m_->log_view_->scrollToBottom (); +} + +void AbstractLogWindow::set_log_view_font (QFont const& font) +{ + // m_->log_view_->setFont (font); + // m_->log_view_->horizontalHeader ()->setFont (font); + // m_->log_view_->verticalHeader ()->setFont (font); + m_->model_.set_font (font); +} diff --git a/widgets/AbstractLogWindow.hpp b/widgets/AbstractLogWindow.hpp new file mode 100644 index 000000000..35d5d27cf --- /dev/null +++ b/widgets/AbstractLogWindow.hpp @@ -0,0 +1,32 @@ +#ifndef ABSTRACT_LOG_WINDOW_HPP_ +#define ABSTRACT_LOG_WINDOW_HPP_ + +#include +#include "pimpl_h.hpp" + +class QString; +class QSettings; +class Configuration; +class QAbstractItemModel; +class QTableView; +class QFont; + +class AbstractLogWindow + : public QWidget +{ +public: + AbstractLogWindow (QString const& settings_key, QSettings * settings + , Configuration const * configuration + , QWidget * parent = nullptr); + virtual ~AbstractLogWindow () = 0; + + void set_log_model (QAbstractItemModel *); + void set_log_view (QTableView *); + void set_log_view_font (QFont const&); + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp index 4a86b4509..ab83a79f2 100644 --- a/widgets/CabrilloLogWindow.cpp +++ b/widgets/CabrilloLogWindow.cpp @@ -1,77 +1,68 @@ #include "CabrilloLogWindow.hpp" -#include #include -#include -#include -#include -#include -#include - -#include "SettingsGroup.hpp" +#include #include "Configuration.hpp" #include "models/Bands.hpp" #include "item_delegates/ForeignKeyDelegate.hpp" #include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp" #include "item_delegates/CallsignDelegate.hpp" -#include "item_delegates/MaidenheadLocatorDelegate.hpp" -#include "widgets/MessageBox.hpp" -#include "qt_helpers.hpp" +#include "pimpl_impl.hpp" #include "ui_CabrilloLogWindow.h" +namespace +{ + class FormatProxyModel final + : public QIdentityProxyModel + { + public: + explicit FormatProxyModel (QObject * parent = nullptr) + : QIdentityProxyModel {parent} + { + } + + QVariant data (QModelIndex const& index, int role) const override + { + if (Qt::TextAlignmentRole == role && index.isValid ()) + { + switch (index.column ()) + { + case 1: + case 6: + return Qt::AlignRight + Qt::AlignVCenter; + default: + break; + } + } + return QIdentityProxyModel::data (index, role); + } + }; +} + +class CabrilloLogWindow::impl final +{ +public: + explicit impl () = default; + FormatProxyModel format_model_; + Ui::CabrilloLogWindow ui_; +}; + CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const * configuration , QAbstractItemModel * cabrillo_log_model, QWidget * parent) - : QWidget {parent} - , settings_ {settings} - , configuration_ {configuration} - , ui_ {new Ui::CabrilloLogWindow} + : AbstractLogWindow {"Cabrillo Log Window", settings, configuration, parent} { - cabrillo_log_model_.setSourceModel (cabrillo_log_model); setWindowTitle (QApplication::applicationName () + " - Cabrillo Log"); - ui_->setupUi (this); - read_settings (); - change_font (configuration_->decoded_text_font ()); - ui_->log_table_view->setModel (&cabrillo_log_model_); - ui_->log_table_view->setColumnHidden (0, true); - ui_->log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this}); - ui_->log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); - ui_->log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration_->bands (), &cabrillo_log_model_, 0, 6, this}); - ui_->log_table_view->setSelectionMode (QTableView::SingleSelection); - auto horizontal_header = ui_->log_table_view->horizontalHeader (); - horizontal_header->setStretchLastSection (true); - horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); - horizontal_header->setSectionsMovable (true); - horizontal_header->moveSection (6, 1); // band to first column - ui_->log_table_view->scrollToBottom (); - - // ensure view scrolls to latest new row - connect (&cabrillo_log_model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) { - ui_->log_table_view->scrollToBottom (); - }); + m_->ui_.setupUi (this); + m_->format_model_.setSourceModel (cabrillo_log_model); + set_log_model (&m_->format_model_); + set_log_view (m_->ui_.log_table_view); + m_->ui_.log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this}); + m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); + m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), cabrillo_log_model, 0, 6, this}); + m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // band to first column } CabrilloLogWindow::~CabrilloLogWindow () { - write_settings (); -} - -void CabrilloLogWindow::read_settings () -{ - SettingsGroup g {settings_, "Cabrillo Log Window"}; - restoreGeometry (settings_->value ("window/geometery").toByteArray ()); -} - -void CabrilloLogWindow::write_settings () const -{ - SettingsGroup g {settings_, "Cabrillo Log Window"}; - settings_->setValue ("window/geometery", saveGeometry ()); -} - -void CabrilloLogWindow::change_font (QFont const& font) -{ - // ui_->log_table_view->setFont (font); - // ui_->log_table_view->horizontalHeader ()->setFont (font); - // ui_->log_table_view->verticalHeader ()->setFont (font); - cabrillo_log_model_.set_font (font); } diff --git a/widgets/CabrilloLogWindow.hpp b/widgets/CabrilloLogWindow.hpp index 9a352ce9d..c0a964ce5 100644 --- a/widgets/CabrilloLogWindow.hpp +++ b/widgets/CabrilloLogWindow.hpp @@ -1,39 +1,25 @@ #ifndef CABRILLO_LOG_WINDOW_HPP_ #define CABRILLO_LOG_WINDOW_HPP_ -#include -#include -#include -#include "models/FontOverrideModel.hpp" +#include "AbstractLogWindow.hpp" +#include "pimpl_h.hpp" class QSettings; class Configuration; class QFont; -class QDateTime; class QAbstractItemModel; -namespace Ui -{ - class CabrilloLogWindow; -} class CabrilloLogWindow final - : public QWidget + : public AbstractLogWindow { public: explicit CabrilloLogWindow (QSettings *, Configuration const *, QAbstractItemModel * cabrillo_log_model - , QWidget * parent = nullptr); + , QWidget * parent = nullptr); ~CabrilloLogWindow (); - void change_font (QFont const&); - private: - void read_settings (); - void write_settings () const; - - QSettings * settings_; - Configuration const * configuration_; - FontOverrideModel cabrillo_log_model_; - QScopedPointer ui_; + class impl; + pimpl m_; }; #endif diff --git a/widgets/CabrilloLogWindow.ui b/widgets/CabrilloLogWindow.ui index eb25d1a6b..43061f132 100644 --- a/widgets/CabrilloLogWindow.ui +++ b/widgets/CabrilloLogWindow.ui @@ -2,12 +2,30 @@ CabrilloLogWindow + + + 0 + 0 + 274 + 210 + + Contest Log - + + + true + + + QAbstractItemView::SingleSelection + + + true + + diff --git a/widgets/FoxLogWindow.cpp b/widgets/FoxLogWindow.cpp index 252045359..f5e7e517d 100644 --- a/widgets/FoxLogWindow.cpp +++ b/widgets/FoxLogWindow.cpp @@ -1,12 +1,6 @@ #include "FoxLogWindow.hpp" -#include #include -#include -#include -#include -#include -#include #include "SettingsGroup.hpp" #include "Configuration.hpp" @@ -15,82 +9,50 @@ #include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp" #include "item_delegates/CallsignDelegate.hpp" #include "item_delegates/MaidenheadLocatorDelegate.hpp" -#include "widgets/MessageBox.hpp" -#include "qt_helpers.hpp" +#include "pimpl_impl.hpp" #include "ui_FoxLogWindow.h" +class FoxLogWindow::impl final +{ +public: + explicit impl () = default; + Ui::FoxLogWindow ui_; +}; + FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configuration , QAbstractItemModel * fox_log_model, QWidget * parent) - : QWidget {parent} - , settings_ {settings} - , configuration_ {configuration} - , ui_ {new Ui::FoxLogWindow} + : AbstractLogWindow {"Fox Log Window", settings, configuration, parent} { - fox_log_model_.setSourceModel (fox_log_model); setWindowTitle (QApplication::applicationName () + " - Fox Log"); - ui_->setupUi (this); - read_settings (); - change_font (configuration_->decoded_text_font ()); - ui_->log_table_view->setModel (&fox_log_model_); - ui_->log_table_view->setColumnHidden (0, true); - ui_->log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this}); - ui_->log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this}); - ui_->log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this}); - ui_->log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration_->bands (), &fox_log_model_, 0, 6, this}); - ui_->log_table_view->setSelectionMode (QTableView::SingleSelection); - auto horizontal_header = ui_->log_table_view->horizontalHeader (); - horizontal_header->setStretchLastSection (true); - horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); - horizontal_header->setSectionsMovable (true); - horizontal_header->moveSection (6, 1); // move band to first column - ui_->rate_label->setNum (0); - ui_->queued_label->setNum (0); - ui_->callers_label->setNum (0); - ui_->log_table_view->scrollToBottom (); - - // ensure view scrolls to latest new row - connect (&fox_log_model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) { - ui_->log_table_view->scrollToBottom (); - }); + m_->ui_.setupUi (this); + set_log_model (fox_log_model); + set_log_view (m_->ui_.log_table_view); + m_->ui_.log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this}); + m_->ui_.log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this}); + m_->ui_.log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this}); + m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), fox_log_model, 0, 6, this}); + m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // move band to first column + m_->ui_.rate_label->setNum (0); + m_->ui_.queued_label->setNum (0); + m_->ui_.callers_label->setNum (0); } FoxLogWindow::~FoxLogWindow () { - write_settings (); -} - -void FoxLogWindow::read_settings () -{ - SettingsGroup g {settings_, "Fox Log Window"}; - restoreGeometry (settings_->value ("window/geometery").toByteArray ()); -} - -void FoxLogWindow::write_settings () const -{ - SettingsGroup g {settings_, "Fox Log Window"}; - settings_->setValue ("window/geometery", saveGeometry ()); -} - -void FoxLogWindow::change_font (QFont const& font) -{ - // ui_->log_table_view->setFont (font); - // ui_->log_table_view->horizontalHeader ()->setFont (font); - // ui_->log_table_view->verticalHeader ()->setFont (font); - fox_log_model_.set_font (font); } void FoxLogWindow::callers (int n) { - ui_->callers_label->setNum (n); + m_->ui_.callers_label->setNum (n); } void FoxLogWindow::queued (int n) { - ui_->queued_label->setNum (n); + m_->ui_.queued_label->setNum (n); } void FoxLogWindow::rate (int n) { - ui_->rate_label->setNum (n); + m_->ui_.rate_label->setNum (n); } diff --git a/widgets/FoxLogWindow.hpp b/widgets/FoxLogWindow.hpp index 62895a763..d27ccdea6 100644 --- a/widgets/FoxLogWindow.hpp +++ b/widgets/FoxLogWindow.hpp @@ -1,42 +1,29 @@ #ifndef FOX_LOG_WINDOW_HPP_ #define FOX_LOG_WINDOW_HPP_ -#include -#include -#include -#include "models/FontOverrideModel.hpp" +#include "AbstractLogWindow.hpp" +#include "pimpl_h.hpp" class QSettings; class Configuration; class QFont; -class QDateTime; class QAbstractItemModel; -namespace Ui -{ - class FoxLogWindow; -} class FoxLogWindow final - : public QWidget + : public AbstractLogWindow { public: explicit FoxLogWindow (QSettings *, Configuration const *, QAbstractItemModel * fox_log_model , QWidget * parent = nullptr); ~FoxLogWindow (); - void change_font (QFont const&); void callers (int); void queued (int); void rate (int); private: - void read_settings (); - void write_settings () const; - - QSettings * settings_; - Configuration const * configuration_; - FontOverrideModel fox_log_model_; - QScopedPointer ui_; + class impl; + pimpl m_; }; #endif diff --git a/widgets/FoxLogWindow.ui b/widgets/FoxLogWindow.ui index 2a3e84aba..96ef8b112 100644 --- a/widgets/FoxLogWindow.ui +++ b/widgets/FoxLogWindow.ui @@ -2,12 +2,30 @@ FoxLogWindow + + + 0 + 0 + 331 + 238 + + Fox Log - + + + true + + + QAbstractItemView::SingleSelection + + + true + + diff --git a/widgets/logqso.cpp b/widgets/logqso.cpp index 77324e52b..b6412cb59 100644 --- a/widgets/logqso.cpp +++ b/widgets/logqso.cpp @@ -10,6 +10,7 @@ #include "MessageBox.hpp" #include "Configuration.hpp" #include "models/Bands.hpp" +#include "models/CabrilloLog.hpp" #include "validators/MaidenheadLocatorValidator.hpp" #include "ui_logqso.h" @@ -57,11 +58,10 @@ void LogQSO::storeSettings () const void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, - Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd) + Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd, + CabrilloLog * cabrillo_log) { if(!isHidden()) return; - m_xSent=xSent; - m_xRcvd=xRcvd; ui->call->setText(hisCall); ui->grid->setText(hisGrid); ui->name->setText(""); @@ -87,17 +87,23 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString m_myGrid=m_config->my_grid(); ui->band->setText (m_config->bands ()->find (dialFreq)); ui->loggedOperator->setText(m_config->opCall()); - ui->exchSent->setText(m_xSent); - ui->exchRcvd->setText(m_xRcvd); + ui->exchSent->setText (xSent); + ui->exchRcvd->setText (xRcvd); + m_cabrilloLog = cabrillo_log; using SpOp = Configuration::SpecialOperatingActivity; - if( SpOp::FOX == m_config->special_op_id() or - (m_config->autoLog() and SpOp::NONE < m_config->special_op_id() and - m_xSent!="" and m_xRcvd!="")) { - accept(); - } else { - show(); - } + auto special_op = m_config->special_op_id (); + if (SpOp::FOX == special_op + || (m_config->autoLog () + && SpOp::NONE < special_op && special_op < SpOp::FOX)) + { + // allow auto logging in Fox mode and contests + accept(); + } + else + { + show(); + } } void LogQSO::accept() @@ -120,6 +126,29 @@ void LogQSO::accept() QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6)); operator_call = ui->loggedOperator->text(); + // validate + using SpOp = Configuration::SpecialOperatingActivity; + auto special_op = m_config->special_op_id (); + if (SpOp::NONE < special_op && special_op < SpOp::FOX) + { + if (ui->exchSent->text ().isEmpty () || ui->exchRcvd->text ().isEmpty ()) + { + show (); + MessageBox::warning_message (this, tr ("Invalid QSO Data"), + tr ("Check exchange sent and received")); + return; // without accepting + } + + if (!m_cabrilloLog->add_QSO (m_dialFreq, QDateTime::currentDateTimeUtc (), hisCall, + ui->exchSent->text (), ui->exchRcvd->text ())) + { + show (); + MessageBox::warning_message (this, tr ("Invalid QSO Data"), + tr ("Check all fields")); + return; // without accepting + } + } + //Log this QSO to file "wsjtx.log" static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx.log")}; if(!f.open(QIODevice::Text | QIODevice::Append)) { @@ -169,8 +198,8 @@ void LogQSO::accept() , m_myGrid , m_txPower , operator_call - , m_xSent - , m_xRcvd)); + , ui->exchSent->text () + , ui->exchRcvd->text ())); QDialog::accept(); } diff --git a/widgets/logqso.h b/widgets/logqso.h index 2f2e4c29e..b0e703a93 100644 --- a/widgets/logqso.h +++ b/widgets/logqso.h @@ -17,6 +17,7 @@ namespace Ui { class QSettings; class Configuration; class QByteArray; +class CabrilloLog; class LogQSO : public QDialog { @@ -28,7 +29,7 @@ public: void initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, Radio::Frequency dialFreq, - bool noSuffix, QString xSent, QString xRcvd); + bool noSuffix, QString xSent, QString xRcvd, CabrilloLog *); public slots: void accept(); @@ -56,10 +57,9 @@ private: Radio::Frequency m_dialFreq; QString m_myCall; QString m_myGrid; - QString m_xSent; - QString m_xRcvd; QDateTime m_dateTimeOn; QDateTime m_dateTimeOff; + CabrilloLog * m_cabrilloLog; }; #endif // LogQSO_H diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 186f5f40c..c1a09c227 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -1228,10 +1228,10 @@ void MainWindow::setDecodedTextFont (QFont const& font) m_msgAvgWidget->changeFont (font); } if (m_foxLogWindow) { - m_foxLogWindow->change_font (font); + m_foxLogWindow->set_log_view_font (font); } if (m_contestLogWindow) { - m_contestLogWindow->change_font (font); + m_contestLogWindow->set_log_view_font (font); } updateGeometry (); } @@ -5331,9 +5331,16 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button default: break; } + using SpOp = Configuration::SpecialOperatingActivity; + auto special_op = m_config.special_op_id (); + if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) + { + if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); + } m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + - ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd); + ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd, + m_cabrilloLog.data ()); } void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid @@ -5350,15 +5357,6 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, tr ("Cannot open \"%1\"").arg (m_logBook.path ())); } - - if (SpecOp::NONE < m_config.special_op_id() && SpecOp::FOX > m_config.special_op_id()) { - if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); - m_cabrilloLog->add_QSO (m_freqNominal, QDateTime::currentDateTimeUtc (), m_hisCall, m_xSent, m_xRcvd); - m_xSent=""; - m_xRcvd=""; - ui->sbSerialNumber->setValue (ui->sbSerialNumber->value () + 1); - } - m_messageClient->qso_logged (QSO_date_off, call, grid, dial_freq, mode, rpt_sent, rpt_received , tx_power, comments, name, QSO_date_on, operator_call, my_call, my_grid); m_messageClient->logged_ADIF (ADIF); @@ -5378,6 +5376,15 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, if (m_config.clear_DX () and SpecOp::HOUND != m_config.special_op_id()) clearDX (); m_dateTimeQSOOn = QDateTime {}; + using SpOp = Configuration::SpecialOperatingActivity; + auto special_op = m_config.special_op_id (); + if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) + { + ui->sbSerialNumber->setValue (ui->sbSerialNumber->value () + 1); + } + + m_xSent.clear (); + m_xRcvd.clear (); } qint64 MainWindow::nWidgets(QString t) @@ -6125,11 +6132,12 @@ void MainWindow::on_reset_fox_log_action_triggered () void MainWindow::on_reset_cabrillo_log_action_triggered () { - if (MessageBox::Yes == MessageBox::query_message(this, tr("Confirm Erase"), - tr("Are you sure you want to erase file cabrillo.log" - " and start a new Cabrillo log?"))) + if (MessageBox::Yes == MessageBox::query_message (this, tr ("Confirm Reset"), + tr ("Are you sure you want to erase your contest log?"), + tr ("Doing this will remove all QSO records for the current contest. " + "They will be kept in the ADIF log file but will not be available " + "for export in your Cabrillo log."))) { - QFile {m_config.writeable_data_dir ().absoluteFilePath ("cabrillo.log")}.remove (); ui->sbSerialNumber->setValue (1); if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); m_cabrilloLog->reset (); diff --git a/widgets/widgets.pri b/widgets/widgets.pri index 019fdcd17..e70c5cb9e 100644 --- a/widgets/widgets.pri +++ b/widgets/widgets.pri @@ -7,7 +7,8 @@ SOURCES += \ widgets/echoplot.cpp widgets/echograph.cpp widgets/fastgraph.cpp \ widgets/fastplot.cpp widgets/MessageBox.cpp \ widgets/colorhighlighting.cpp widgets/ExportCabrillo.cpp \ - widgets/CabrilloLogWindow.cpp + widgets/AbstractLogWindow.cpp \ + widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp HEADERS += \ widgets/mainwindow.h widgets/plotter.h \ @@ -17,8 +18,8 @@ HEADERS += \ widgets/meterwidget.h widgets/messageaveraging.h \ widgets/echoplot.h widgets/echograph.h widgets/fastgraph.h \ widgets/fastplot.h widgets/MessageBox.hpp widgets/colorhighlighting.h \ - widgets/ExportCabrillo.h \ - widgets/CabrilloLogWindow.cpp + widgets/ExportCabrillo.h widgets/AbstractLogWindow.hpp \ + widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp FORMS += \ widgets/mainwindow.ui widgets/about.ui \ @@ -26,5 +27,4 @@ FORMS += \ widgets/logqso.ui widgets/messageaveraging.ui \ widgets/echograph.ui widgets/fastgraph.ui \ widgets/colorhighlighting.ui widgets/ExportCabrillo.ui \ - widgets/FoxLogWindow.ui \ - widgets/CabrilloLogWindow.ui + widgets/FoxLogWindow.ui widgets/CabrilloLogWindow.ui From e434bc5b550ec34632cfa2b9fc46beb3641cf363 Mon Sep 17 00:00:00 2001 From: Steve Franke Date: Fri, 23 Nov 2018 15:10:44 -0600 Subject: [PATCH 43/52] Remove obsolete routines related to msk144. --- CMakeLists.txt | 13 +-- lib/Makefile.mskWin | 75 --------------- lib/encode_msk144.f90 | 111 --------------------- lib/extractmessage144.f90 | 51 ---------- lib/genmsk144.f90 | 146 ---------------------------- lib/genmsk_short.f90 | 66 ------------- lib/ldpcsim144.f90 | 175 --------------------------------- lib/msk144d.f90 | 136 -------------------------- lib/msk144sd.f90 | 197 -------------------------------------- lib/msk144sim.f90 | 21 ++-- lib/platanh.f90 | 24 +++++ lib/pltanh.f90 | 24 +++++ lib/unpackmsg144.f90 | 117 ---------------------- 13 files changed, 59 insertions(+), 1097 deletions(-) delete mode 100644 lib/Makefile.mskWin delete mode 100644 lib/encode_msk144.f90 delete mode 100644 lib/extractmessage144.f90 delete mode 100644 lib/genmsk144.f90 delete mode 100644 lib/genmsk_short.f90 delete mode 100644 lib/ldpcsim144.f90 delete mode 100644 lib/msk144d.f90 delete mode 100644 lib/msk144sd.f90 create mode 100644 lib/platanh.f90 create mode 100644 lib/pltanh.f90 delete mode 100644 lib/unpackmsg144.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 39411f8a2..5818cc8b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -382,7 +382,6 @@ set (wsjt_FSRCS lib/badmsg.f90 lib/ft8/baseline.f90 lib/bpdecode40.f90 - lib/bpdecode144.f90 lib/bpdecode128_90.f90 lib/ft8/bpdecode174.f90 lib/ft8/bpdecode174_91.f90 @@ -414,7 +413,6 @@ set (wsjt_FSRCS lib/encode232.f90 lib/encode4.f90 lib/encode_msk40.f90 - lib/encode_msk144.f90 lib/encode_128_90.f90 lib/ft8/encode174.f90 lib/ft8/encode174_91.f90 @@ -422,7 +420,6 @@ set (wsjt_FSRCS lib/ephem.f90 lib/extract.f90 lib/extract4.f90 - lib/extractmessage144.f90 lib/extractmessage77.f90 lib/ft8/extractmessage174.f90 lib/ft8/extractmessage174_91.f90 @@ -497,10 +494,8 @@ set (wsjt_FSRCS lib/moondopjpl.f90 lib/morse.f90 lib/move.f90 - lib/msk144d.f90 lib/msk40decodeframe.f90 lib/msk144decodeframe.f90 - lib/msk144sd.f90 lib/msk40spd.f90 lib/msk144spd.f90 lib/msk40sync.f90 @@ -519,6 +514,8 @@ set (wsjt_FSRCS lib/peakdt9.f90 lib/peakup.f90 lib/plotsave.f90 + lib/platanh.f90 + lib/pltanh.f90 lib/polyfit.f90 lib/prog_args.f90 lib/ps4.f90 @@ -561,7 +558,6 @@ set (wsjt_FSRCS lib/twkfreq.f90 lib/ft8/twkfreq1.f90 lib/twkfreq65.f90 - lib/unpackmsg144.f90 lib/update_recent_calls.f90 lib/update_hasharray.f90 lib/ft8/watterson.f90 @@ -1252,14 +1248,9 @@ target_link_libraries (ft8code wsjt_fort wsjt_cxx) add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc) target_link_libraries (ft8sim wsjt_fort wsjt_cxx) -add_executable (msk144sd lib/msk144sd.f90 wsjtx.rc) -target_link_libraries (msk144sd wsjt_fort wsjt_cxx) - add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc) target_link_libraries (msk144sim wsjt_fort wsjt_cxx) -add_executable (msk144d lib/msk144d.f90 wsjtx.rc) -target_link_libraries (msk144d wsjt_fort wsjt_cxx) endif(WSJT_BUILD_UTILS) # build the main application diff --git a/lib/Makefile.mskWin b/lib/Makefile.mskWin deleted file mode 100644 index 9d5e6e62b..000000000 --- a/lib/Makefile.mskWin +++ /dev/null @@ -1,75 +0,0 @@ - -# Set paths -EXE_DIR = ..\\..\\wsjtx_install -QT_DIR = C:/wsjt-env/Qt5/5.2.1/mingw48_32 -FFTW3_DIR = .. - -INCPATH = -I${QT_DIR}/include/QtCore -I${QT_DIR}/include - -# Compilers -CC = gcc -CXX = g++ -FC = gfortran -AR = ar cr -RANLIB = ranlib -MKDIR = mkdir -p -CP = cp -RM = rm -f - -FFLAGS = -O2 -fbounds-check -Wall -Wno-conversion -CFLAGS = -O2 -I. - -# Default rules -%.o: %.c - ${CC} ${CFLAGS} -c $< -%.o: %.f - ${FC} ${FFLAGS} -c $< -%.o: %.F - ${FC} ${FFLAGS} -c $< -%.o: %.f90 - ${FC} ${FFLAGS} -c $< -%.o: %.F90 - ${FC} ${FFLAGS} -c $< - -#all: jt9code JTMSKcode.exe -all: jtmsk.exe JTMSKsim.exe JTMSKcode.exe fixwav.exe - -OBJS3 = JTMSKsim.o wavhdr.o gran.o four2a.o db.o -JTMSKsim.exe: $(OBJS3) - $(FC) -o JTMSKsim.exe $(OBJS3) C:\JTSDK\fftw3f\libfftw3f-3.dll - -OBJS4 = jt9code.o packjt.o fmtmsg.o gen9.o deg2grid.o grid2deg.o \ - entail.o encode232.o interleave9.o graycode.o igray.o -jt9code: $(OBJS4) - $(FC) -o jt9code $(OBJS4) - -OBJS5 = JTMSKcode.o packjt.o fmtmsg.o genmsk.o deg2grid.o grid2deg.o \ - entail.o tab.o vit213.o hashing.o nhash.o -JTMSKcode.exe: $(OBJS5) - $(FC) -o JTMSKcode.exe $(OBJS5) - -OBJS6 = jtmsk.o analytic.o four2a.o db.o pctile.o \ - shell.o tweak1.o syncmsk.o genmsk.o packjt.o fmtmsg.o indexx.o \ - deg2grid.o grid2deg.o entail.o hashing.o nhash.o tab.o vit213.o \ - mskdt.o rectify_msk.o timer.o jtmsk_decode.o genmsk_short.o \ - jtmsk_short.o golay24_table.o hash.o - -jtmsk.exe: $(OBJS6) - $(FC) -o jtmsk.exe $(OBJS6) C:\JTSDK\fftw3f\libfftw3f-3.dll - -OBJS1 = fixwav.o wavhdr.o -fixwav.exe: $(OBJS1) - $(FC) -o fixwav.exe $(OBJS1) - -OBJS2 = t2.o four2a.o db.o -t2: $(OBJS2) - $(FC) -o t2 $(OBJS2) C:\JTSDK\fftw3f\libfftw3f-3.dll - -OBJS6 = t6.o four2a.o db.o -t6: $(OBJS6) - $(FC) -o t6 $(OBJS6) C:\JTSDK\fftw3f\libfftw3f-3.dll - -.PHONY : clean - -clean: - $(RM) *.o JTMSKcode JTMSKcode.exe diff --git a/lib/encode_msk144.f90 b/lib/encode_msk144.f90 deleted file mode 100644 index 4e4d8968e..000000000 --- a/lib/encode_msk144.f90 +++ /dev/null @@ -1,111 +0,0 @@ -subroutine encode_msk144(message,codeword) -! Encode an 80-bit message and return a 128-bit codeword. -! The generator matrix has dimensions (48,80). -! The code is a (128,80) regular ldpc code with column weight 3. -! The code was generated using the PEG algorithm. -! After creating the codeword, the columns are re-ordered according to -! "colorder" to make the codeword compatible with the parity-check -! matrix stored in Radford Neal's "pchk" format. -! -character*20 g(48) -integer*1 codeword(128) -integer*1 colorder(128) -integer*1 gen144(48,80) -integer*1 itmp(128) -integer*1 message(80) -integer*1 pchecks(48) -logical first -data first/.true./ -data g/ & !parity-check generator matrix for (128,80) code - "24084000800020008000", & - "b39678f7ccdb1baf5f4c", & - "10001000400408012000", & - "08104000100002010800", & - "dc9c18f61ea0e4b7f05c", & - "42c040160909ca002c00", & - "cc50b52b9a80db0d7f9e", & - "dde5ace80780bae74740", & - "00800080020000890080", & - "01020040010400400040", & - "20008010020000100030", & - "80400008004000040050", & - "a4b397810915126f5604", & - "04040100001040200008", & - "00800006000888000800", & - "00010c00000104040001", & - "cc7cd7d953cdc204eba0", & - "0094abe7dd146beb16ce", & - "5af2aec8c7b051c7544a", & - "14040508801840200088", & - "7392f5e720f8f5a62c1e", & - "503cc2a06bff4e684ec9", & - "5a2efd46f1efbb513b80", & - "ac06e9513fd411f1de03", & - "16a31be3dd3082ca2bd6", & - "28542e0daf62fe1d9332", & - "00210c002001540c0401", & - "0ed90d56f84298706a98", & - "939670f7ecdf9baf4f4c", & - "cfe41dec47a433e66240", & - "16d2179c2d5888222630", & - "408000160108ca002800", & - "808000830a00018900a0", & - "9ae2ed8ef3afbf8c3a52", & - "5aaafd86f3efbfc83b02", & - "f39658f68cdb0baf1f4c", & - "9414bb6495106261366a", & - "71ba18670c08411bf682", & - "7298f1a7217cf5c62e5e", & - "86d7a4864396a981369b", & - "a8042c01ae22fe191362", & - "9235ae108b2d60d0e306", & - "dfe5ade807a03be74640", & - "d2451588e6e27ccd9bc4", & - "12b51ae39d20e2ea3bde", & - "a49387810d95136fd604", & - "467e7578e51d5b3b8a0e", & - "f6ad1ac7cc3aaa3fe580"/ - -data colorder/0,1,2,3,4,5,6,7,8,9, & - 10,11,12,13,14,15,24,26,29,30, & - 32,43,44,47,60,77,79,97,101,111, & - 96,38,64,53,93,34,59,94,74,90, & - 108,123,85,57,70,25,69,62,48,49, & - 50,51,52,33,54,55,56,21,58,36, & - 16,61,23,63,20,65,66,67,68,46, & - 22,71,72,73,31,75,76,45,78,17, & - 80,81,82,83,84,42,86,87,88,89, & - 39,91,92,35,37,95,19,27,98,99, & - 100,28,102,103,104,105,106,107,40,109, & - 110,18,112,113,114,115,116,117,118,119, & - 120,121,122,41,124,125,126,127/ - -save first,gen144 - -if( first ) then ! fill the generator matrix - gen144=0 - do i=1,48 - do j=1,5 - read(g(i)( (j-1)*4+1:(j-1)*4+4 ),"(Z4)") istr - do jj=1,16 - icol=(j-1)*16+jj - if( btest(istr,16-jj) ) gen144(i,icol)=1 - enddo - enddo - enddo -first=.false. -endif - -do i=1,48 - nsum=0 - do j=1,80 - nsum=nsum+message(j)*gen144(i,j) - enddo - pchecks(i)=mod(nsum,2) -enddo -itmp(1:48)=pchecks -itmp(49:128)=message(1:80) -codeword(colorder+1)=itmp(1:128) - -return -end subroutine encode_msk144 diff --git a/lib/extractmessage144.f90 b/lib/extractmessage144.f90 deleted file mode 100644 index a5dadb0b4..000000000 --- a/lib/extractmessage144.f90 +++ /dev/null @@ -1,51 +0,0 @@ -subroutine extractmessage144(decoded,msgreceived,nhashflag,recent_calls,nrecent) - use iso_c_binding, only: c_loc,c_size_t - use packjt - use hashing - - character*22 msgreceived - character*12 call1,call2 - character*12 recent_calls(nrecent) - integer*1 decoded(80) - integer*1, target:: i1Dec8BitBytes(10) - integer*1 i1hashdec - integer*4 i4Dec6BitWords(12) - -! Collapse 80 decoded bits to 10 bytes. Bytes 1-9 are the message, byte 10 is the hash - do ibyte=1,10 - itmp=0 - do ibit=1,8 - itmp=ishft(itmp,1)+iand(1,decoded((ibyte-1)*8+ibit)) - enddo - i1Dec8BitBytes(ibyte)=itmp - enddo - -! Calculate the hash using the first 9 bytes. - ihashdec=nhash(c_loc(i1Dec8BitBytes),int(9,c_size_t),146) - ihashdec=2*iand(ihashdec,255) - -! Compare calculated hash with received byte 10 - if they agree, keep the message. - i1hashdec=ihashdec - if( i1hashdec .eq. i1Dec8BitBytes(10) ) then -! Good hash --- unpack 72-bit message - do ibyte=1,12 - itmp=0 - do ibit=1,6 - itmp=ishft(itmp,1)+iand(1,decoded((ibyte-1)*6+ibit)) - enddo - i4Dec6BitWords(ibyte)=itmp - enddo - call unpackmsg144(i4Dec6BitWords,msgreceived,call1,call2) - nhashflag=1 - if( call1(1:2) .ne. 'CQ' .and. call1(1:2) .ne. ' ' ) then - call update_recent_calls(call1,recent_calls,nrecent) - endif - if( call2(1:2) .ne. ' ' ) then - call update_recent_calls(call2,recent_calls,nrecent) - endif - else - msgreceived=' ' - nhashflag=-1 - endif - return - end subroutine extractmessage144 diff --git a/lib/genmsk144.f90 b/lib/genmsk144.f90 deleted file mode 100644 index f02344439..000000000 --- a/lib/genmsk144.f90 +++ /dev/null @@ -1,146 +0,0 @@ -subroutine genmsk144(msg0,mygrid,ichk,msgsent,i4tone,itype) -! s8 + 48bits + s8 + 80 bits = 144 bits (72ms message duration) -! -! Encode an MSK144 message -! Input: -! - msg0 requested message to be transmitted -! - ichk if ichk=1, return only msgsent -! if ichk.ge.10000, set imsg=ichk-10000 for short msg -! - msgsent message as it will be decoded -! - i4tone array of audio tone values, 0 or 1 -! - itype message type -! 1 = standard message "Call_1 Call_2 Grid/Rpt" -! 2 = type 1 prefix -! 3 = type 1 suffix -! 4 = type 2 prefix -! 5 = type 2 suffix -! 6 = free text (up to 13 characters) -! 7 = short message " Rpt" - - use iso_c_binding, only: c_loc,c_size_t - use packjt - use hashing - character*22 msg0 - character*22 message !Message to be generated - character*22 msgsent !Message as it will be received - character*6 mygrid - integer*4 i4Msg6BitWords(13) !72-bit message as 6-bit words - integer*4 i4tone(144) ! - integer*1, target:: i1Msg8BitBytes(10) !80 bits represented in 10 bytes - integer*1 codeword(128) !Encoded bits before re-ordering - integer*1 msgbits(80) !72-bit message + 8-bit hash - integer*1 bitseq(144) !Tone #s, data and sync (values 0-1) - integer*1 i1hash(4) - integer*1 s8(8) - real*8 pp(12) - real*8 xi(864),xq(864),pi,twopi - data s8/0,1,1,1,0,0,1,0/ - equivalence (ihash,i1hash) - logical first - data first/.true./ - save - - if(first) then - first=.false. - nsym=128 - pi=4.0*atan(1.0) - twopi=8.*atan(1.0) - do i=1,12 - pp(i)=sin((i-1)*pi/12) - enddo - endif - - if(msg0(1:1).eq.'@') then !Generate a fixed tone - read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency - go to 2 -1 nfreq=1000 -2 i4tone(1)=nfreq - else - message=msg0 - do i=1,22 - if(ichar(message(i:i)).eq.0) then - message(i:)=' ' - exit - endif - enddo - - do i=1,22 !Strip leading blanks - if(message(1:1).ne.' ') exit - message=message(i+1:) - enddo - - if(message(1:1).eq.'<') then - call genmsk40(message,msgsent,ichk,i4tone,itype) - if(itype.lt.0) go to 999 - i4tone(41)=-40 - go to 999 - endif - - call packmsg(message,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes - call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent - - if(ichk.eq.1) go to 999 - i4=0 - ik=0 - im=0 - do i=1,12 - nn=i4Msg6BitWords(i) - do j=1, 6 - ik=ik+1 - i4=i4+i4+iand(1,ishft(nn,j-6)) - i4=iand(i4,255) - if(ik.eq.8) then - im=im+1 - i1Msg8BitBytes(im)=i4 - ik=0 - endif - enddo - enddo - - ihash=nhash(c_loc(i1Msg8BitBytes),int(9,c_size_t),146) - ihash=2*iand(ihash,32767) !Generate the 8-bit hash - i1Msg8BitBytes(10)=i1hash(1) !Hash code to byte 10 - - mbit=0 - do i=1, 10 - i1=i1Msg8BitBytes(i) - do ibit=1,8 - mbit=mbit+1 - msgbits(mbit)=iand(1,ishft(i1,ibit-8)) - enddo - enddo - - call encode_msk144(msgbits,codeword) - -!Create 144-bit channel vector: -!8-bit sync word + 48 bits + 8-bit sync word + 80 bits - bitseq=0 - bitseq(1:8)=s8 - bitseq(9:56)=codeword(1:48) - bitseq(57:64)=s8 - bitseq(65:144)=codeword(49:128) - bitseq=2*bitseq-1 - - xq(1:6)=bitseq(1)*pp(7:12) !first bit is mapped to 1st half-symbol on q - do i=1,71 - is=(i-1)*12+7 - xq(is:is+11)=bitseq(2*i+1)*pp - enddo - xq(864-5:864)=bitseq(1)*pp(1:6) !last half symbol - do i=1,72 - is=(i-1)*12+1 - xi(is:is+11)=bitseq(2*i)*pp - enddo -! Map I and Q to tones. - i4tone=0 - do i=1,72 - i4tone(2*i-1)=(bitseq(2*i)*bitseq(2*i-1)+1)/2; - i4tone(2*i)=-(bitseq(2*i)*bitseq(mod(2*i,144)+1)-1)/2; - enddo - endif - -! Flip polarity - i4tone=-i4tone+1 - -999 return -end subroutine genmsk144 diff --git a/lib/genmsk_short.f90 b/lib/genmsk_short.f90 deleted file mode 100644 index f1b555f34..000000000 --- a/lib/genmsk_short.f90 +++ /dev/null @@ -1,66 +0,0 @@ -subroutine genmsk_short(msg,msgsent,ichk,itone,itype) - - use hashing - character*22 msg,msgsent - character*3 crpt,rpt(0:7) - logical first - integer itone(35) - integer ig24(0:4096-1) !Codewords for Golay (24,12) code - integer b11(11) - data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 code - data rpt /'26 ','27 ','28 ','R26','R27','R28','RRR','73 '/ - data first/.true./ - save first,ig24 - - if(first) then - call golay24_table(ig24) !Define the Golay(24,12) codewords - first=.false. - endif - - itype=-1 - msgsent='*** bad message ***' - itone=0 - i1=index(msg,'>') - if(i1.lt.9) go to 900 - call fmtmsg(msg,iz) - crpt=msg(i1+2:i1+5) - do i=0,7 - if(crpt.eq.rpt(i)) go to 10 - enddo - go to 900 - -10 irpt=i !Report index, 0-7 - if(ichk.lt.10000) then - call hash(msg(2:i1-1),i1-2,ihash) - ihash=iand(ihash,511) !9-bit hash for the two callsigns - ig=8*ihash + irpt !12-bit message information - else - ig=ichk-10000 - endif - ncodeword=ig24(ig) - itone(1:11)=b11 !Insert the Barker-11 code - n=2**24 - do i=12,35 !Insert codeword into itone array - n=n/2 - itone(i)=0 - if(iand(ncodeword,n).ne.0) itone(i)=1 - enddo - msgsent=msg - itype=7 - - n=count(itone(1:35).eq.0) - if(mod(n,2).ne.0) stop 'Parity error in genmsk_short.' - -900 return -end subroutine genmsk_short - -subroutine hash_calls(calls,ih9) - - use hashing - character*(*) calls - i1=index(calls,'>') - call hash(calls(2:i1-1),i1-2,ih9) - ih9=iand(ih9,511) !9-bit hash for the two callsigns - - return -end subroutine hash_calls diff --git a/lib/ldpcsim144.f90 b/lib/ldpcsim144.f90 deleted file mode 100644 index 3121ada2c..000000000 --- a/lib/ldpcsim144.f90 +++ /dev/null @@ -1,175 +0,0 @@ -program ldpcsim - -use, intrinsic :: iso_c_binding -use iso_c_binding, only: c_loc,c_size_t -use hashing -use packjt -parameter(NRECENT=10) -character*12 recent_calls(NRECENT) -character*22 msg,msgsent,msgreceived -character*8 arg -integer*1, allocatable :: codeword(:), decoded(:), message(:) -integer*1, target:: i1Msg8BitBytes(10) -integer*1 i1hash(4) -integer*1 msgbits(80) -integer*4 i4Msg6BitWords(13) -integer ihash -integer nerrtot(0:128),nerrdec(0:128) -real*8, allocatable :: lratio(:), rxdata(:), rxavgd(:) -real, allocatable :: yy(:), llr(:) -equivalence(ihash,i1hash) - -do i=1,NRECENT - recent_calls(i)=' ' -enddo -nerrtot=0 -nerrdec=0 - -nargs=iargc() -if(nargs.ne.4) then - print*,'Usage: ldpcsim niter navg #trials s ' - print*,'eg: ldpcsim 10 1 1000 0.75' - return -endif -call getarg(1,arg) -read(arg,*) max_iterations -call getarg(2,arg) -read(arg,*) navg -call getarg(3,arg) -read(arg,*) ntrials -call getarg(4,arg) -read(arg,*) s - -! don't count hash bits as data bits -K=72 -N=128 -rate=real(K)/real(N) - -write(*,*) "rate: ",rate - -write(*,*) "niter= ",max_iterations," navg= ",navg," s= ",s - -allocate ( codeword(N), decoded(K), message(K) ) -allocate ( lratio(N), rxdata(N), rxavgd(N), yy(N), llr(N) ) - -msg="K9AN K1JT EN50" - call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes - call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent - write(*,*) "message sent ",msgsent - - i4=0 - ik=0 - im=0 - do i=1,12 - nn=i4Msg6BitWords(i) - do j=1, 6 - ik=ik+1 - i4=i4+i4+iand(1,ishft(nn,j-6)) - i4=iand(i4,255) - if(ik.eq.8) then - im=im+1 -! if(i4.gt.127) i4=i4-256 - i1Msg8BitBytes(im)=i4 - ik=0 - endif - enddo - enddo - - ihash=nhash(c_loc(i1Msg8BitBytes),int(9,c_size_t),146) - ihash=2*iand(ihash,32767) !Generate the 8-bit hash - i1Msg8BitBytes(10)=i1hash(1) !Hash code to byte 10 - mbit=0 - do i=1, 10 - i1=i1Msg8BitBytes(i) - do ibit=1,8 - mbit=mbit+1 - msgbits(mbit)=iand(1,ishft(i1,ibit-8)) - enddo - enddo - call encode_msk144(msgbits,codeword) - call init_random_seed() - -write(*,*) "Eb/N0 SNR2500 ngood nundetected nbadhash sigma" -do idb = 14,-6,-1 - db=idb/2.0-1.0 - sigma=1/sqrt( 2*rate*(10**(db/10.0)) ) - ngood=0 - nue=0 - nbadhash=0 - - do itrial=1, ntrials - rxavgd=0d0 - do iav=1,navg - call sgran() -! Create a realization of a noisy received word - do i=1,N - rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran() - enddo - rxavgd=rxavgd+rxdata - enddo - rxdata=rxavgd - nerr=0 - do i=1,N - if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1 - enddo - nerrtot(nerr)=nerrtot(nerr)+1 - -! Correct signal normalization is important for this decoder. - rxav=sum(rxdata)/N - rx2av=sum(rxdata*rxdata)/N - rxsig=sqrt(rx2av-rxav*rxav) - rxdata=rxdata/rxsig -! To match the metric to the channel, s should be set to the noise standard deviation. -! For now, set s to the value that optimizes decode probability near threshold. -! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of -! magnitude in UER - if( s .lt. 0 ) then - ss=sigma - else - ss=s - endif - - llr=2.0*rxdata/(ss*ss) - lratio=exp(llr) - yy=rxdata - -! max_iterations is max number of belief propagation iterations -! call ldpc_decode(lratio, decoded, max_iterations, niterations, max_dither, ndither) -! call amsdecode(yy, max_iterations, decoded, niterations) -! call bitflipmsk144(rxdata, decoded, niterations) - call bpdecode144(llr, max_iterations, decoded, niterations) - -! If the decoder finds a valid codeword, niterations will be .ge. 0. - if( niterations .ge. 0 ) then - call extractmessage144(decoded,msgreceived,nhashflag,recent_calls,nrecent) - if( nhashflag .ne. 1 ) then - nbadhash=nbadhash+1 - endif - nueflag=0 - -! Check the message plus hash against what was sent. - do i=1,K - if( msgbits(i) .ne. decoded(i) ) then - nueflag=1 - endif - enddo - if( nhashflag .eq. 1 .and. nueflag .eq. 0 ) then - ngood=ngood+1 - nerrdec(nerr)=nerrdec(nerr)+1 - else if( nhashflag .eq. 1 .and. nueflag .eq. 1 ) then - nue=nue+1; - endif - endif - enddo - snr2500=db-3.5 - write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2)") db,snr2500,ngood,nue,nbadhash,ss - -enddo - -open(unit=23,file='nerrhisto.dat',status='unknown') -do i=0,128 - write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10) -enddo -close(23) - -end program ldpcsim diff --git a/lib/msk144d.f90 b/lib/msk144d.f90 deleted file mode 100644 index 60c8b0c1d..000000000 --- a/lib/msk144d.f90 +++ /dev/null @@ -1,136 +0,0 @@ -program msk144d - - ! Test the msk144 decoder for WSJT-X - - use options - use timer_module, only: timer - use timer_impl, only: init_timer - use readwav - - character c - character*80 line - character*512 datadir - character*500 infile - character*12 mycall,hiscall - character*6 mygrid - character(len=500) optarg - - logical :: display_help=.false. - logical*1 bShMsgs - logical*1 btrain - logical*1 bswl - - type(wav_header) :: wav - - integer*2 id2(30*12000) - integer*2 ichunk(7*1024) - - real*8 pcoeffs(5) - - type (option) :: long_options(9) = [ & - option ('ndepth',.true.,'c','ndepth',''), & - option ('dxcall',.true.,'d','hiscall',''), & - option ('evemode',.true.,'e','Must be used with -s.',''), & - option ('frequency',.true.,'f','rxfreq',''), & - option ('help',.false.,'h','Display this help message',''), & - option ('mycall',.true.,'m','mycall',''), & - option ('nftol',.true.,'n','nftol',''), & - option ('rxequalize',.false.,'r','Rx Equalize',''), & - option ('short',.false.,'s','enable Sh','') & - ] - t0=0.0 - ndepth=3 - ntol=100 - nrxfreq=1500 - mycall='' - mygrid='EN50WC' - hiscall='' - bShMsgs=.false. - btrain=.false. - bswl=.false. - datadir='.' - pcoeffs=0.d0 - - do - call getopt('c:d:ef:hm:n:rs',long_options,c,optarg,narglen,nstat,noffset,nremain,.true.) - if( nstat .ne. 0 ) then - exit - end if - select case (c) - case ('c') - read (optarg(:narglen), *) ndepth - case ('d') - read (optarg(:narglen), *) hiscall - case ('e') - bswl=.true. - case ('f') - read (optarg(:narglen), *) nrxfreq - case ('h') - display_help = .true. - case ('m') - read (optarg(:narglen), *) mycall - case ('n') - read (optarg(:narglen), *) ntol - case ('r') - btrain=.true. - case ('s') - bShMsgs=.true. - end select - end do - - if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then - print *, '' - print *, 'Usage: msk144d [OPTIONS] file1 [file2 ...]' - print *, '' - print *, ' msk144 decode pre-recorded .WAV file(s)' - print *, '' - print *, 'OPTIONS:' - do i = 1, size (long_options) - call long_options(i) % print (6) - end do - go to 999 - endif - - call init_timer ('timer.out') - call timer('msk144 ',0) - ndecoded=0 - do ifile=noffset+1,noffset+nremain - call get_command_argument(ifile,optarg,narglen) - infile=optarg(:narglen) - call timer('read ',0) - call wav%read (infile) - i1=index(infile,'.wav') - if( i1 .eq. 0 ) i1=index(infile,'.WAV') - read(infile(i1-6:i1-1),*,err=998) nutc - inquire(FILE=infile,SIZE=isize) - npts=min((isize-216)/2,360000) - read(unit=wav%lun) id2(1:npts) - close(unit=wav%lun) - call timer('read ',1) - - do i=1,npts-7*1024+1,7*512 - ichunk=id2(i:i+7*1024-1) - tsec=(i-1)/12000.0 - tt=sum(float(abs(id2(i:i+7*512-1)))) - if( tt .ne. 0.0 ) then - call mskrtd(ichunk,nutc,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall,bShMsgs, & - btrain,pcoeffs,bswl,datadir,line) - if( index(line,"&") .ne. 0 .or. & - index(line,"^") .ne. 0 .or. & - index(line,"!") .ne. 0 .or. & - index(line,"@") .ne. 0 ) then - write(*,*) line - endif - endif - enddo - enddo - - call timer('msk144 ',1) - call timer('msk144 ',101) - go to 999 - -998 print*,'Cannot read from file:' - print*,infile - -999 continue -end program msk144d diff --git a/lib/msk144sd.f90 b/lib/msk144sd.f90 deleted file mode 100644 index 267fff545..000000000 --- a/lib/msk144sd.f90 +++ /dev/null @@ -1,197 +0,0 @@ -program msk144sd -! -! A simple decoder for slow msk144. -! Can be used as a (slow) brute-force multi-decoder by looping -! over a set of carrier frequencies. -! - use options - use timer_module, only: timer - use timer_impl, only: init_timer - use readwav - - parameter (NRECENT=10) - parameter (NSPM=864) - parameter (NPATTERNS=4) - - character ch - character*80 line - character*500 infile - character*12 mycall,hiscall - character*6 mygrid - character(len=500) optarg - character*22 msgreceived - character*12 recent_calls(NRECENT) - - complex cdat(30*375) - complex c(NSPM) - complex ct(NSPM) - - real softbits(144) - real xmc(NPATTERNS) - - logical :: display_help=.false. - - type(wav_header) :: wav - - integer iavmask(8) - integer iavpatterns(8,NPATTERNS) - integer npkloc(10) - - integer*2 id2(30*12000) - integer*2 ichunk(7*1024) - - data iavpatterns/ & - 1,1,1,1,0,0,0,0, & - 0,1,1,1,1,0,0,0, & - 0,0,1,1,1,1,0,0, & - 1,1,1,1,1,1,0,0/ - data xmc/2.0,4.5,2.5,3.0/ - - type (option) :: long_options(2) = [ & - option ('frequency',.true.,'f','rxfreq',''), & - option ('help',.false.,'h','Display this help message','') & - ] - t0=0.0 - ntol=100 - nrxfreq=1500 - - do - call getopt('f:h',long_options,ch,optarg,narglen,nstat,noffset,nremain,.true.) - if( nstat .ne. 0 ) then - exit - end if - select case (ch) - case ('f') - read (optarg(:narglen), *) nrxfreq - case ('h') - display_help = .true. - end select - end do - - if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then - print *, '' - print *, 'Usage: msk144sd [OPTIONS] file1 [file2 ...]' - print *, '' - print *, ' decode pre-recorded .WAV file(s)' - print *, '' - print *, 'OPTIONS:' - do i = 1, size (long_options) - call long_options(i) % print (6) - end do - go to 999 - endif - - call init_timer ('timer.out') - call timer('msk144 ',0) - ndecoded=0 - do ifile=noffset+1,noffset+nremain - call get_command_argument(ifile,optarg,narglen) - infile=optarg(:narglen) - call timer('read ',0) - call wav%read (infile) - i1=index(infile,'.wav') - if( i1 .eq. 0 ) i1=index(infile,'.WAV') - read(infile(i1-6:i1-1),*,err=998) nutc - inquire(FILE=infile,SIZE=isize) - npts=min((isize-216)/2,360000) - read(unit=wav%lun) id2(1:npts) - close(unit=wav%lun) - call timer('read ',1) - -! do if=1,89 ! brute force multi-decoder - fo=nrxfreq -! fo=(if-1)*25.0+300.0 - call msksddc(id2,npts,fo,cdat) - np=npts/32 - ntol=200 ! actual ntol is ntol/32=6.25 Hz. Detection window is 12.5 Hz wide - fc=1500.0 - call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, & - softbits,recent_calls,nrecent) - nsnr=0 ! need an snr estimate - if( ndecodesuccess .eq. 1 ) then - fest=fo+fest-fc ! fudging because spd thinks input signal is at 1500 Hz - goto 900 - endif -! If short ping decoder doesn't find a decode - npat=NPATTERNS - do iavg=1,npat - iavmask=iavpatterns(1:8,iavg) - navg=sum(iavmask) - deltaf=4.0/real(navg) ! search increment for frequency sync - npeaks=4 - ntol=200 - fc=1500.0 - call msk144sync(cdat(1:6*NSPM),6,ntol,deltaf,iavmask,npeaks,fc, & - fest,npkloc,nsyncsuccess,xmax,c) - if( nsyncsuccess .eq. 0 ) cycle - - do ipk=1,npeaks - do is=1,3 - ic0=npkloc(ipk) - if(is.eq.2) ic0=max(1,ic0-1) - if(is.eq.3) ic0=min(NSPM,ic0+1) - ct=cshift(c,ic0-1) - call msk144decodeframe(ct,softbits,msgreceived,ndecodesuccess, & - recent_calls,nrecent) - if(ndecodesuccess .gt. 0) then - tdec=tsec+xmc(iavg)*tframe - fest=fo+(fest-fc)/32.0 - goto 900 - endif - enddo !Slicer dither - enddo !Peak loop - enddo - -! enddo -900 continue - if( ndecodesuccess .gt. 0 ) then - write(*,1020) nutc,nsnr,tdec,nint(fest),' % ',msgreceived,navg -1020 format(i6.6,i4,f5.1,i5,a3,a22,i4) - endif - enddo - - call timer('msk144 ',1) - call timer('msk144 ',101) - go to 999 - -998 print*,'Cannot read from file:' - print*,infile - -999 continue -end program msk144sd - -subroutine msksddc(id2,npts,fc,cdat) - -! The msk144 detector/demodulator/decoder will decode signals -! with carrier frequency, fc, in the range fN/4 +/- 0.03333*fN. -! -! For slow MSK144 with nslow=32: -! fs=12000/32=375 Hz, fN=187.5 Hz -! -! This routine accepts input samples with fs=12000 Hz. It -! downconverts and decimates by 32 to center a signal with input carrier -! frequency fc at new carrier frequency 1500/32=46.875 Hz. -! The analytic signal is returned. - - parameter (NFFT1=30*12000,NFFT2=30*375) - integer*2 id2(npts) - complex cx(0:NFFT1) - complex cdat(30*375) - - dt=1.0/12000.0 - df=1.0/(NFFT1*dt) - icenter=int(fc/df+0.5) - i46p875=int(46.875/df+0.5) - ishift=icenter-i46p875 - cx=cmplx(0.0,0.0) - cx(1:npts)=id2 - call four2a(cx,NFFT1,1,-1,1) - cx=cshift(cx,ishift) - cx(1)=0.5*cx(1) - cx(2*i46p875+1:)=cmplx(0.0,0.0) - call four2a(cx,NFFT2,1,1,1) - cdat(1:npts/32)=cx(0:npts/32-1)/NFFT1 - return - -end subroutine msksddc - diff --git a/lib/msk144sim.f90 b/lib/msk144sim.f90 index 75c6a1e64..7b2a8a00b 100644 --- a/lib/msk144sim.f90 +++ b/lib/msk144sim.f90 @@ -13,10 +13,10 @@ program msk144sim integer itone(144) !Message bits nargs=iargc() - if(nargs.ne.6) then - print*,'Usage: msk144sim message freq width nslow snr nfiles' - print*,'Example: msk144sim "K1ABC W9XYZ EN37" 1500 0.12 1 2 1' - print*,' msk144sim "K1ABC W9XYZ EN37" 1500 2.5 32 15 1' + if(nargs.ne.5) then + print*,'Usage: msk144sim message freq width snr nfiles' + print*,'Example: msk144sim "K1ABC W9XYZ EN37" 1500 0.12 2 1' + print*,' msk144sim "K1ABC W9XYZ EN37" 1500 2.5 15 1' go to 999 endif call getarg(1,msg) @@ -25,10 +25,8 @@ program msk144sim call getarg(3,arg) read(arg,*) width call getarg(4,arg) - read(arg,*) nslow - call getarg(5,arg) read(arg,*) snrdb - call getarg(6,arg) + call getarg(5,arg) read(arg,*) nfiles !sig is the peak amplitude of the ping. @@ -50,9 +48,9 @@ program msk144sim twopi=8.d0*atan(1.d0) nsym=144 - nsps=6*nslow + nsps=6 if( itone(41) .lt. 0 ) nsym=40 - baud=2000.d0/nslow + baud=2000.d0 dphi0=twopi*(freq-0.25d0*baud)/12000.d0 dphi1=twopi*(freq+0.25d0*baud)/12000.d0 phi=0.0 @@ -79,7 +77,7 @@ program msk144sim go to 999 endif - if(nslow.eq.1) call makepings(pings,NMAX,width,sig) + call makepings(pings,NMAX,width,sig) ! call sgran() do ifile=1,nfiles !Loop over requested number of files @@ -92,8 +90,7 @@ program msk144sim fac=sqrt(6000.0/2500.0) do i=0,NMAX-1 xx=gran() - if(nslow.eq.1) wave(i)=pings(i)*waveform(i) + fac*xx - if(nslow.gt.1) wave(i)=sig*waveform(i) + fac*xx + wave(i)=pings(i)*waveform(i) + fac*xx iwave(i)=30.0*wave(i) enddo diff --git a/lib/platanh.f90 b/lib/platanh.f90 new file mode 100644 index 000000000..e610366d7 --- /dev/null +++ b/lib/platanh.f90 @@ -0,0 +1,24 @@ +subroutine platanh(x,y) + isign=+1 + z=x + if( x.lt.0 ) then + isign=-1 + z=abs(x) + endif + if( z.le. 0.664 ) then + y=x/0.83 + return + elseif( z.le. 0.9217 ) then + y=isign*(z-0.4064)/0.322 + return + elseif( z.le. 0.9951 ) then + y=isign*(z-0.8378)/0.0524 + return + elseif( z.le. 0.9998 ) then + y=isign*(z-0.9914)/0.0012 + return + else + y=isign*7.0 + return + endif +end subroutine platanh diff --git a/lib/pltanh.f90 b/lib/pltanh.f90 new file mode 100644 index 000000000..4c6c2b6d6 --- /dev/null +++ b/lib/pltanh.f90 @@ -0,0 +1,24 @@ +subroutine pltanh(x,y) + isign=+1 + z=x + if( x.lt.0 ) then + isign=-1 + z=abs(x) + endif + if( z.le. 0.8 ) then + y=0.83*x + return + elseif( z.le. 1.6 ) then + y=isign*(0.322*z+0.4064) + return + elseif( z.le. 3.0 ) then + y=isign*(0.0524*z+0.8378) + return + elseif( z.lt. 7.0 ) then + y=isign*(0.0012*z+0.9914) + return + else + y=isign*0.9998 + return + endif +end subroutine pltanh diff --git a/lib/unpackmsg144.f90 b/lib/unpackmsg144.f90 deleted file mode 100644 index 96423ff69..000000000 --- a/lib/unpackmsg144.f90 +++ /dev/null @@ -1,117 +0,0 @@ - subroutine unpackmsg144(dat,msg,c1,c2) -! special unpackmsg for MSK144 - returns call1 and call2 to enable -! maintenance of a recent-calls-heard list - - use packjt - parameter (NBASE=37*36*10*27*27*27) - parameter (NGBASE=180*180) - integer dat(12) - character c1*12,c2*12,grid*4,msg*22,grid6*6,psfx*4,junk2*4 - logical cqnnn - - cqnnn=.false. - nc1=ishft(dat(1),22) + ishft(dat(2),16) + ishft(dat(3),10)+ & - ishft(dat(4),4) + iand(ishft(dat(5),-2),15) - - nc2=ishft(iand(dat(5),3),26) + ishft(dat(6),20) + & - ishft(dat(7),14) + ishft(dat(8),8) + ishft(dat(9),2) + & - iand(ishft(dat(10),-4),3) - - ng=ishft(iand(dat(10),15),12) + ishft(dat(11),6) + dat(12) - - if(ng.ge.32768) then - call unpacktext(nc1,nc2,ng,msg) - c1(1:12)=' ' - c2(1:12)=' ' - go to 100 - endif - - call unpackcall(nc1,c1,iv2,psfx) - if(iv2.eq.0) then - ! This is an "original JT65" message - if(nc1.eq.NBASE+1) c1='CQ ' - if(nc1.eq.NBASE+2) c1='QRZ ' - nfreq=nc1-NBASE-3 - if(nfreq.ge.0 .and. nfreq.le.999) then - write(c1,1002) nfreq - 1002 format('CQ ',i3.3) - cqnnn=.true. - endif - endif - - call unpackcall(nc2,c2,junk1,junk2) - call unpackgrid(ng,grid) - - if(iv2.gt.0) then - ! This is a JT65v2 message - do i=1,4 - if(ichar(psfx(i:i)).eq.0) psfx(i:i)=' ' - enddo - - n1=len_trim(psfx) - n2=len_trim(c2) - if(iv2.eq.1) msg='CQ '//psfx(:n1)//'/'//c2(:n2)//' '//grid - if(iv2.eq.2) msg='QRZ '//psfx(:n1)//'/'//c2(:n2)//' '//grid - if(iv2.eq.3) msg='DE '//psfx(:n1)//'/'//c2(:n2)//' '//grid - if(iv2.eq.4) msg='CQ '//c2(:n2)//'/'//psfx(:n1)//' '//grid - if(iv2.eq.5) msg='QRZ '//c2(:n2)//'/'//psfx(:n1)//' '//grid - if(iv2.eq.6) msg='DE '//c2(:n2)//'/'//psfx(:n1)//' '//grid - if(iv2.eq.7) msg='DE '//c2(:n2)//' '//grid - if(iv2.eq.8) msg=' ' - go to 100 - else - - endif - - grid6=grid//'ma' - call grid2k(grid6,k) - if(k.ge.1 .and. k.le.450) call getpfx2(k,c1) - if(k.ge.451 .and. k.le.900) call getpfx2(k,c2) - - i=index(c1,char(0)) - if(i.ge.3) c1=c1(1:i-1)//' ' - i=index(c2,char(0)) - if(i.ge.3) c2=c2(1:i-1)//' ' - - msg=' ' - j=0 - if(cqnnn) then - msg=c1//' ' - j=7 !### ??? ### - go to 10 - endif - - do i=1,12 - j=j+1 - msg(j:j)=c1(i:i) - if(c1(i:i).eq.' ') go to 10 - enddo - j=j+1 - msg(j:j)=' ' - - 10 do i=1,12 - if(j.le.21) j=j+1 - msg(j:j)=c2(i:i) - if(c2(i:i).eq.' ') go to 20 - enddo - if(j.le.21) j=j+1 - msg(j:j)=' ' - - 20 if(k.eq.0) then - do i=1,4 - if(j.le.21) j=j+1 - msg(j:j)=grid(i:i) - enddo - if(j.le.21) j=j+1 - msg(j:j)=' ' - endif - - 100 continue - if(msg(1:6).eq.'CQ9DX ') msg(3:3)=' ' - if(msg(1:2).eq.'E9' .and. & - msg(3:3).ge.'A' .and. msg(3:3).le.'Z' .and. & - msg(4:4).ge.'A' .and. msg(4:4).le.'Z' .and. & - msg(5:5).eq.' ') msg='CQ '//msg(3:) - - return - end subroutine unpackmsg144 From 59c74905f3527f66d4cb669577be9d03bb324f9e Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 23 Nov 2018 22:18:43 +0000 Subject: [PATCH 44/52] Force the Aqua theme on macOS to avoid issues with the Mojave dark theme Qt 5.12 is exected to sort out issues with the Mojave dark theme, until then we just have to stop it trying to make WSJT-X dark. --- Darwin/Info.plist.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Darwin/Info.plist.in b/Darwin/Info.plist.in index b62e03682..830975da5 100644 --- a/Darwin/Info.plist.in +++ b/Darwin/Info.plist.in @@ -36,5 +36,7 @@ NSApplication NSHighResolutionCapable True + NSRequiresAquaSystemAppearance + From ef053e5a9fec6f19980e0b0d56f4a5940353ac86 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 24 Nov 2018 09:09:50 -0500 Subject: [PATCH 45/52] Protect against execution of on_pbTxMode() when not in "JT9+JT65" mode. --- widgets/mainwindow.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 186f5f40c..26d12a698 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6482,15 +6482,17 @@ void MainWindow::on_readFreq_clicked() void MainWindow::on_pbTxMode_clicked() { - if(m_modeTx=="JT9") { - m_modeTx="JT65"; - ui->pbTxMode->setText("Tx JT65 #"); - } else { - m_modeTx="JT9"; - ui->pbTxMode->setText("Tx JT9 @"); + if(m_mode=="JT9+JT65") { + if(m_modeTx=="JT9") { + m_modeTx="JT65"; + ui->pbTxMode->setText("Tx JT65 #"); + } else { + m_modeTx="JT9"; + ui->pbTxMode->setText("Tx JT9 @"); + } + m_wideGraph->setModeTx(m_modeTx); + statusChanged(); } - m_wideGraph->setModeTx(m_modeTx); - statusChanged(); } void MainWindow::setXIT(int n, Frequency base) From 7b4b4074554c38ef1a026c90c2715da2c2cba9f0 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 25 Nov 2018 21:53:38 +0000 Subject: [PATCH 46/52] Improved layout of settings frequencies and station details tables --- Configuration.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Configuration.cpp b/Configuration.cpp index 03f5b2ac2..a75cacc68 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -1091,6 +1091,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network frequencies_.sort (FrequencyList_v2::frequency_column); ui_->frequencies_table_view->setModel (&next_frequencies_); + ui_->frequencies_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); + ui_->frequencies_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); ui_->frequencies_table_view->sortByColumn (FrequencyList_v2::frequency_column, Qt::AscendingOrder); ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true); @@ -1131,6 +1133,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network // stations_.sort (StationList::band_column); ui_->stations_table_view->setModel (&next_stations_); + ui_->stations_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); + ui_->stations_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder); // stations delegates From 86fb68f305ab41d27a0bd6980897826ea47cae54 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 25 Nov 2018 21:55:19 +0000 Subject: [PATCH 47/52] Set foreign key item delegate references key values combo box size according to contents --- item_delegates/ForeignKeyDelegate.cpp | 22 +++++++++++++++++++++- item_delegates/ForeignKeyDelegate.hpp | 5 +++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/item_delegates/ForeignKeyDelegate.cpp b/item_delegates/ForeignKeyDelegate.cpp index 09df6a731..204738163 100644 --- a/item_delegates/ForeignKeyDelegate.cpp +++ b/item_delegates/ForeignKeyDelegate.cpp @@ -1,7 +1,10 @@ #include "ForeignKeyDelegate.hpp" +#include #include - +#include +#include +#include #include "CandidateKeyFilter.hpp" ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referenced_model @@ -40,3 +43,20 @@ QWidget * ForeignKeyDelegate::createEditor (QWidget * parent editor->setSizeAdjustPolicy (QComboBox::AdjustToContents); return editor; } + +QSize ForeignKeyDelegate::sizeHint (QStyleOptionViewItem const& option, QModelIndex const& index) const +{ + auto size_hint = QStyledItemDelegate::sizeHint (option, index); + QFontMetrics metrics {option.font}; + QStyleOptionComboBox combo_box_option; + combo_box_option.rect = option.rect; + combo_box_option.state = option.state | QStyle::State_Enabled; + for (auto row = 0; row < candidate_key_filter_->rowCount (); ++row) + { + size_hint = size_hint.expandedTo (qApp->style ()->sizeFromContents (QStyle::CT_ComboBox + , &combo_box_option + , {metrics.width (candidate_key_filter_->data (candidate_key_filter_->index (row, 0)).toString ()) + , metrics.height ()})); + } + return size_hint; +} diff --git a/item_delegates/ForeignKeyDelegate.hpp b/item_delegates/ForeignKeyDelegate.hpp index 01b03ee5b..4f58f4608 100644 --- a/item_delegates/ForeignKeyDelegate.hpp +++ b/item_delegates/ForeignKeyDelegate.hpp @@ -33,9 +33,10 @@ public: , int referencing_key_role = Qt::EditRole); ~ForeignKeyDelegate (); - QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; - private: + QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; + QSize sizeHint (QStyleOptionViewItem const&, QModelIndex const&) const override; + QScopedPointer candidate_key_filter_; }; From 314d8a645b740b1adc2358501e7f1e391dbbd08d Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 25 Nov 2018 22:13:15 +0000 Subject: [PATCH 48/52] Replace deprecated Qt algorithms with C++ Standard Library equivalents --- Configuration.cpp | 8 ++++---- models/FrequencyList.cpp | 14 +++++--------- models/StationList.cpp | 13 ++++--------- widgets/mainwindow.cpp | 5 +++-- 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/Configuration.cpp b/Configuration.cpp index a75cacc68..bf57206b2 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -2279,10 +2279,10 @@ void Configuration::impl::delete_selected_macros (QModelIndexList selected_rows) { // sort in reverse row order so that we can delete without changing // indices underneath us - qSort (selected_rows.begin (), selected_rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) - { - return rhs.row () < lhs.row (); // reverse row ordering - }); + std::sort (selected_rows.begin (), selected_rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) + { + return rhs.row () < lhs.row (); // reverse row ordering + }); // now delete them Q_FOREACH (auto index, selected_rows) diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp index e50afe2a4..55844bdfa 100644 --- a/models/FrequencyList.cpp +++ b/models/FrequencyList.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -350,14 +351,6 @@ bool FrequencyList_v2::remove (Item f) return m_->removeRow (row); } -namespace -{ - bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) - { - return lhs.row () > rhs.row (); - } -} - bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows) { bool result {true}; @@ -371,7 +364,10 @@ bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows) } // reverse sort by row - qSort (rows.begin (), rows.end (), row_is_higher); + std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) + { + return rhs.row () < lhs.row (); // reverse row ordering + }); Q_FOREACH (auto index, rows) { if (result && !m_->removeRow (index.row ())) diff --git a/models/StationList.cpp b/models/StationList.cpp index cfd629ede..eeeb4d607 100644 --- a/models/StationList.cpp +++ b/models/StationList.cpp @@ -139,14 +139,6 @@ bool StationList::remove (Station s) return removeRow (row); } -namespace -{ - bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) - { - return lhs.row () > rhs.row (); - } -} - bool StationList::removeDisjointRows (QModelIndexList rows) { bool result {true}; @@ -160,7 +152,10 @@ bool StationList::removeDisjointRows (QModelIndexList rows) } // reverse sort by row - qSort (rows.begin (), rows.end (), row_is_higher); + std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) + { + return rhs.row () < lhs.row (); // reverse row ordering + }); Q_FOREACH (auto index, rows) { if (result && !m_->removeRow (index.row ())) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index e0788a8f9..895569942 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -7923,9 +7924,9 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB) if(isort>1) { if(bReverse) { - qSort(list.begin(),list.end(),qGreater()); + std::sort (list.begin (), list.end (), std::greater ()); } else { - qSort(list.begin(),list.end()); + std::sort (list.begin (), list.end ()); } } From db51726da2a955b49d73ab8f039ec89df66b05e5 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 25 Nov 2018 22:19:41 +0000 Subject: [PATCH 49/52] Move Fox log reset action to Fox log window context menu and allow deletes of QSOs Move to OnRowChange edit strategy for log tables so that deletes from view can be implemented cleanly. Improve layout of log view tables by resizing to contents. --- models/CabrilloLog.cpp | 17 ++++---- models/CabrilloLog.hpp | 4 +- models/FoxLog.cpp | 17 ++++---- models/FoxLog.hpp | 4 +- qt_db_helpers.hpp | 32 ++++++++++++--- widgets/AbstractLogWindow.cpp | 75 ++++++++++++++++++++++++++++++----- widgets/AbstractLogWindow.hpp | 13 +++++- widgets/CabrilloLogWindow.cpp | 29 +++++++++++--- widgets/CabrilloLogWindow.hpp | 6 ++- widgets/CabrilloLogWindow.ui | 8 +--- widgets/FoxLogWindow.cpp | 46 +++++++++++++++++++-- widgets/FoxLogWindow.hpp | 10 ++++- widgets/FoxLogWindow.ui | 12 +++--- widgets/mainwindow.cpp | 18 ++------- widgets/mainwindow.h | 1 - widgets/mainwindow.ui | 1 - 16 files changed, 214 insertions(+), 79 deletions(-) diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index f447bca79..965d6f957 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -52,7 +52,7 @@ CabrilloLog::impl::impl (Configuration const * configuration) SQL_error_check (export_query_, &QSqlQuery::prepare, "SELECT frequency, \"when\", exchange_sent, call, exchange_rcvd FROM cabrillo_log ORDER BY \"when\""); - setEditStrategy (QSqlTableModel::OnManualSubmit); + setEditStrategy (QSqlTableModel::OnRowChange); setTable ("cabrillo_log"); setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(kHz)")); setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); @@ -73,7 +73,7 @@ CabrilloLog::~CabrilloLog () { } -QAbstractItemModel * CabrilloLog::model () +QSqlTableModel * CabrilloLog::model () { return &*m_; } @@ -96,7 +96,6 @@ namespace bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call , QString const& exchange_sent, QString const& exchange_received) { - ConditionalTransaction transaction {*m_}; auto record = m_->record (); record.setValue ("frequency", frequency / 1000ull); // kHz if (!when.isNull ()) @@ -111,13 +110,12 @@ bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString c set_value_maybe_null (record, "exchange_sent", exchange_sent); set_value_maybe_null (record, "exchange_rcvd", exchange_received); set_value_maybe_null (record, "band", m_->configuration_->bands ()->find (frequency)); - SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record); - if (!transaction.submit (false)) + auto ok = m_->insertRecord (-1, record); + if (ok) { - transaction.revert (); - return false; + m_->select (); // to refresh views } - return true; + return ok; } bool CabrilloLog::dupe (Frequency frequency, QString const& call) const @@ -133,9 +131,12 @@ void CabrilloLog::reset () { if (m_->rowCount ()) { + m_->setEditStrategy (QSqlTableModel::OnManualSubmit); ConditionalTransaction transaction {*m_}; SQL_error_check (*m_, &QSqlTableModel::removeRows, 0, m_->rowCount (), QModelIndex {}); transaction.submit (); + m_->select (); // to refresh views + m_->setEditStrategy (QSqlTableModel::OnRowChange); } } diff --git a/models/CabrilloLog.hpp b/models/CabrilloLog.hpp index e328d0633..43b9e8f94 100644 --- a/models/CabrilloLog.hpp +++ b/models/CabrilloLog.hpp @@ -8,7 +8,7 @@ class Configuration; class QDateTime; class QString; -class QAbstractItemModel; +class QSqlTableModel; class QTextStream; class CabrilloLog final @@ -25,7 +25,7 @@ public: , QString const& report_sent, QString const& report_received); bool dupe (Frequency, QString const& call) const; - QAbstractItemModel * model (); + QSqlTableModel * model (); void reset (); void export_qsos (QTextStream&) const; diff --git a/models/FoxLog.cpp b/models/FoxLog.cpp index 43cdd2b8f..1503e5662 100644 --- a/models/FoxLog.cpp +++ b/models/FoxLog.cpp @@ -43,7 +43,7 @@ FoxLog::impl::impl () SQL_error_check (dupe_query_, &QSqlQuery::prepare, "SELECT COUNT(*) FROM fox_log WHERE call = :call AND band = :band"); - setEditStrategy (QSqlTableModel::OnManualSubmit); + setEditStrategy (QSqlTableModel::OnRowChange); setTable ("fox_log"); setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call")); @@ -62,7 +62,7 @@ FoxLog::~FoxLog () { } -QAbstractItemModel * FoxLog::model () +QSqlTableModel * FoxLog::model () { return &*m_; } @@ -86,7 +86,6 @@ bool FoxLog::add_QSO (QDateTime const& when, QString const& call, QString const& , QString const& report_sent, QString const& report_received , QString const& band) { - ConditionalTransaction transaction {*m_}; auto record = m_->record (); if (!when.isNull ()) { @@ -101,13 +100,12 @@ bool FoxLog::add_QSO (QDateTime const& when, QString const& call, QString const& set_value_maybe_null (record, "report_sent", report_sent); set_value_maybe_null (record, "report_rcvd", report_received); set_value_maybe_null (record, "band", band); - SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record); - if (!transaction.submit (false)) + auto ok = m_->insertRecord (-1, record); + if (ok) { - transaction.revert (); - return false; + m_->select (); // to refresh views } - return true; + return ok; } bool FoxLog::dupe (QString const& call, QString const& band) const @@ -123,8 +121,11 @@ void FoxLog::reset () { if (m_->rowCount ()) { + m_->setEditStrategy (QSqlTableModel::OnManualSubmit); ConditionalTransaction transaction {*m_}; SQL_error_check (*m_, &QSqlTableModel::removeRows, 0, m_->rowCount (), QModelIndex {}); transaction.submit (); + m_->select (); // to refresh views + m_->setEditStrategy (QSqlTableModel::OnRowChange); } } diff --git a/models/FoxLog.hpp b/models/FoxLog.hpp index 028f8205c..caa8e358f 100644 --- a/models/FoxLog.hpp +++ b/models/FoxLog.hpp @@ -6,7 +6,7 @@ class QDateTime; class QString; -class QAbstractItemModel; +class QSqlTableModel; class FoxLog final : private boost::noncopyable @@ -21,7 +21,7 @@ public: , QString const& band); bool dupe (QString const& call, QString const& band) const; - QAbstractItemModel * model (); + QSqlTableModel * model (); void reset (); private: diff --git a/qt_db_helpers.hpp b/qt_db_helpers.hpp index da823b0cb..49a082f72 100644 --- a/qt_db_helpers.hpp +++ b/qt_db_helpers.hpp @@ -30,32 +30,51 @@ public: { model_.database ().transaction (); } + bool submit (bool throw_on_error = true) { - Q_ASSERT (model_.isDirty ()); bool ok {true}; if (throw_on_error) { - SQL_error_check (model_, &QSqlTableModel::submitAll); + SQL_error_check (model_ + , QSqlTableModel::OnManualSubmit == model_.editStrategy () + ? &QSqlTableModel::submitAll + : &QSqlTableModel::submit); } else { - ok = model_.submitAll (); + ok = QSqlTableModel::OnManualSubmit == model_.editStrategy () + ? model_.submitAll () : model_.submit (); } submitted_ = submitted_ || ok; return ok; } + void revert () { - Q_ASSERT (model_.isDirty ()); - model_.revertAll (); + if (QSqlTableModel::OnManualSubmit == model_.editStrategy ()) + { + model_.revertAll (); + } + else + { + model_.revert (); + } } + ~ConditionalTransaction () { if (model_.isDirty ()) { // abandon un-submitted changes to the model - model_.revertAll (); + if (QSqlTableModel::OnManualSubmit == model_.editStrategy ()) + { + model_.revertAll (); + } + else + { + model_.revert (); + } } auto database = model_.database (); if (submitted_) @@ -67,6 +86,7 @@ public: database.rollback (); } } + private: QSqlTableModel& model_; bool submitted_; diff --git a/widgets/AbstractLogWindow.cpp b/widgets/AbstractLogWindow.cpp index ebc901cd8..e796cdc3e 100644 --- a/widgets/AbstractLogWindow.cpp +++ b/widgets/AbstractLogWindow.cpp @@ -1,25 +1,36 @@ #include "AbstractLogWindow.hpp" +#include #include #include #include #include +#include +#include +#include +#include #include "Configuration.hpp" #include "SettingsGroup.hpp" +#include "MessageBox.hpp" #include "models/FontOverrideModel.hpp" #include "pimpl_impl.hpp" class AbstractLogWindow::impl final { public: - impl (QString const& settings_key, QSettings * settings, Configuration const * configuration) - : settings_key_ {settings_key} + impl (AbstractLogWindow * self, QString const& settings_key, QSettings * settings + , Configuration const * configuration) + : self_ {self} + , settings_key_ {settings_key} , settings_ {settings} , configuration_ {configuration} , log_view_ {nullptr} { } + void delete_QSOs (); + + AbstractLogWindow * self_; QString settings_key_; QSettings * settings_; Configuration const * configuration_; @@ -27,11 +38,51 @@ public: FontOverrideModel model_; }; +namespace +{ + bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) + { + return lhs.row () > rhs.row (); + } +} + +void AbstractLogWindow::impl::delete_QSOs () +{ + auto selection_model = log_view_->selectionModel (); + selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + auto row_indexes = selection_model->selectedRows (); + + if (row_indexes.size () + && MessageBox::Yes == MessageBox::query_message (self_ + , tr ("Confirm Delete") + , tr ("Are you sure you want to delete the %n " + "selected QSO(s) from the log", "" + , row_indexes.size ()))) + { + // We must work with source model indexes because we don't want row + // removes to invalidate model indexes we haven't yet processed. We + // achieve that by processing them in decending row order. + for (auto& row_index : row_indexes) + { + row_index = model_.mapToSource (row_index); + } + + // reverse sort by row + std::sort (row_indexes.begin (), row_indexes.end (), row_is_higher); + for (auto index : row_indexes) + { + auto row = model_.mapFromSource (index).row (); + model_.removeRow (row); + self_->log_model_changed (); + } + } +} + AbstractLogWindow::AbstractLogWindow (QString const& settings_key, QSettings * settings , Configuration const * configuration , QWidget * parent) : QWidget {parent} - , m_ {settings_key, settings, configuration} + , m_ {this, settings_key, settings, configuration} { // ensure view scrolls to latest new row connect (&m_->model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) { @@ -45,18 +96,17 @@ AbstractLogWindow::~AbstractLogWindow () m_->settings_->setValue ("window/geometry", saveGeometry ()); } -void AbstractLogWindow::set_log_model (QAbstractItemModel * log_model) -{ - m_->model_.setSourceModel (log_model); -} - void AbstractLogWindow::set_log_view (QTableView * log_view) { // do this here because we know the UI must be setup before this SettingsGroup g {m_->settings_, m_->settings_key_}; restoreGeometry (m_->settings_->value ("window/geometry").toByteArray ()); - m_->log_view_ = log_view; + m_->log_view_->setContextMenuPolicy (Qt::ActionsContextMenu); + m_->log_view_->setAlternatingRowColors (true); + m_->log_view_->setSelectionBehavior (QAbstractItemView::SelectRows); + m_->log_view_->setSelectionMode (QAbstractItemView::ExtendedSelection); + m_->model_.setSourceModel (m_->log_view_->model ()); m_->log_view_->setModel (&m_->model_); m_->log_view_->setColumnHidden (0, true); auto horizontal_header = log_view->horizontalHeader (); @@ -65,6 +115,13 @@ void AbstractLogWindow::set_log_view (QTableView * log_view) m_->log_view_->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); set_log_view_font (m_->configuration_->decoded_text_font ()); m_->log_view_->scrollToBottom (); + + // actions + auto delete_action = new QAction {tr ("&Delete ..."), m_->log_view_}; + m_->log_view_->insertAction (nullptr, delete_action); + connect (delete_action, &QAction::triggered, [this] (bool /*checked*/) { + m_->delete_QSOs (); + }); } void AbstractLogWindow::set_log_view_font (QFont const& font) diff --git a/widgets/AbstractLogWindow.hpp b/widgets/AbstractLogWindow.hpp index 35d5d27cf..581212d82 100644 --- a/widgets/AbstractLogWindow.hpp +++ b/widgets/AbstractLogWindow.hpp @@ -7,10 +7,15 @@ class QString; class QSettings; class Configuration; -class QAbstractItemModel; class QTableView; class QFont; +// +// AbstractLogWindow - Base class for log view windows +// +// QWidget that manages the common functionality shared by windows +// that include a QSO log view. +// class AbstractLogWindow : public QWidget { @@ -20,11 +25,15 @@ public: , QWidget * parent = nullptr); virtual ~AbstractLogWindow () = 0; - void set_log_model (QAbstractItemModel *); + // set the QTableView that shows the log records, must have its + // model set before calling this void set_log_view (QTableView *); + void set_log_view_font (QFont const&); private: + virtual void log_model_changed (int row = -1) = 0; + class impl; pimpl m_; }; diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp index ab83a79f2..20f39e4e6 100644 --- a/widgets/CabrilloLogWindow.cpp +++ b/widgets/CabrilloLogWindow.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "Configuration.hpp" #include "models/Bands.hpp" #include "item_delegates/ForeignKeyDelegate.hpp" @@ -43,26 +44,44 @@ namespace class CabrilloLogWindow::impl final { public: - explicit impl () = default; + explicit impl (QSqlTableModel * log_model) + : log_model_ {log_model} + { + } + + QSqlTableModel * log_model_; FormatProxyModel format_model_; Ui::CabrilloLogWindow ui_; }; CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const * configuration - , QAbstractItemModel * cabrillo_log_model, QWidget * parent) + , QSqlTableModel * cabrillo_log_model, QWidget * parent) : AbstractLogWindow {"Cabrillo Log Window", settings, configuration, parent} + , m_{cabrillo_log_model} { setWindowTitle (QApplication::applicationName () + " - Cabrillo Log"); m_->ui_.setupUi (this); - m_->format_model_.setSourceModel (cabrillo_log_model); - set_log_model (&m_->format_model_); + m_->format_model_.setSourceModel (m_->log_model_); + m_->ui_.log_table_view->setModel (&m_->format_model_); set_log_view (m_->ui_.log_table_view); m_->ui_.log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); - m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), cabrillo_log_model, 0, 6, this}); + m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), m_->log_model_, 0, 6, this}); m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // band to first column } CabrilloLogWindow::~CabrilloLogWindow () { } + +void CabrilloLogWindow::log_model_changed (int row) +{ + if (row >= 0) + { + m_->log_model_->selectRow (row); + } + else + { + m_->log_model_->select (); + } +} diff --git a/widgets/CabrilloLogWindow.hpp b/widgets/CabrilloLogWindow.hpp index c0a964ce5..e2aa1627a 100644 --- a/widgets/CabrilloLogWindow.hpp +++ b/widgets/CabrilloLogWindow.hpp @@ -7,17 +7,19 @@ class QSettings; class Configuration; class QFont; -class QAbstractItemModel; +class QSqlTableModel; class CabrilloLogWindow final : public AbstractLogWindow { public: - explicit CabrilloLogWindow (QSettings *, Configuration const *, QAbstractItemModel * cabrillo_log_model + explicit CabrilloLogWindow (QSettings *, Configuration const *, QSqlTableModel * cabrillo_log_model , QWidget * parent = nullptr); ~CabrilloLogWindow (); private: + void log_model_changed (int row) override; + class impl; pimpl m_; }; diff --git a/widgets/CabrilloLogWindow.ui b/widgets/CabrilloLogWindow.ui index 43061f132..929b41a7b 100644 --- a/widgets/CabrilloLogWindow.ui +++ b/widgets/CabrilloLogWindow.ui @@ -6,7 +6,7 @@ 0 0 - 274 + 493 210 @@ -16,12 +16,6 @@ - - true - - - QAbstractItemView::SingleSelection - true diff --git a/widgets/FoxLogWindow.cpp b/widgets/FoxLogWindow.cpp index f5e7e517d..21029c73c 100644 --- a/widgets/FoxLogWindow.cpp +++ b/widgets/FoxLogWindow.cpp @@ -1,9 +1,14 @@ #include "FoxLogWindow.hpp" #include +#include +#include +#include +#include #include "SettingsGroup.hpp" #include "Configuration.hpp" +#include "MessageBox.hpp" #include "models/Bands.hpp" #include "item_delegates/ForeignKeyDelegate.hpp" #include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp" @@ -16,26 +21,47 @@ class FoxLogWindow::impl final { public: - explicit impl () = default; + explicit impl (QSqlTableModel * log_model) + : log_model_ {log_model} + { + } + + QSqlTableModel * log_model_; Ui::FoxLogWindow ui_; }; FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configuration - , QAbstractItemModel * fox_log_model, QWidget * parent) + , QSqlTableModel * fox_log_model, QWidget * parent) : AbstractLogWindow {"Fox Log Window", settings, configuration, parent} + , m_ {fox_log_model} { setWindowTitle (QApplication::applicationName () + " - Fox Log"); m_->ui_.setupUi (this); - set_log_model (fox_log_model); + m_->ui_.log_table_view->setModel (m_->log_model_); set_log_view (m_->ui_.log_table_view); m_->ui_.log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this}); - m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), fox_log_model, 0, 6, this}); + m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), m_->log_model_, 0, 6, this}); m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // move band to first column m_->ui_.rate_label->setNum (0); m_->ui_.queued_label->setNum (0); m_->ui_.callers_label->setNum (0); + + // actions + auto reset_action = new QAction {tr ("&Reset ..."), m_->ui_.log_table_view}; + m_->ui_.log_table_view->insertAction (nullptr, reset_action); + connect (reset_action, &QAction::triggered, [this, configuration] (bool /*checked*/) { + if (MessageBox::Yes == MessageBox::query_message( this + , tr ("Confirm Reset") + , tr ("Are you sure you want to erase file FoxQSO.txt " + "and start a new Fox log?"))) + { + QFile f{configuration->writeable_data_dir ().absoluteFilePath ("FoxQSO.txt")}; + f.remove (); + Q_EMIT reset_log_model (); + } + }); } FoxLogWindow::~FoxLogWindow () @@ -56,3 +82,15 @@ void FoxLogWindow::rate (int n) { m_->ui_.rate_label->setNum (n); } + +void FoxLogWindow::log_model_changed (int row) +{ + if (row >= 0) + { + m_->log_model_->selectRow (row); + } + else + { + m_->log_model_->select (); + } +} diff --git a/widgets/FoxLogWindow.hpp b/widgets/FoxLogWindow.hpp index d27ccdea6..65bcb0bd0 100644 --- a/widgets/FoxLogWindow.hpp +++ b/widgets/FoxLogWindow.hpp @@ -7,13 +7,15 @@ class QSettings; class Configuration; class QFont; -class QAbstractItemModel; +class QSqlTableModel; class FoxLogWindow final : public AbstractLogWindow { + Q_OBJECT + public: - explicit FoxLogWindow (QSettings *, Configuration const *, QAbstractItemModel * fox_log_model + explicit FoxLogWindow (QSettings *, Configuration const *, QSqlTableModel * fox_log_model , QWidget * parent = nullptr); ~FoxLogWindow (); @@ -21,7 +23,11 @@ public: void queued (int); void rate (int); + Q_SIGNAL void reset_log_model () const; + private: + void log_model_changed (int row) override; + class impl; pimpl m_; }; diff --git a/widgets/FoxLogWindow.ui b/widgets/FoxLogWindow.ui index 96ef8b112..0a9815478 100644 --- a/widgets/FoxLogWindow.ui +++ b/widgets/FoxLogWindow.ui @@ -6,21 +6,21 @@ 0 0 - 331 + 453 238 + + Qt::DefaultContextMenu + Fox Log - - true - - - QAbstractItemView::SingleSelection + + Qt::ActionsContextMenu true diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 895569942..18f6cee84 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -2419,6 +2419,10 @@ void MainWindow::on_fox_log_action_triggered() // Connect signals from fox log window connect (this, &MainWindow::finished, m_foxLogWindow.data (), &FoxLogWindow::close); + connect (m_foxLogWindow.data (), &FoxLogWindow::reset_log_model, [this] () { + if (!m_foxLog) m_foxLog.reset (new FoxLog); + m_foxLog->reset (); + }); } m_foxLogWindow->showNormal (); m_foxLogWindow->raise (); @@ -5332,7 +5336,6 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button default: break; } - using SpOp = Configuration::SpecialOperatingActivity; auto special_op = m_config.special_op_id (); if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) { @@ -5377,7 +5380,6 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, if (m_config.clear_DX () and SpecOp::HOUND != m_config.special_op_id()) clearDX (); m_dateTimeQSOOn = QDateTime {}; - using SpOp = Configuration::SpecialOperatingActivity; auto special_op = m_config.special_op_id (); if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) { @@ -6119,18 +6121,6 @@ void MainWindow::on_actionErase_ALL_TXT_triggered() //Erase ALL.TXT } } -void MainWindow::on_reset_fox_log_action_triggered () -{ - int ret = MessageBox::query_message(this, tr("Confirm Reset"), - tr("Are you sure you want to erase file FoxQSO.txt and start a new Fox log?")); - if(ret==MessageBox::Yes) { - QFile f{m_config.writeable_data_dir().absoluteFilePath("FoxQSO.txt")}; - f.remove(); - if (!m_foxLog) m_foxLog.reset (new FoxLog); - m_foxLog->reset (); - } -} - void MainWindow::on_reset_cabrillo_log_action_triggered () { if (MessageBox::Yes == MessageBox::query_message (this, tr ("Confirm Reset"), diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index e5b9de9a8..4cab787b5 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -204,7 +204,6 @@ private slots: void on_actionDeepestDecode_toggled (bool); void bumpFqso(int n); void on_actionErase_ALL_TXT_triggered(); - void on_reset_fox_log_action_triggered (); void on_reset_cabrillo_log_action_triggered (); void on_actionErase_wsjtx_log_adi_triggered(); void on_actionExport_Cabrillo_log_triggered(); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 8256eb606..21799434e 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -2653,7 +2653,6 @@ list. The list can be maintained in Settings (F2). - From 4334c997ee7526115733963323f3a27b6f4c87ea Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 25 Nov 2018 22:30:28 +0000 Subject: [PATCH 50/52] Add tool tips to log view windows --- widgets/CabrilloLogWindow.ui | 3 +++ widgets/FoxLogWindow.ui | 3 +++ 2 files changed, 6 insertions(+) diff --git a/widgets/CabrilloLogWindow.ui b/widgets/CabrilloLogWindow.ui index 929b41a7b..efefe5d3c 100644 --- a/widgets/CabrilloLogWindow.ui +++ b/widgets/CabrilloLogWindow.ui @@ -16,6 +16,9 @@ + + <html><head/><body><p>Right-click here for available actions.</p></body></html> + true diff --git a/widgets/FoxLogWindow.ui b/widgets/FoxLogWindow.ui index 0a9815478..cd224ed33 100644 --- a/widgets/FoxLogWindow.ui +++ b/widgets/FoxLogWindow.ui @@ -22,6 +22,9 @@ Qt::ActionsContextMenu + + <html><head/><body><p>Right-click here for available actions.</p></body></html> + true From 4dbba727ecaefd63439ec5b1a435134519bb8769 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Mon, 26 Nov 2018 01:42:57 +0000 Subject: [PATCH 51/52] Explicitly include MOC generated source --- widgets/FoxLogWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/widgets/FoxLogWindow.cpp b/widgets/FoxLogWindow.cpp index 21029c73c..0f96529aa 100644 --- a/widgets/FoxLogWindow.cpp +++ b/widgets/FoxLogWindow.cpp @@ -17,6 +17,7 @@ #include "pimpl_impl.hpp" #include "ui_FoxLogWindow.h" +#include "moc_FoxLogWindow.cpp" class FoxLogWindow::impl final { From cd8721f7e5bcf5e75a150fb4a3c9d9212b9f82c2 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 26 Nov 2018 10:21:18 -0500 Subject: [PATCH 52/52] Update the Release Notes for RC5. --- Release_Notes.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Release_Notes.txt b/Release_Notes.txt index 8c483f454..c2b2c711b 100644 --- a/Release_Notes.txt +++ b/Release_Notes.txt @@ -12,6 +12,31 @@ Copyright 2001 - 2018 by Joe Taylor, K1JT. + Release: WSJT-X 2.0-rc5 + November 26, 2018 + ----------------------- + +Release Candidate 5 ("RC5") is stable, works well, and fixes the known +problems in RC4. It is likely that the General Availability (GA) +release of WSJT-X 2.0 will be nearly identical to RC5. + +Changes from WSJT-X 2.0-rc4 include the following: + + - Make the "Auto Seq" checkbox sticky, again + - Remove the 5-minute mouse timer + - Correct the "worked before" logic for color highlighting + - Add "No own call decodes" checkbox in WSPR mode + - Display and log UTC (not local time) in contest operations + - Validate contest QSO details before allowing logging + - Force Aqua theme on macOS to avoid issues with Mojave dark theme + - Move Fox log Reset action to Fox log window context menu + - Improve layout of Working Frequencies and Station Information tables + - Allow deletes and editing in Fox and Contest log windows + - Add Tool Tips for Fox and Contest log windows + - Fix a bug causing false AP decodes in JT65 VHF+ operation + - Fix a bug that could switch unexpectedly from JT65 to JT9 mode + + Release: WSJT-X 2.0-rc4 November 12, 2018 -----------------------