diff --git a/CMakeLists.txt b/CMakeLists.txt index ec59d0ae2..788ee435c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ message (STATUS "******************************************************") include (set_build_type) # RC 0 or omitted is a development build, GA is a General Availability release build -set_build_type (RC 1) +set_build_type (RC 0) set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}") # @@ -126,7 +126,8 @@ option (WSJT_GENERATE_DOCS "Generate documentation files." ON) option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.") option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.") option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON) - +CMAKE_DEPENDENT_OPTION (WSJT_QDEBUG_IN_RELEASE "Leave Qt debugging statements in Release configuration." OFF + "NOT is_debug_build" OFF) CMAKE_DEPENDENT_OPTION (WSJT_ENABLE_EXPERIMENTAL_FEATURES "Enable features not fully ready for public releases." ON is_debug_build OFF) CMAKE_DEPENDENT_OPTION (WSJT_CREATE_WINMAIN @@ -336,6 +337,7 @@ set (wsjt_FSRCS lib/timer_module.f90 lib/wavhdr.f90 lib/qra/q65/q65_encoding_modules.f90 + lib/ft8/ft8_a7.f90 # remaining non-module sources lib/addit.f90 @@ -461,7 +463,6 @@ set (wsjt_FSRCS lib/inter_wspr.f90 lib/jplsubs.f lib/jt9fano.f90 - lib/jtmsg.f90 lib/libration.f90 lib/lorentzian.f90 lib/fst4/lorentzian_fading.f90 @@ -1448,7 +1449,7 @@ set_target_properties (wsjtx PROPERTIES ) target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS}) -if (APPLE) +if ((NOT ${OPENMP_FOUND}) OR APPLE) target_link_libraries (wsjtx wsjt_fort) else () target_link_libraries (wsjtx wsjt_fort_omp) diff --git a/Configuration.cpp b/Configuration.cpp index 7b78abed0..661a42d6e 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -593,6 +593,7 @@ private: bool highlight_by_mode_; bool highlight_only_fields_; bool include_WAE_entities_; + bool highlight_73_; int LotW_days_since_upload_; TransceiverFactory::ParameterPack rig_params_; @@ -670,6 +671,10 @@ private: bool bLowSidelobes_; bool pwrBandTxMemory_; bool pwrBandTuneMemory_; + bool highlight_DXcall_; + bool clear_DXcall_; + bool highlight_DXgrid_; + bool clear_DXgrid_; QAudioDeviceInfo audio_input_device_; QAudioDeviceInfo next_audio_input_device_; @@ -787,6 +792,11 @@ DecodeHighlightingModel const& Configuration::decode_highlighting () const {retu bool Configuration::highlight_by_mode () const {return m_->highlight_by_mode_;} bool Configuration::highlight_only_fields () const {return m_->highlight_only_fields_;} bool Configuration::include_WAE_entities () const {return m_->include_WAE_entities_;} +bool Configuration::highlight_73 () const {return m_->highlight_73_;} +bool Configuration::highlight_DXcall () const {return m_->highlight_DXcall_;} +bool Configuration::clear_DXcall () const {return m_->clear_DXcall_;} +bool Configuration::highlight_DXgrid () const {return m_->highlight_DXgrid_;} +bool Configuration::clear_DXgrid () const {return m_->clear_DXgrid_;} void Configuration::set_calibration (CalibrationParams params) { @@ -920,6 +930,30 @@ void Configuration::set_location (QString const& grid_descriptor) m_->dynamic_grid_ = grid_descriptor.trimmed (); } +void Configuration::setSpecial_Hound() +{ + m_->bSpecialOp_=true; + m_->ui_->gbSpecialOpActivity->setChecked(m_->bSpecialOp_); + m_->ui_->rbHound->setChecked(true); + m_->SelectedActivity_ = static_cast (SpecialOperatingActivity::HOUND); + m_->write_settings(); +} + +void Configuration::setSpecial_Fox() +{ + m_->bSpecialOp_=true; + m_->ui_->gbSpecialOpActivity->setChecked(m_->bSpecialOp_); + m_->ui_->rbFox->setChecked(true); + m_->SelectedActivity_ = static_cast (SpecialOperatingActivity::FOX); + m_->write_settings(); +} + +void Configuration::setSpecial_None() +{ + m_->bSpecialOp_=false; + m_->ui_->gbSpecialOpActivity->setChecked(m_->bSpecialOp_); + m_->write_settings(); +} namespace { #if defined (Q_OS_MAC) @@ -984,6 +1018,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network , highlight_by_mode_ {false} , highlight_only_fields_ {false} , include_WAE_entities_ {false} + , highlight_73_ {false} , LotW_days_since_upload_ {0} , last_port_type_ {TransceiverFactory::Capabilities::none} , rig_is_dummy_ {false} @@ -1397,7 +1432,12 @@ void Configuration::impl::initialize_models () ui_->highlight_by_mode_check_box->setChecked (highlight_by_mode_); ui_->only_fields_check_box->setChecked (highlight_only_fields_); ui_->include_WAE_check_box->setChecked (include_WAE_entities_); + ui_->highlight_73_check_box->setChecked (highlight_73_); ui_->LotW_days_since_upload_spin_box->setValue (LotW_days_since_upload_); + ui_->cbHighlightDXcall->setChecked(highlight_DXcall_); + ui_->cbClearDXcall->setChecked(clear_DXcall_); + ui_->cbHighlightDXgrid->setChecked(highlight_DXgrid_); + ui_->cbClearDXgrid->setChecked(clear_DXgrid_); set_rig_invariants (); } @@ -1492,6 +1532,7 @@ void Configuration::impl::read_settings () highlight_by_mode_ = settings_->value("HighlightByMode", false).toBool (); highlight_only_fields_ = settings_->value("OnlyFieldsSought", false).toBool (); include_WAE_entities_ = settings_->value("IncludeWAEEntities", false).toBool (); + highlight_73_ = settings_->value("Highlight73", false).toBool (); LotW_days_since_upload_ = settings_->value ("LotWDaysSinceLastUpload", 365).toInt (); lotw_users_.set_age_constraint (LotW_days_since_upload_); @@ -1554,6 +1595,10 @@ void Configuration::impl::read_settings () calibration_.slope_ppm = settings_->value ("CalibrationSlopePPM", 0.).toDouble (); pwrBandTxMemory_ = settings_->value("pwrBandTxMemory",false).toBool (); pwrBandTuneMemory_ = settings_->value("pwrBandTuneMemory",false).toBool (); + highlight_DXcall_ = settings_->value("highlight_DXcall",false).toBool (); + clear_DXcall_ = settings_->value("clear_DXcall",false).toBool (); + highlight_DXgrid_ = settings_->value("highlight_DXgrid",false).toBool (); + clear_DXgrid_ = settings_->value("clear_DXgrid",false).toBool (); } void Configuration::impl::find_audio_devices () @@ -1626,6 +1671,7 @@ void Configuration::impl::write_settings () settings_->setValue ("HighlightByMode", highlight_by_mode_); settings_->setValue ("OnlyFieldsSought", highlight_only_fields_); settings_->setValue ("IncludeWAEEntities", include_WAE_entities_); + settings_->setValue ("Highlight73", highlight_73_); settings_->setValue ("LotWDaysSinceLastUpload", LotW_days_since_upload_); settings_->setValue ("toRTTY", log_as_RTTY_); settings_->setValue ("dBtoComments", report_in_comments_); @@ -1685,6 +1731,10 @@ void Configuration::impl::write_settings () settings_->setValue ("pwrBandTuneMemory", pwrBandTuneMemory_); settings_->setValue ("Region", QVariant::fromValue (region_)); settings_->setValue ("AutoGrid", use_dynamic_grid_); + settings_->setValue ("highlight_DXcall", highlight_DXcall_); + settings_->setValue ("clear_DXcall", clear_DXcall_); + settings_->setValue ("highlight_DXgrid", highlight_DXgrid_); + settings_->setValue ("clear_DXgrid", clear_DXgrid_); settings_->sync (); } @@ -2163,6 +2213,7 @@ void Configuration::impl::accept () highlight_by_mode_ = ui_->highlight_by_mode_check_box->isChecked (); highlight_only_fields_ = ui_->only_fields_check_box->isChecked (); include_WAE_entities_ = ui_->include_WAE_check_box->isChecked (); + highlight_73_ = ui_->highlight_73_check_box->isChecked (); LotW_days_since_upload_ = ui_->LotW_days_since_upload_spin_box->value (); lotw_users_.set_age_constraint (LotW_days_since_upload_); @@ -2172,6 +2223,10 @@ void Configuration::impl::accept () dynamic_grid_.clear (); } use_dynamic_grid_ = ui_->use_dynamic_grid->isChecked(); + highlight_DXcall_ = ui_->cbHighlightDXcall->isChecked(); + clear_DXcall_ = ui_->cbClearDXcall->isChecked(); + highlight_DXgrid_ = ui_->cbHighlightDXgrid->isChecked(); + clear_DXgrid_ = ui_->cbClearDXgrid->isChecked(); write_settings (); // make visible to all } diff --git a/Configuration.hpp b/Configuration.hpp index b0f6bf75b..c4cf068ec 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -181,6 +181,14 @@ public: bool highlight_by_mode () const; bool highlight_only_fields () const; bool include_WAE_entities () const; + bool highlight_73 () const; + void setSpecial_Hound(); + void setSpecial_Fox(); + void setSpecial_None(); + bool highlight_DXcall () const; + bool clear_DXcall () const; + bool highlight_DXgrid () const; + bool clear_DXgrid () const; enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, FOX, HOUND}; SpecialOperatingActivity special_op_id () const; diff --git a/Configuration.ui b/Configuration.ui index 17fd1a326..c538b0be6 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -7,7 +7,7 @@ 0 0 554 - 560 + 599 @@ -181,29 +181,6 @@ - - - - Show if decoded stations are new DXCC entities or worked before. - - - Show &DXCC, grid, and worked-before status - - - false - - - - - - - <html><head/><body><p>Check to have decodes for a new period start at the top of the Band Activity window and not scroll off the top when the window is full.</p><p>This is to aid selecting decodes to double-click while decoding is still in progress. Use the Band Activity vertical scroll bar to reveal decodes past the bottom of the window.</p></body></html> - - - Start new period decodes at top - - - @@ -265,13 +242,10 @@ - - - - Include a separator line between periods in the band activity window. - + + - &Blank line between decoding periods + Highlight DX Call in message @@ -285,6 +259,60 @@ + + + + Show if decoded stations are new DXCC entities or worked before. + + + Show &DXCC, grid, and worked-before status + + + false + + + + + + + <html><head/><body><p>Check to have decodes for a new period start at the top of the Band Activity window and not scroll off the top when the window is full.</p><p>This is to aid selecting decodes to double-click while decoding is still in progress. Use the Band Activity vertical scroll bar to reveal decodes past the bottom of the window.</p></body></html> + + + Start new period decodes at top + + + + + + + Clear DX Grid after QSO + + + + + + + Include a separator line between periods in the band activity window. + + + &Blank line between decoding periods + + + + + + + Highlight DX Grid in message + + + + + + + Clear DX Call after QSO + + + @@ -2302,6 +2330,23 @@ Right click for insert and delete options. + + + + Include extra WAE entities + + + + + + + Check to for grid highlighting to only apply to unworked grid fields + + + Only grid Fields sought + + + @@ -2349,20 +2394,10 @@ Right click for insert and delete options. - - + + - Include extra WAE entities - - - - - - - Check to for grid highlighting to only apply to unworked grid fields - - - Only grid Fields sought + Highlight also messages with 73 or RR73 @@ -3233,13 +3268,13 @@ Right click for insert and delete options. + + + - - - - - + + diff --git a/Radio.cpp b/Radio.cpp index ed4bf388d..5ee290406 100644 --- a/Radio.cpp +++ b/Radio.cpp @@ -54,7 +54,7 @@ namespace Radio value *= std::pow (10., scale); if (ok) { - if (value < 0. || value > std::numeric_limits::max ()) + if (value < 0. || value > static_cast(std::numeric_limits::max ())) { value = 0.; *ok = false; @@ -91,8 +91,8 @@ namespace Radio value *= std::pow (10., scale); if (ok) { - if (value < -std::numeric_limits::max () - || value > std::numeric_limits::max ()) + if (value < static_cast(std::numeric_limits::min ()) + || value > static_cast(std::numeric_limits::max ())) { value = 0.; *ok = false; diff --git a/cty.dat b/cty.dat index 843e99b03..bdba2c705 100644 --- a/cty.dat +++ b/cty.dat @@ -2445,7 +2445,7 @@ Corsica: 15: 28: EU: 42.00: -9.00: -1.0: TK: Central African Republic: 36: 47: AF: 6.75: -20.33: -1.0: TL: TL; Republic of the Congo: 36: 52: AF: -1.02: -15.37: -1.0: TN: - TN; + TN0,TN1,TN2,TN3,TN4,TN5,TN6,TN7,TN8,TN9; Gabon: 36: 52: AF: -0.37: -11.73: -1.0: TR: TR; Chad: 36: 47: AF: 15.80: -18.17: -1.0: TT: @@ -3376,7 +3376,7 @@ Indonesia: 28: 51: OC: -7.30: -109.88: -7.0: YB: 8D8[54],8E8[54],8F8[54],8G8[54],8H8[54],8I8[54],YB8[54],YC8[54],YD8[54],YE8[54],YF8[54],YG8[54], YH8[54]; Iraq: 21: 39: AS: 33.92: -42.78: -3.0: YI: - HN,YI,=K4CY/M,=YI1IRQ/ND; + HN0,HN1,HN2,HN3,HN4,HN5,HN6,HN7,HN8,HN9,YI,=K4CY/M,=YI1IRQ/ND; Vanuatu: 32: 56: OC: -17.67: -168.38: -11.0: YJ: YJ; Syria: 20: 39: AS: 35.38: -38.20: -2.0: YK: diff --git a/doc/user_guide/en/make-qso.adoc b/doc/user_guide/en/make-qso.adoc index c48d5f741..43f2b48f5 100644 --- a/doc/user_guide/en/make-qso.adoc +++ b/doc/user_guide/en/make-qso.adoc @@ -144,7 +144,7 @@ station's log and not the supposed QSO partner's. To avoid Not-in-Log (NIL) penalties for yourself and others, we recommend the following guidelines for contest logging with FT4, FT8, and MSK144: - - Activate and learn to use the alternate F1-F6 bindings selectable + - Activate and learn to use the *Alternate F1-F6 bindings* selectable on the *Settings | General* tab. - Always log a QSO when you have received RRR, RR73, or 73 from a @@ -153,8 +153,9 @@ guidelines for contest logging with FT4, FT8, and MSK144: - Log a QSO when you send RR73 or 73 if you are reasonably confident it will be copied. But be sure to watch for any indication that it was not copied, and then take appropriate action. For example, if - you receive the Tx3 message (R plus contest exchange) again, hit F4 - to re-send your RR73. + you receive the Tx3 message (R plus contest exchange) again, and if + you have activated the *Alternate F1-F6 bindings*, hit *F4* to + re-send your RR73. [[COMP-CALL]] === Nonstandard Callsigns diff --git a/lib/77bit/packjt77.f90 b/lib/77bit/packjt77.f90 index 23d4bdb87..8fc575f0c 100644 --- a/lib/77bit/packjt77.f90 +++ b/lib/77bit/packjt77.f90 @@ -830,7 +830,9 @@ subroutine split77(msg,nwords,nw,w) iz=j !Message length nwords=k !Number of words in msg if(nwords.le.0) go to 900 - nw(k)=len(trim(w(k))) + do i=1,nwords + nw(i)=len(trim(w(i))) + enddo msg(iz+1:)=' ' if(nwords.lt.3) go to 900 call chkcall(w(3),bcall_1,ok1) @@ -839,7 +841,7 @@ subroutine split77(msg,nwords,nw,w) w(2:12)=w(3:13) !Move all remaining words down by one nwords=nwords-1 endif - + 900 return end subroutine split77 diff --git a/lib/chkcall.f90 b/lib/chkcall.f90 index 23900748e..944cfeeb8 100644 --- a/lib/chkcall.f90 +++ b/lib/chkcall.f90 @@ -34,7 +34,9 @@ subroutine chkcall(w,bc,cok) ! One of first two characters (c1 or c2) must be a letter if((.not.isletter(bc(1:1))) .and. (.not.isletter(bc(2:2)))) go to 100 - if(bc(1:1).eq.'Q') go to 100 !Calls don't start with Q +! Real calls don't start with Q, but we'll allow the placeholder +! callsign QU1RK to be considered a standard call: + if(bc(1:1).eq.'Q' .and. bc(1:5).ne.'QU1RK') go to 100 ! Must have a digit in 2nd or 3rd position i1=0 diff --git a/lib/ft8/chkdec.f90 b/lib/ft8/chkdec.f90 new file mode 100644 index 000000000..7a5e7618a --- /dev/null +++ b/lib/ft8/chkdec.f90 @@ -0,0 +1,161 @@ +program chkdec + + parameter(NMAX=100) + character*88 line + character*37 msg(NMAX),msg0,msg1 + character*2 c2(NMAX) + character*1 c1(NMAX) + character*1 only + integer nsnr(NMAX,0:1),nf(NMAX,0:1) + real dt(NMAX,0:1) + logical found,eof + +! These files are sorted by freq within each Rx sequence + open(10,file='all.wsjtx',status='old') + open(11,file='all.jtdx',status='old') + write(20,1030) +1030 format(' iseq B w j W W+ J E B w j W', & + ' W+ J E'/80('-')) + + nutc0=-1 + nbt=0 !Both + nwt=0 !WSJT-X only + njt=0 !JTDX only + net=0 !Either + n7t=0 !a7 + eof=.false. + + do iseq=1,9999 + j=0 + msg=' ' + nsnr=-99 + nf=-99 + dt=-99 + c1=' ' + c2=' ' + do i=1,NMAX + read(10,'(a88)',end=8) line !Read from the WSJT-X file + if(line(25:30).ne.'Rx FT8') cycle !Ignore any line not an FT8 decode + read(line(8:13),*) nutc + if(nutc0.lt.0) nutc0=nutc !First time only + if(nutc.ne.nutc0) then + backspace(10) + go to 10 !Finished WSJT-X for this sequence + endif + j=j+1 + if(j.eq.1) then + nf(j,0)=-1 + j=j+1 + endif + read(line,1001) nsnr(j,0),dt(j,0),nf(j,0),msg(j),c2(j) +1001 format(30x,i7,f5.1,i5,1x,a36,2x,a2) +! if(nutc.eq.180215 .and. c2(j).eq.'a7') print*,'aaa',j,nf(j,0),c2(j) + nutc0=nutc + enddo ! i + +8 eof=.true. +10 jz=j + do i=1,NMAX + read(11,'(a88)',end=20) line !Read from the JTDX file + if(line(31:31).ne.'~') cycle !Ignore any line not an FT8 decode + read(line(10:15),*) nutc + if(nutc.ne.nutc0) then + backspace(11) + go to 20 !Finished JTDX for this sequence + endif + msg1=line(33:58) + read(line(25:29),*) nf1 + found=.false. + do j=1,jz + if(msg(j).eq.msg1) then + read(line,1002) nsnr(j,1),dt(j,1),nf(j,1),c1(j) +1002 format(15x,i4,f5.1,i5,29x,a1) + found=.true. + exit + endif + i1=index(msg(j),'<') + if(i1.gt.0) then + i2=index(msg(j),'>') + msg0=msg(j)(1:i1-1)//msg(j)(i1+1:i2-1)//msg(j)(i2+1:) + if(msg0.eq.msg1) then + read(line,1002) nsnr(j,1),dt(j,1),nf(j,1),c1(j) + found=.true. + exit + endif + endif + enddo ! j + + if(.not.found) then !Insert this one as a new message + do j=1,jz + if(nf1.ge.nf(j,0) .and. nf1.lt.nf(j+1,0)) then + jj=j+1 + exit + endif + enddo + do j=jz+1,jj+1,-1 + nsnr(j,0)=nsnr(j-1,0) + dt(j,0)=dt(j-1,0) + nf(j,0)=nf(j-1,0) + msg(j)=msg(j-1) + c1(j)=c1(j-1) + c2(j)=c2(j-1) + enddo ! j + read(line,1004) nsnr(jj,1),dt(jj,1),nf(jj,1),msg(jj),c1(jj) +1004 format(15x,i4,f5.1,i5,3x,a26,a1) + c2(jj)=' ' + nsnr(jj,0)=-99 + dt(jj,0)=-99.0 + nf(jj,0)=-99 + jz=jz+1 + endif + enddo ! i + +20 nb=0 + nw=0 + nj=0 + ne=0 + n7=0 + do j=2,jz + write(line,1020) nutc0,j,nsnr(j,:),dt(j,:),nf(j,:),msg(j)(1:26), & + c2(j),c1(j) +1020 format(i6.6,i3,1x,2i4,1x,2f6.1,1x,2i5,1x,a26,1x,a2,1x,a1) + if(c2(j).eq.'a7') n7=n7+1 + only=' ' + if(line(12:14).eq.'-99') then + line(12:14)=' ' + only='j' + nj=nj+1 +! if(c2(j).eq.'a7') print*,'aaa ',trim(line) + endif + if(line(16:18).eq.'-99') then + line(16:18)=' ' + only='w' + nw=nw+1 + endif + if(line(12:14).ne.' ' .or. line(16:19).ne.' ') ne=ne+1 + if(line(12:14).ne.' ' .and. line(16:19).ne.' ') nb=nb+1 + if(line(21:25).eq.'-99.0') line(21:25)=' ' + if(line(27:31).eq.'-99.0') line(27:31)=' ' + if(line(35:37).eq.'-99') line(35:37)=' ' + if(line(40:42).eq.'-99') line(40:42)=' ' +! if(line(12:14).ne.' ') nw=nw+1 +! if(line(16:18).ne.' ') nj=nj+1 + write(*,'(a74,1x,a1)') line(1:74),only + enddo ! j + + nbt=nbt+nb + nwt=nwt+nw + n7t=n7t+n7 + njt=njt+nj + net=net+ne + nutc0=nutc + write(*,*) + + write(20,1031) iseq,nb,nw,nj,nb+nw-n7,nb+nw,nb+nj,ne,nbt,nwt,njt, & + nbt+nwt-n7t,nbt+nwt,nbt+njt,net +1031 format(i5,2x,7i4,2x,7i6) + if(eof) exit +! if(iseq.eq.2) exit + enddo ! iseq + +end program chkdec diff --git a/lib/ft8/ft8_a7.f90 b/lib/ft8/ft8_a7.f90 new file mode 100644 index 000000000..7306c8021 --- /dev/null +++ b/lib/ft8/ft8_a7.f90 @@ -0,0 +1,378 @@ +module ft8_a7 + + parameter(MAXDEC=100) + +! For the following three arrays +! First index i=decode number in this sequence +! Second index j=0 or 1 for even or odd sequence +! Third index k=0 or 1 for previous or current tally for this j + real dt0(MAXDEC,0:1,0:1) !dt0(i,j,k) + real f0(MAXDEC,0:1,0:1) !f0(i,j,k) + character*37 msg0(MAXDEC,0:1,0:1) !msg0(i,j,k) + + integer itone_a7(79) + integer jseq !even=0, odd=1 + integer ndec(0:1,0:1) !ndec(j,k) + data ndec/4*0/,jseq/0/ + +contains + +subroutine ft8_a7_save(nutc,dt,f,msg) + + use packjt77 + character*37 msg,msg1 + character*13 w(19) + character*4 g4 + integer nw(19) + logical isgrid4 + +! Statement function: + isgrid4(g4)=(len_trim(g4).eq.4 .and. & + ichar(g4(1:1)).ge.ichar('A') .and. ichar(g4(1:1)).le.ichar('R') .and. & + ichar(g4(2:2)).ge.ichar('A') .and. ichar(g4(2:2)).le.ichar('R') .and. & + ichar(g4(3:3)).ge.ichar('0') .and. ichar(g4(3:3)).le.ichar('9') .and. & + ichar(g4(4:4)).ge.ichar('0') .and. ichar(g4(4:4)).le.ichar('9')) + + if(index(msg,'/').ge.1 .or. index(msg,'<').ge.1) go to 999 + call split77(msg,nwords,nw,w) !Parse msg into words + if(nwords.lt.1) go to 999 + if(w(1)(1:3).eq.'CQ_') go to 999 + j=mod(nutc/5,2) !j is 0 or 1 for odd/even sequence + jseq=j + +! Add this decode to current table for this sequence + ndec(j,1)=ndec(j,1)+1 !Number of decodes in this sequence + i=ndec(j,1) !i is index of a new table entry + if(i.ge.MAXDEC-1) return !Prevent table overflow + + dt0(i,j,1)=dt !Save dt in table + f0(i,j,1)=f !Save f in table + msg0(i,j,1)=trim(w(1))//' '//trim(w(2)) !Save "call_1 call_2" + if(w(1)(1:3).eq.'CQ ' .and. nw(2).le.2) then + msg0(i,j,1)='CQ '//trim(w(2))//' '//trim(w(3)) !Save "CQ DX Call_2" + endif + msg1=msg0(i,j,1) !Message without grid + nn=len(trim(msg1)) !Message length without grid +! Include grid as part of message + if(isgrid4(w(nwords))) msg0(i,j,1)=trim(msg0(i,j,1))//' '//trim(w(nwords)) + +! If a transmission at this frequency with message fragment "call_1 call_2" +! was decoded in the previous sequence, flag it as "DO NOT USE" because +! we have already decoded and subtracted that station's next transmission. + + call split77(msg0(i,j,1),nwords,nw,w) !Parse msg into words + do i=1,ndec(j,0) + if(f0(i,j,0).le.-98.0) cycle + i2=index(msg0(i,j,0),' '//trim(w(2))) + if(abs(f-f0(i,j,0)).le.3.0 .and. i2.ge.3) then + f0(i,j,0)=-98.0 !Flag as "do not use" for a potential a7 decode + endif + enddo + +999 return +end subroutine ft8_a7_save + +subroutine ft8_a7d(dd0,newdat,call_1,call_2,grid4,xdt,f1,xbase,nharderrors,dmin, & + msg37,xsnr) + +! Examine the raw data in dd0() for possible "a7" decodes. + + use crc + use timer_module, only: timer + use packjt77 + include 'ft8_params.f90' + parameter(NP2=2812) + character*37 msg37,msg,msgsent,msgbest + character*12 call_1,call_2 + character*4 grid4 + real a(5) + real s8(0:7,NN) + real s2(0:511) + real dmm(206) + real bmeta(174),bmetb(174),bmetc(174),bmetd(174) + real llra(174),llrb(174),llrc(174),llrd(174) !Soft symbols + real dd0(15*12000) + real ss(9) + real rcw(174) + integer*1 cw(174) + integer*1 msgbits(77) + integer*1 nxor(174),hdec(174) + integer itone(NN) + integer icos7(0:6),ip(1) + logical one(0:511,0:8) + integer graymap(0:7) + integer iloc(1) + complex cd0(0:3199) + complex ctwk(32) + complex csymb(32) + complex cs(0:7,NN) + logical std_1,std_2 + logical first,newdat + data icos7/3,1,4,0,6,5,2/ !Sync array + data first/.true./ + data graymap/0,1,3,2,5,6,4,7/ + save one + + if(first) then + one=.false. + do i=0,511 + do j=0,8 + if(iand(i,2**j).ne.0) one(i,j)=.true. + enddo + enddo + first=.false. + endif + + call stdcall(call_1,std_1) + if(call_1(1:3).eq.'CQ ') std_1=.true. + call stdcall(call_2,std_2) + + fs2=12000.0/NDOWN + dt2=1.0/fs2 + twopi=8.0*atan(1.0) + delfbest=0. + ibest=0 + + call timer('ft8_down',0) + call ft8_downsample(dd0,newdat,f1,cd0) !Mix f1 to baseband and downsample + call timer('ft8_down',1) + + i0=nint((xdt+0.5)*fs2) !Initial guess for start of signal + smax=0.0 + do idt=i0-10,i0+10 !Search over +/- one quarter symbol + call sync8d(cd0,idt,ctwk,0,sync) !NB: ctwk not used here + if(sync.gt.smax) then + smax=sync + ibest=idt + endif + enddo + +! Peak up in frequency + smax=0.0 + do ifr=-5,5 !Search over +/- 2.5 Hz + delf=ifr*0.5 + dphi=twopi*delf*dt2 + phi=0.0 + do i=1,32 + ctwk(i)=cmplx(cos(phi),sin(phi)) + phi=mod(phi+dphi,twopi) + enddo + call sync8d(cd0,ibest,ctwk,1,sync) + if( sync .gt. smax ) then + smax=sync + delfbest=delf + endif + enddo + a=0.0 + a(1)=-delfbest + call twkfreq1(cd0,NP2,fs2,a,cd0) + f1=f1+delfbest !Improved estimate of DF + + call timer('ft8_down',0) + call ft8_downsample(dd0,.false.,f1,cd0) !Mix f1 to baseband and downsample + call timer('ft8_down',1) + + smax=0.0 + do idt=-4,4 !Search over +/- one quarter symbol + call sync8d(cd0,ibest+idt,ctwk,0,sync) + ss(idt+5)=sync + enddo + smax=maxval(ss) + iloc=maxloc(ss) + ibest=iloc(1)-5+ibest + xdt=(ibest-1)*dt2 - 0.5 + sync=smax + + do k=1,NN + i1=ibest+(k-1)*32 + csymb=cmplx(0.0,0.0) + if( i1.ge.0 .and. i1+31 .le. NP2-1 ) csymb=cd0(i1:i1+31) + call four2a(csymb,32,1,-1,1) + cs(0:7,k)=csymb(1:8)/1e3 + s8(0:7,k)=abs(csymb(1:8)) + enddo + +! sync quality check + is1=0 + is2=0 + is3=0 + do k=1,7 + ip=maxloc(s8(:,k)) + if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1 + ip=maxloc(s8(:,k+36)) + if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1 + ip=maxloc(s8(:,k+72)) + if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1 + enddo +! hard sync sum - max is 21 + nsync=is1+is2+is3 +! if(nsync .le. 6) return ! bail out + + do nsym=1,3 + nt=2**(3*nsym) + do ihalf=1,2 + do k=1,29,nsym + if(ihalf.eq.1) ks=k+7 + if(ihalf.eq.2) ks=k+43 + amax=-1.0 + do i=0,nt-1 + i1=i/64 + i2=iand(i,63)/8 + i3=iand(i,7) + if(nsym.eq.1) then + s2(i)=abs(cs(graymap(i3),ks)) + elseif(nsym.eq.2) then + s2(i)=abs(cs(graymap(i2),ks)+cs(graymap(i3),ks+1)) + elseif(nsym.eq.3) then + s2(i)=abs(cs(graymap(i1),ks)+cs(graymap(i2),ks+1)+cs(graymap(i3),ks+2)) + else + print*,"Error - nsym must be 1, 2, or 3." + endif + enddo + i32=1+(k-1)*3+(ihalf-1)*87 + if(nsym.eq.1) ibmax=2 + if(nsym.eq.2) ibmax=5 + if(nsym.eq.3) ibmax=8 + do ib=0,ibmax + bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - & + maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)) + if(i32+ib .gt.174) cycle + if(nsym.eq.1) then + bmeta(i32+ib)=bm + den=max(maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)), & + maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib))) + if(den.gt.0.0) then + cm=bm/den + else ! erase it + cm=0.0 + endif + bmetd(i32+ib)=cm + elseif(nsym.eq.2) then + bmetb(i32+ib)=bm + elseif(nsym.eq.3) then + bmetc(i32+ib)=bm + endif + enddo + enddo + enddo + enddo + call normalizebmet(bmeta,174) + call normalizebmet(bmetb,174) + call normalizebmet(bmetc,174) + call normalizebmet(bmetd,174) + + scalefac=2.83 + llra=scalefac*bmeta + llrb=scalefac*bmetb + llrc=scalefac*bmetc + llrd=scalefac*bmetd + +! apmag=maxval(abs(llra))*1.01 + + MAXMSG=206 + pbest=0. + dmin=1.e30 + nharderrors=-1 + + do imsg=1,MAXMSG + msg=trim(call_1)//' '//trim(call_2) + i=imsg + if(call_1(1:3).eq.'CQ ' .and. i.ne.5) msg='QU1RK '//trim(call_2) + if(.not.std_1) then + if(i.eq.1 .or. i.ge.6) msg='<'//trim(call_1)//'> '//trim(call_2) + if(i.ge.2 .and. i.le.4) msg=trim(call_1)//' <'//trim(call_2)//'>' + else if(.not.std_2) then + if(i.le.4 .or. i.eq.6) msg='<'//trim(call_1)//'> '//trim(call_2) + if(i.ge.7) msg=trim(call_1)//' <'//trim(call_2)//'>' + endif + j0=len(trim(msg))+2 + if(i.eq.2) msg(j0:j0+2)='RRR' + if(i.eq.3) msg(j0:j0+3)='RR73' + if(i.eq.4) msg(j0:j0+1)='73' + if(i.eq.5) then + if(std_2) then + msg='CQ '//trim(call_2) + if(call_1(3:3).eq.'_') msg=trim(call_1)//' '//trim(call_2) + if(grid4.ne.'RR73') msg=trim(msg)//' '//grid4 + endif + if(.not.std_2) msg='CQ '//trim(call_2) + endif + if(i.eq.6 .and. std_2) msg(j0:j0+3)=grid4 + if(i.ge.7) then + isnr = -50 + (i-7)/2 + if(iand(i,1).eq.1) then + write(msg(j0:j0+2),'(i3.2)') isnr + if(msg(j0:j0).eq.' ') msg(j0:j0)='+' + else + write(msg(j0:j0+3),'("R",i3.2)') isnr + if(msg(j0+1:j0+1).eq.' ') msg(j0+1:j0+1)='+' + endif + endif + + i3=-1 + n3=-1 + call genft8(msg,i3,n3,msgsent,msgbits,itone) !Source-encode this message + call encode174_91(msgbits,cw) !Get codeword for this message + rcw=2*cw-1 + pow=0.0 + do i=1,79 + pow=pow+s8(itone(i),i)**2 + enddo + + hdec=0 + where(llra.ge.0.0) hdec=1 + nxor=ieor(hdec,cw) + da=sum(nxor*abs(llra)) + + hdec=0 + where(llrb.ge.0.0) hdec=1 + nxor=ieor(hdec,cw) + dbb=sum(nxor*abs(llrb)) + + hdec=0 + where(llrc.ge.0.0) hdec=1 + nxor=ieor(hdec,cw) + dc=sum(nxor*abs(llrc)) + + hdec=0 + where(llrd.ge.0.0) hdec=1 + nxor=ieor(hdec,cw) + dd=sum(nxor*abs(llrd)) + + dm=min(da,dbb,dc,dd) + dmm(imsg)=dm + if(dm.lt.dmin) then + dmin=dm + msgbest=msgsent + pbest=pow + if(dm.eq.da) then + nharderrors=count((2*cw-1)*llra.lt.0.0) + else if(dm.eq.dbb) then + nharderrors=count((2*cw-1)*llrb.lt.0.0) + else if(dm.eq.dc) then + nharderrors=count((2*cw-1)*llrc.lt.0.0) + else if(dm.eq.dd) then + nharderrors=count((2*cw-1)*llrd.lt.0.0) + endif + endif + + enddo ! imsg + + iloc=minloc(dmm) + dmm(iloc(1))=1.e30 + iloc=minloc(dmm) + dmin2=dmm(iloc(1)) + xsnr=-24. + arg=pbest/xbase/3.0e6-1.0 + if(arg.gt.0.0) xsnr=db(arg)-27.0 +! write(41,3041) nharderrors,dmin,dmin2,dmin2/dmin,xsnr,trim(msgbest) +!3041 format(i3,2f7.1,f7.2,f7.1,1x,a) + if(dmin.gt.100.0 .or. dmin2/dmin.lt.1.3) nharderrors=-1 + msg37=msgbest + if(msg37(1:3).eq.'CQ ' .and. std_2 .and. grid4.eq.' ') nharderrors=-1 + if(msg37(1:6).eq.'QU1RK ') nharderrors=-1 + + return +end subroutine ft8_a7d + +end module ft8_a7 diff --git a/lib/ft8/ft8c.f90 b/lib/ft8/ft8c.f90 new file mode 100644 index 000000000..a7d1ccb90 --- /dev/null +++ b/lib/ft8/ft8c.f90 @@ -0,0 +1,261 @@ +subroutine ft8c(dd0,newdat,call_1,call_2,grid4,xdt,f1,nharderrors,dmin, & + msg37,xsnr) + + use crc + use timer_module, only: timer + use packjt77 + include 'ft8_params.f90' + parameter(NP2=2812) + character*37 msg37,msg,msgsent,msgbest + character*12 call_1,call_2 + character*4 grid4 + real a(5) + real s8(0:7,NN) + real s2(0:511) + real bmeta(174),bmetb(174),bmetc(174),bmetd(174) + real llra(174),llrb(174),llrc(174),llrd(174),llrbest(174) !Soft symbols + real dd0(15*12000) + real ss(9) + real rcw(174) + integer*1 cw(174) + integer*1 msgbits(77) + integer*1 nxor(174),hdec(174) + integer itone(NN) + integer icos7(0:6),ip(1) + logical one(0:511,0:8) + integer graymap(0:7) + integer iloc(1) + complex cd0(0:3199) + complex ctwk(32) + complex csymb(32) + complex cs(0:7,NN) + logical std_1,std_2 + logical first,newdat + data icos7/3,1,4,0,6,5,2/ ! Flipped w.r.t. original FT8 sync array + data first/.true./ + data graymap/0,1,3,2,5,6,4,7/ + save one + + if(first) then + one=.false. + do i=0,511 + do j=0,8 + if(iand(i,2**j).ne.0) one(i,j)=.true. + enddo + enddo + first=.false. + endif + + call stdcall(call_1,std_1) + if(call_1(1:3).eq.'CQ ') std_1=.true. + call stdcall(call_2,std_2) + + nharderrors=-1 + fs2=12000.0/NDOWN + dt2=1.0/fs2 + twopi=8.0*atan(1.0) + delfbest=0. + ibest=0 + + call timer('ft8_down',0) + call ft8_downsample(dd0,newdat,f1,cd0) !Mix f1 to baseband and downsample + call timer('ft8_down',1) + + i0=nint((xdt+0.5)*fs2) !Initial guess for start of signal + smax=0.0 + do idt=i0-10,i0+10 !Search over +/- one quarter symbol + call sync8d(cd0,idt,ctwk,0,sync) + if(sync.gt.smax) then + smax=sync + ibest=idt + endif + enddo + +! Now peak up in frequency + smax=0.0 + do ifr=-5,5 !Search over +/- 2.5 Hz + delf=ifr*0.5 + dphi=twopi*delf*dt2 + phi=0.0 + do i=1,32 + ctwk(i)=cmplx(cos(phi),sin(phi)) + phi=mod(phi+dphi,twopi) + enddo + call sync8d(cd0,ibest,ctwk,1,sync) + if( sync .gt. smax ) then + smax=sync + delfbest=delf + endif + enddo + a=0.0 + a(1)=-delfbest + call twkfreq1(cd0,NP2,fs2,a,cd0) + f1=f1+delfbest !Improved estimate of DF + + call timer('ft8_down',0) + call ft8_downsample(dd0,.false.,f1,cd0) !Mix f1 to baseband and downsample + call timer('ft8_down',1) + + smax=0.0 + do idt=-4,4 !Search over +/- one quarter symbol + call sync8d(cd0,ibest+idt,ctwk,0,sync) + ss(idt+5)=sync + enddo + smax=maxval(ss) + iloc=maxloc(ss) + ibest=iloc(1)-5+ibest + xdt=(ibest-1)*dt2 - 0.5 + sync=smax + + do k=1,NN + i1=ibest+(k-1)*32 + csymb=cmplx(0.0,0.0) + if( i1.ge.0 .and. i1+31 .le. NP2-1 ) csymb=cd0(i1:i1+31) + call four2a(csymb,32,1,-1,1) + cs(0:7,k)=csymb(1:8)/1e3 + s8(0:7,k)=abs(csymb(1:8)) + enddo + +! sync quality check + is1=0 + is2=0 + is3=0 + do k=1,7 + ip=maxloc(s8(:,k)) + if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1 + ip=maxloc(s8(:,k+36)) + if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1 + ip=maxloc(s8(:,k+72)) + if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1 + enddo +! hard sync sum - max is 21 + nsync=is1+is2+is3 +! if(nsync .le. 6) return ! bail out + + do nsym=1,3 + nt=2**(3*nsym) + do ihalf=1,2 + do k=1,29,nsym + if(ihalf.eq.1) ks=k+7 + if(ihalf.eq.2) ks=k+43 + amax=-1.0 + do i=0,nt-1 + i1=i/64 + i2=iand(i,63)/8 + i3=iand(i,7) + if(nsym.eq.1) then + s2(i)=abs(cs(graymap(i3),ks)) + elseif(nsym.eq.2) then + s2(i)=abs(cs(graymap(i2),ks)+cs(graymap(i3),ks+1)) + elseif(nsym.eq.3) then + s2(i)=abs(cs(graymap(i1),ks)+cs(graymap(i2),ks+1)+cs(graymap(i3),ks+2)) + else + print*,"Error - nsym must be 1, 2, or 3." + endif + enddo + i32=1+(k-1)*3+(ihalf-1)*87 + if(nsym.eq.1) ibmax=2 + if(nsym.eq.2) ibmax=5 + if(nsym.eq.3) ibmax=8 + do ib=0,ibmax + bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - & + maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)) + if(i32+ib .gt.174) cycle + if(nsym.eq.1) then + bmeta(i32+ib)=bm + den=max(maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)), & + maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib))) + if(den.gt.0.0) then + cm=bm/den + else ! erase it + cm=0.0 + endif + bmetd(i32+ib)=cm + elseif(nsym.eq.2) then + bmetb(i32+ib)=bm + elseif(nsym.eq.3) then + bmetc(i32+ib)=bm + endif + enddo + enddo + enddo + enddo + call normalizebmet(bmeta,174) + call normalizebmet(bmetb,174) + call normalizebmet(bmetc,174) + call normalizebmet(bmetd,174) + + scalefac=2.83 + llra=scalefac*bmeta + llrb=scalefac*bmetb + llrc=scalefac*bmetc + llrd=scalefac*bmetd + +! apmag=maxval(abs(llra))*1.01 + + MAXMSG=206 + pbest=0. + do imsg=1,MAXMSG + msg=trim(call_1)//' '//trim(call_2) + i=imsg + if(call_1(1:3).eq.'CQ ' .and. i.ne.5) msg='QQ0XYZ '//trim(call_2) + if(.not.std_1) then + if(i.eq.1 .or. i.ge.6) msg='<'//trim(call_1)//'> '//trim(call_2) + if(i.ge.2 .and. i.le.4) msg=trim(call_1)//' <'//trim(call_2)//'>' + else if(.not.std_2) then + if(i.le.4 .or. i.eq.6) msg='<'//trim(call_1)//'> '//trim(call_2) + if(i.ge.7) msg=trim(call_1)//' <'//trim(call_2)//'>' + endif + j0=len(trim(msg))+2 + if(i.eq.2) msg(j0:j0+2)='RRR' + if(i.eq.3) msg(j0:j0+3)='RR73' + if(i.eq.4) msg(j0:j0+1)='73' + if(i.eq.5) then + if(std_2) then + msg='CQ '//trim(call_2) + if(call_1(3:3).eq.'_') msg=trim(call_1)//' '//trim(call_2) + if(grid4.ne.'RR73') msg=trim(msg)//' '//grid4 + endif + if(.not.std_2) msg='CQ '//trim(call_2) + endif + if(i.eq.6 .and. std_2) msg(j0:j0+3)=grid4 + if(i.ge.7) then + isnr = -50 + (i-7)/2 + if(iand(i,1).eq.1) then + write(msg(j0:j0+2),'(i3.2)') isnr + if(msg(j0:j0).eq.' ') msg(j0:j0)='+' + else + write(msg(j0:j0+3),'("R",i3.2)') isnr + if(msg(j0+1:j0+1).eq.' ') msg(j0+1:j0+1)='+' + endif + endif + +! Source-encode, then get codeword + i3=-1 + n3=-1 + call genft8(msg,i3,n3,msgsent,msgbits,itone) + call encode174_91(msgbits,cw) + rcw=2*cw-1 + pa=sum(llra*rcw) + pb=sum(llrb*rcw) + pc=sum(llrc*rcw) + pd=sum(llrd*rcw) + + if(pa.gt.pbest) then + pbest=pa + msgbest=msgsent + llrbest=llra + nharderrors=count((2*cw-1)*llra.lt.0.0) + hdec=0 + where(llra.ge.0.0) hdec=1 + nxor=ieor(hdec,cw) + dmin=sum(nxor*abs(llra)) + endif + enddo ! imsg + +! write(*,4001) pbest,nharderrors,dmin,trim(msgbest) +!4001 format('$$$',f7.1,i4,f7.1,2x,a) + msg37=msgbest + + return +end subroutine ft8c diff --git a/lib/ft8/ft8q3.f90 b/lib/ft8/ft8q3.f90 new file mode 100644 index 000000000..122e49c99 --- /dev/null +++ b/lib/ft8/ft8q3.f90 @@ -0,0 +1,109 @@ +subroutine ft8q3(cd,xdt,f0,call_1,call_2,grid4,msgbest,snr) + +! Get q3-style decodes for FT8. + + use packjt77 + parameter(NN=79,NSPS=32) + parameter(NWAVE=NN*NSPS) !2528 + parameter(NZ=3200,NLAGS=NZ-NWAVE) + character*12 call_1,call_2 + character*4 grid4 + character*37 msg,msgbest,msgsent + character c77*77 + complex cwave(0:NWAVE-1) + complex cd(0:NZ-1) + complex z + real xjunk(NWAVE) + real ccf(0:NLAGS-1) + real ccfmsg(206) + integer itone(NN) + integer*1 msgbits(77) + logical std_1,std_2 + + if(xdt.eq.-99.0) return !Silence compiler warning + call stdcall(call_1,std_1) + call stdcall(call_2,std_2) + + fs=200.0 !Sample rate (Hz) + dt=1.0/fs !Sample interval (s) + bt=2.0 + ccfbest=0. + lagbest=-1 + + do imsg=1,206 + msg=trim(call_1)//' '//trim(call_2) + i=imsg + if(.not.std_1) then + if(i.eq.1 .or. i.ge.6) msg='<'//trim(call_1)//'> '//trim(call_2) + if(i.ge.2 .and. i.le.4) msg=trim(call_1)//' <'//trim(call_2)//'>' + else if(.not.std_2) then + if(i.le.4 .or. i.eq.6) msg='<'//trim(call_1)//'> '//trim(call_2) + if(i.ge.7) msg=trim(call_1)//' <'//trim(call_2)//'>' + endif + j0=len(trim(msg))+2 + if(i.eq.2) msg(j0:j0+2)='RRR' + if(i.eq.3) msg(j0:j0+3)='RR73' + if(i.eq.4) msg(j0:j0+1)='73' + if(i.eq.5) then + if(std_2) msg='CQ '//trim(call_2)//' '//grid4 + if(.not.std_2) msg='CQ '//trim(call_2) + endif + if(i.eq.6 .and. std_2) msg(j0:j0+3)=grid4 + if(i.ge.7 .and. i.le.206) then + isnr = -50 + (i-7)/2 + if(iand(i,1).eq.1) then + write(msg(j0:j0+2),'(i3.2)') isnr + if(msg(j0:j0).eq.' ') msg(j0:j0)='+' + else + write(msg(j0:j0+3),'("R",i3.2)') isnr + if(msg(j0+1:j0+1).eq.' ') msg(j0+1:j0+1)='+' + endif + endif + +! Source-encode, then get itone() + i3=-1 + n3=-1 + call pack77(msg,i3,n3,c77) + call genft8(msg,i3,n3,msgsent,msgbits,itone) +! Generate complex cwave + call gen_ft8wave(itone,NN,NSPS,bt,fs,f0,cwave,xjunk,1,NWAVE) + + lagmax=-1 + ccfmax=0. + nsum=32*2 + do lag=0,nlags-1 + z=0. + s=0. + do i=0,NWAVE-1 + z=z + cd(i+lag)*conjg(cwave(i)) + if(mod(i,nsum).eq.nsum-1 .or. i.eq.NWAVE-1) then + s=s + abs(z) + z=0. + endif + enddo + ccf(lag)=s + if(ccf(lag).gt.ccfmax) then + ccfmax=ccf(lag) + lagmax=lag + endif + enddo ! lag + ccfmsg(imsg)=ccfmax + if(ccfmax.gt.ccfbest) then + ccfbest=ccfmax + lagbest=lagmax + msgbest=msg + endif + enddo ! imsg + + call pctile(ccfmsg,207,50,base) + call pctile(ccfmsg,207,67,sigma) + sigma=sigma-base + ccfmsg=(ccfmsg-base)/sigma +! do imsg=1,207 +! write(44,3044) imsg,ccfmsg(imsg) +!3044 format(i5,f10.3) +! enddo + snr=maxval(ccfmsg) + + return +end subroutine ft8q3 diff --git a/lib/ft8/gen_ft8wave.f90 b/lib/ft8/gen_ft8wave.f90 index 9e2773758..c7be09159 100644 --- a/lib/ft8/gen_ft8wave.f90 +++ b/lib/ft8/gen_ft8wave.f90 @@ -9,11 +9,12 @@ subroutine gen_ft8wave(itone,nsym,nsps,bt,fsample,f0,cwave,wave,icmplx,nwave) real pulse(23040) real dphi(0:(nsym+2)*nsps-1) integer itone(nsym) - data ibt0/0/ - save pulse,twopi,dt,hmod,ibt0,ctab + data fchk0/0.0/ + save pulse,twopi,dt,hmod,fchk0,ctab ibt=nint(10*bt) - if(ibt0.ne.ibt) then + fchk=nsym+nsps+bt+fsample + if(fchk.ne.fchk0) then twopi=8.0*atan(1.0) dt=1.0/fsample hmod=1.0 @@ -22,11 +23,11 @@ subroutine gen_ft8wave(itone,nsym,nsps,bt,fsample,f0,cwave,wave,icmplx,nwave) tt=(i-1.5*nsps)/real(nsps) pulse(i)=gfsk_pulse(bt,tt) enddo - ibt0=nint(10*bt) do i=0,NTAB-1 phi=i*twopi/NTAB ctab(i)=cmplx(cos(phi),sin(phi)) enddo + fchk0=fchk endif ! Compute the smoothed frequency waveform. diff --git a/lib/ft8/subtractft8.f90 b/lib/ft8/subtractft8.f90 index 7c3b59082..40657e7e7 100644 --- a/lib/ft8/subtractft8.f90 +++ b/lib/ft8/subtractft8.f90 @@ -58,6 +58,8 @@ subroutine subtractft8(dd0,itone,f0,dt,lrefinedt) sq0=sqf(0) !Do the subtraction with idt=0 endif dd0=dd !Return dd0 with this signal subtracted +! write(44,3044) nint(f0),dt-0.5,1.e-8*sum(dd*dd) +!3044 format(i4,f7.2,f10.6) return contains diff --git a/lib/ft8/test_ft8q3.f90 b/lib/ft8/test_ft8q3.f90 new file mode 100644 index 000000000..4a3802c3c --- /dev/null +++ b/lib/ft8/test_ft8q3.f90 @@ -0,0 +1,41 @@ +program test_ft8q3 + +! Test q3-style decodes for FT8. + + use packjt77 + parameter(NN=79,NSPS=32) + parameter(NWAVE=NN*NSPS) !2528 + parameter(NZ=3200,NLAGS=NZ-NWAVE) + character arg*12 + character*37 msg + character*12 call_1,call_2 + character*4 grid4 + complex cd(0:NZ-1) + +! Get command-line argument(s) + nargs=iargc() + if(nargs.ne.4 .and. nargs.ne.5) then + print*,'Usage: ft8q3 DT f0 call_1 call_2 [grid4]' + go to 999 + endif + call getarg(1,arg) + read(arg,*) xdt !Time offset from nominal (s) + call getarg(2,arg) + read(arg,*) f0 !Frequency (Hz) + call getarg(3,call_1) !First callsign + call getarg(4,call_2) !Second callsign + grid4=' ' + if(nargs.eq.5) call getarg(5,grid4) !Locator for call_2 + + do i=0,NZ-1 + read(40,3040) cd(i) +3040 format(17x,2f10.3) + enddo + + call sec0(0,t) + call ft8q3(cd,xdt,f0,call_1,call_2,grid4,msg,snr) + call sec0(1,t) + write(*,1100) t,snr,trim(msg) +1100 format('Time:',f6.2,' S/N:',f6.1,' msg: ',a) + +999 end program test_ft8q3 diff --git a/lib/ft8_decode.f90 b/lib/ft8_decode.f90 index 73d0f8c2a..b33629738 100644 --- a/lib/ft8_decode.f90 +++ b/lib/ft8_decode.f90 @@ -38,6 +38,7 @@ contains use iso_c_binding, only: c_bool, c_int use timer_module, only: timer use shmem, only: shmem_lock, shmem_unlock + use ft8_a7 include 'ft8/ft8_params.f90' @@ -53,7 +54,8 @@ contains logical newdat,lsubtract,ldupe,lrefinedt logical*1 ldiskdat logical lsubtracted(MAX_EARLY) - character*12 mycall12,hiscall12 + character*12 mycall12,hiscall12,call_1,call_2 + character*4 grid4 integer*2 iwave(15*12000) integer apsym2(58),aph10(10) character datetime*13,msg37*37 @@ -64,13 +66,33 @@ contains integer itone_save(NN,MAX_EARLY) real f1_save(MAX_EARLY) real xdt_save(MAX_EARLY) + data nutc0/-1/ - save s,dd,dd1,ndec_early,itone_save,f1_save,xdt_save,lsubtracted,allmessages + save s,dd,dd1,nutc0,ndec_early,itone_save,f1_save,xdt_save,lsubtracted,& + allmessages this%callback => callback write(datetime,1001) nutc !### TEMPORARY ### 1001 format("000000_",i6.6) + if(nutc0.eq.-1) then + msg0=' ' + dt0=0. + f0=0. + endif + if(nutc.ne.nutc0) then +! New UTC. Move previously saved 'a7' data from k=1 to k=0 + iz=ndec(jseq,1) + dt0(1:iz,jseq,0) = dt0(1:iz,jseq,1) + f0(1:iz,jseq,0) = f0(1:iz,jseq,1) + msg0(1:iz,jseq,0) = msg0(1:iz,jseq,1) + ndec(jseq,0)=iz + ndec(jseq,1)=0 + nutc0=nutc + dt0(:,jseq,1)=0. + f0(:,jseq,1)=0. + endif + if(ndepth.eq.1 .and. nzhsym.lt.50) then ndec_early=0 return @@ -178,7 +200,7 @@ contains hiscall12,f1,xdt,xbase,apsym2,aph10,nharderrors,dmin, & nbadcrc,iappass,msg37,xsnr,itone) call timer('ft8b ',1) - nsnr=nint(xsnr) + nsnr=nint(xsnr) xdt=xdt-0.5 hd=nharderrors+dmin if(nbadcrc.eq.0) then @@ -198,6 +220,11 @@ contains qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0] if(emedelay.ne.0) xdt=xdt+2.0 call this%callback(sync,nsnr,xdt,f1,msg37,iaptype,qual) + call ft8_a7_save(nutc,xdt,f1,msg37) !Enter decode in table +! ii=ndec(jseq,1) +! write(41,3041) jseq,ii,nint(f0(ii,jseq,0)),msg0(ii,jseq,0)(1:22),& +! nint(f0(ii,jseq,1)),msg0(ii,jseq,1)(1:22) +!3041 format(3i5,2x,a22,i5,2x,a22) endif endif call timestamp(tsec,tseq,ctime) @@ -209,7 +236,43 @@ contains 800 ndec_early=0 if(nzhsym.lt.50) ndec_early=ndecodes -900 return +900 continue + if(nzhsym.eq.50 .and. ndec(jseq,0).ge.1) then + newdat=.true. + do i=1,ndec(jseq,0) + if(f0(i,jseq,0).eq.-99.0) exit + if(f0(i,jseq,0).eq.-98.0) cycle + if(index(msg0(i,jseq,0),'<').ge.1) cycle !### Temporary ### + msg37=msg0(i,jseq,0) + i1=index(msg37,' ') + i2=index(msg37(i1+1:),' ') + i1 + call_1=msg37(1:i1-1) + call_2=msg37(i1+1:i2-1) + grid4=msg37(i2+1:i2+4) + if(grid4.eq.'RR73' .or. index(grid4,'+').gt.0 .or. & + index(grid4,'-').gt.0) grid4=' ' + xdt=dt0(i,jseq,0) + f1=f0(i,jseq,0) + xbase=10.0**(0.1*(sbase(max(1,nint(f1/3.125)))-40.0)) + msg37=' ' + call timer('ft8_a7d ',0) + call ft8_a7d(dd,newdat,call_1,call_2,grid4,xdt,f1,xbase,nharderrors, & + dmin,msg37,xsnr) + call timer('ft8_a7d ',1) + + if(nharderrors.ge.0) then + if(associated(this%callback)) then + nsnr=xsnr + iaptype=7 + qual=1.0 + call this%callback(sync,nsnr,xdt,f1,msg37,iaptype,qual) + call ft8_a7_save(nutc,xdt,f1,msg37) !Enter decode in table + endif + endif + enddo + endif + + return end subroutine decode subroutine timestamp(tsec,tseq,ctime) diff --git a/lib/gen65.f90 b/lib/gen65.f90 index af036c2a9..2fd6495a7 100644 --- a/lib/gen65.f90 +++ b/lib/gen65.f90 @@ -1,9 +1,10 @@ -subroutine gen65(msg0,ichk,msgsent,itone,itype) +subroutine gen65(msg00,ichk,msgsent0,itone,itype) BIND(c) ! Encodes a JT65 message to yieild itone(1:126) ! Temporarily, does not implement EME shorthands use packjt + character*1 msg00(23),msgsent0(23) character*22 msg0 character*22 message !Message to be generated character*22 msgsent !Message as it will be received @@ -21,6 +22,10 @@ subroutine gen65(msg0,ichk,msgsent,itone,itype) 1,1,1,1,1,1/ save + do i=1,22 + msg0(i:i)=msg00(i) + enddo + if(msg0(1:1).eq.'@') then read(msg0(2:5),*,end=1,err=1) nfreq go to 2 @@ -48,7 +53,7 @@ subroutine gen65(msg0,ichk,msgsent,itone,itype) call unpackmsg(dgen,msgsent) !Unpack to get message sent msgsent(20:22)=cok call fmtmsg(msgsent,iz) - if(ichk.ne.0) go to 999 !Return if checking only + if(ichk.ne.0) go to 900 !Return if checking only call rs_encode(dgen,sent) !Apply Reed-Solomon code call interleave63(sent,1) !Apply interleaving @@ -79,5 +84,10 @@ subroutine gen65(msg0,ichk,msgsent,itone,itype) endif endif -999 return +900 do i=1,22 + msgsent0(i)=msgsent(i:i) + enddo + msgsent0(23)=char(0) + + return end subroutine gen65 diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index f445cec5c..04e58eb86 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -62,6 +62,7 @@ contains character(len=12) :: mycall, hiscall !Used for AP decoding character(len=6) :: hisgrid character*37 decoded !Decoded message + character*37 decodes(100) character*77 c77 character*78 c78 character*6 cutc @@ -80,6 +81,8 @@ contains ! Start by setting some parameters and allocating storage for large arrays call sec0(0,tdecode) + ndecodes=0 + decodes=' ' nfa=nfa0 nfb=nfb0 nqd=nqd0 @@ -166,8 +169,8 @@ contains call q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, & emedelay,xdt,f0,snr1,width,dat4,snr2,idec,stageno) call timer('q65_dec0',1) -! write(*,3001) '=a',sum(abs(float(iwave))),nfqso,ntol,ndepth,xdt,f0,idec -!3001 format(a2,f15.0,3i5,f7.2,f7.1,i5) +! write(*,3001) '=a',nfqso,ntol,ndepth,xdt,f0,idec +!3001 format(a2,3i5,f7.2,f7.1,i5) if(idec.ge.0) then dtdec=xdt !We have a q3 or q0 decode at nfqso @@ -201,6 +204,7 @@ contains call q65_loops(c00,npts/2,nsps/2,nsubmode,ndepth,jpk0, & xdt,f0,iaptype,xdt1,f1,snr2,dat4,idec) call timer('q65loops',1) +! write(*,3001) '=b',nfqso,ntol,ndepth,xdt,f0,idec if(idec.ge.0) then dtdec=xdt1 f0dec=f1 @@ -268,33 +272,41 @@ contains ! Unpack decoded message for display to user write(c77,1000) dat4(1:12),dat4(13)/2 1000 format(12b6.6,b5.5) - call unpack77(c77,1,decoded,unpk77_success) !Unpack to get msgsent - call q65_snr(dat4,dtdec,f0dec,mode_q65,nused,snr2) - nsnr=nint(snr2) - call this%callback(nutc,snr1,nsnr,dtdec,f0dec,decoded, & - idec,nused,ntrperiod) - call q65_hist(nint(f0dec),msg0=decoded) - if(iand(ndepth,128).ne.0 .and. .not.lagain .and. & - int(abs(f0dec-nfqso)).le.ntol ) call q65_clravg !AutoClrAvg - call sec0(1,tdecode) - open(22,file=trim(data_dir)//'/q65_decodes.dat',status='unknown', & - position='append',iostat=ios) - if(ios.eq.0) then + call unpack77(c77,1,decoded,unpk77_success) !Unpack to get decoded + idupe=0 + do i=1,ndecodes + if(decodes(i).eq.decoded) idupe=1 + enddo + if(idupe.eq.0) then + ndecodes=min(ndecodes+1,100) + decodes(ndecodes)=decoded + call q65_snr(dat4,dtdec,f0dec,mode_q65,nused,snr2) + nsnr=nint(snr2) + call this%callback(nutc,snr1,nsnr,dtdec,f0dec,decoded, & + idec,nused,ntrperiod) + call q65_hist(nint(f0dec),msg0=decoded) + if(iand(ndepth,128).ne.0 .and. .not.lagain .and. & + int(abs(f0dec-nfqso)).le.ntol ) call q65_clravg !AutoClrAvg + call sec0(1,tdecode) + open(22,file=trim(data_dir)//'/q65_decodes.dat',status='unknown', & + position='append',iostat=ios) + if(ios.eq.0) then ! Save decoding parameters to q65_decoded.dat, for later analysis. - write(cmode,'(i3)') ntrperiod - cmode(4:4)=char(ichar('A')+nsubmode) - c6=hiscall(1:6) - if(c6.eq.' ') c6=' ' - c4=hisgrid(1:4) - if(c4.eq.' ') c4=' ' - fmt='(i6.4,1x,a4,4i2,6i3,i4,f6.2,f7.1,f6.1,f7.1,f6.2,'// & - '1x,a6,1x,a6,1x,a4,1x,a)' - if(ntrperiod.le.30) fmt(5:5)='6' - if(idec.eq.3) nrc=0 - write(22,fmt) nutc,cmode,nQSOprogress,idec,idfbest,idtbest,ibw, & - ndistbest,nused,icand,ncand,nrc,ndepth,xdt,f0,snr2,plog, & - tdecode,mycall(1:6),c6,c4,trim(decoded) - close(22) + write(cmode,'(i3)') ntrperiod + cmode(4:4)=char(ichar('A')+nsubmode) + c6=hiscall(1:6) + if(c6.eq.' ') c6=' ' + c4=hisgrid(1:4) + if(c4.eq.' ') c4=' ' + fmt='(i6.4,1x,a4,i5,4i2,6i3,i4,f6.2,f7.1,f6.1,f7.1,f6.2,'// & + '1x,a6,1x,a6,1x,a4,1x,a)' + if(ntrperiod.le.30) fmt(5:5)='6' + if(idec.eq.3) nrc=0 + write(22,fmt) nutc,cmode,nfqso,nQSOprogress,idec,idfbest,idtbest, & + ibw,ndistbest,nused,icand,ncand,nrc,ndepth,xdt,f0,snr2,plog, & + tdecode,mycall(1:6),c6,c4,trim(decoded) + close(22) + endif endif endif navg0=1000*navg(0) + navg(1) @@ -333,6 +345,7 @@ contains call q65_loops(c00,npts/2,nsps/2,nsubmode,ndepth,jpk0, & xdt,f0,iaptype,xdt1,f1,snr2,dat4,idec) call timer('q65loops',1) +! write(*,3001) '=e',nfqso,ntol,ndepth,xdt,f0,idec if(idec.ge.0) then dtdec=xdt1 f0dec=f1 @@ -344,33 +357,41 @@ contains if(idec.ge.0) then ! Unpack decoded message for display to user write(c77,1000) dat4(1:12),dat4(13)/2 - call unpack77(c77,1,decoded,unpk77_success) !Unpack to get msgsent - call q65_snr(dat4,dtdec,f0dec,mode_q65,nused,snr2) - nsnr=nint(snr2) - call this%callback(nutc,snr1,nsnr,dtdec,f0dec,decoded, & - idec,nused,ntrperiod) - call q65_hist(nint(f0dec),msg0=decoded) - if(iand(ndepth,128).ne.0 .and. .not.lagain .and. & - int(abs(f0dec-nfqso)).le.ntol ) call q65_clravg !AutoClrAvg - call sec0(1,tdecode) - open(22,file=trim(data_dir)//'/q65_decodes.dat',status='unknown', & - position='append',iostat=ios) - if(ios.eq.0) then + call unpack77(c77,1,decoded,unpk77_success) !Unpack to get decoded + idupe=0 + do i=1,ndecodes + if(decodes(i).eq.decoded) idupe=1 + enddo + if(idupe.eq.0) then + ndecodes=min(ndecodes+1,100) + decodes(ndecodes)=decoded + call q65_snr(dat4,dtdec,f0dec,mode_q65,nused,snr2) + nsnr=nint(snr2) + call this%callback(nutc,snr1,nsnr,dtdec,f0dec,decoded, & + idec,nused,ntrperiod) + call q65_hist(nint(f0dec),msg0=decoded) + if(iand(ndepth,128).ne.0 .and. .not.lagain .and. & + int(abs(f0dec-nfqso)).le.ntol ) call q65_clravg !AutoClrAvg + call sec0(1,tdecode) + open(22,file=trim(data_dir)//'/q65_decodes.dat',status='unknown', & + position='append',iostat=ios) + if(ios.eq.0) then ! Save decoding parameters to q65_decoded.dat, for later analysis. - write(cmode,'(i3)') ntrperiod - cmode(4:4)=char(ichar('A')+nsubmode) - c6=hiscall(1:6) - if(c6.eq.' ') c6=' ' - c4=hisgrid(1:4) - if(c4.eq.' ') c4=' ' - fmt='(i6.4,1x,a4,4i2,6i3,i4,f6.2,f7.1,f6.1,f7.1,f6.2,'// & - '1x,a6,1x,a6,1x,a4,1x,a)' - if(ntrperiod.le.30) fmt(5:5)='6' - if(idec.eq.3) nrc=0 - write(22,fmt) nutc,cmode,nQSOprogress,idec,idfbest,idtbest,ibw, & - ndistbest,nused,icand,ncand,nrc,ndepth,xdt,f0,snr2,plog, & - tdecode,mycall(1:6),c6,c4,trim(decoded) - close(22) + write(cmode,'(i3)') ntrperiod + cmode(4:4)=char(ichar('A')+nsubmode) + c6=hiscall(1:6) + if(c6.eq.' ') c6=' ' + c4=hisgrid(1:4) + if(c4.eq.' ') c4=' ' + fmt='(i6.4,1x,a4,i5,4i2,6i3,i4,f6.2,f7.1,f6.1,f7.1,f6.2,'// & + '1x,a6,1x,a6,1x,a4,1x,a)' + if(ntrperiod.le.30) fmt(5:5)='6' + if(idec.eq.3) nrc=0 + write(22,fmt) nutc,cmode,nfqso,nQSOprogress,idec,idfbest,idtbest, & + ibw,ndistbest,nused,icand,ncand,nrc,ndepth,xdt,f0,snr2,plog, & + tdecode,mycall(1:6),c6,c4,trim(decoded) + close(22) + endif endif endif enddo ! icand diff --git a/lib/qra/q65/q65.f90 b/lib/qra/q65/q65.f90 index 349e38c91..65683dd71 100644 --- a/lib/qra/q65/q65.f90 +++ b/lib/qra/q65/q65.f90 @@ -171,8 +171,6 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, & call timer('list_dec',0) call q65_dec_q3(s1,iz,jz,s3,LL,ipk,jpk,snr2,dat4,idec,decoded) call timer('list_dec',1) -! if(idec.ge.0) write(70,3070) idec,mode_q65,better,trim(decoded) -!3070 format(i3,i5,f8.2,2x,a) endif ! If idec=3 we have a q3 decode. Continue to compute sync curve for plotting. endif @@ -250,16 +248,15 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, & call q65_ccf_85(s1w,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,imsg_best, & better,ccf1) call timer('ccf_85 ',1) - ! nsubmode is Tone-spacing indicator, 0-4 for A-E: a 0; b 1; c 2; d 3; e 4. - ! and mode_q65=2**nsubmode + +! nsubmode is Tone-spacing indicator, 0-4 for A-E: a 0; b 1; c 2; d 3; e 4. +! and mode_q65=2**nsubmode if(better.ge.1.10) then ! if(better.ge.1.04 .or. mode_q65.ge.8) then ! if(better.ge.1.10 .or. mode_q65.ge.8) then ORIGINAL call timer('list_dec',0) call q65_dec_q3(s1w,iz,jz,s3,LL,ipk,jpk,snr2,dat4,idec,decoded) call timer('list_dec',1) - ! if(idec.ge.0) write(70,3070) idec,mode_q65,better,trim(decoded) - !3070 format(i3,i5,f8.2,2x,a) endif ! if(better.ge.1.10) endif ! if(ncw.gt.0 .and. iavg.le.1) ! If idec=3 we have a q3 decode. Continue to compute sync curve for plotting. @@ -570,7 +567,6 @@ subroutine q65_ccf_22(s1,iz,jz,nfqso,ntol,ndepth,ntrperiod,iavg,ipk,jpk, & i=indx(k)+ia-1 if(ccf2(i).lt.3.3) exit !Candidate limit f=i*df - if(f.ge.(nfqso-ftol) .and. f.le.(nfqso+ftol)) cycle !Looked here already i3=max(1, i-mode_q65) i4=min(iz,i+mode_q65) biggest=maxval(ccf2(i3:i4)) @@ -785,9 +781,9 @@ subroutine q65_snr(dat4,dtdec,f0dec,mode_q65,nused,snr2) sig_area=sum(spec(ia+nsum:ib-nsum)-1.0) w_equiv=sig_area/(smax-1.0) snr2=db(max(1.0,sig_area)) - db(2500.0/df) - if(nused.eq.2) snr2=snr2 - 2.0 - if(nused.eq.3) snr2=snr2 - 2.9 - if(nused.ge.4) snr2=snr2 - 3.5 + if(nused.eq.2) snr2=snr2 - 1.5 + if(nused.eq.3) snr2=snr2 - 2.4 + if(nused.ge.4) snr2=snr2 - 3.0 return end subroutine q65_snr diff --git a/widgets/FrequencyDeltaLineEdit.cpp b/widgets/FrequencyDeltaLineEdit.cpp index b7ed144b6..59ae9bc9c 100644 --- a/widgets/FrequencyDeltaLineEdit.cpp +++ b/widgets/FrequencyDeltaLineEdit.cpp @@ -39,8 +39,8 @@ namespace FrequencyDeltaLineEdit::FrequencyDeltaLineEdit (QWidget * parent) : QLineEdit (parent) { - setValidator (new MHzValidator {-std::numeric_limits::max () / 10.e6, - std::numeric_limits::max () / 10.e6, this}); + setValidator (new MHzValidator {static_cast(std::numeric_limits::min ()) / 10.e6, + static_cast(std::numeric_limits::max ()) / 10.e6, this}); } auto FrequencyDeltaLineEdit::frequency_delta () const -> FrequencyDelta diff --git a/widgets/FrequencyLineEdit.cpp b/widgets/FrequencyLineEdit.cpp index 1ca2ba20b..8e74c7db4 100644 --- a/widgets/FrequencyLineEdit.cpp +++ b/widgets/FrequencyLineEdit.cpp @@ -39,7 +39,7 @@ namespace FrequencyLineEdit::FrequencyLineEdit (QWidget * parent) : QLineEdit (parent) { - setValidator (new MHzValidator {0., std::numeric_limits::max () / 10.e6, this}); + setValidator (new MHzValidator {0., static_cast(std::numeric_limits::max ()) / 10.e6, this}); } auto FrequencyLineEdit::frequency () const -> Frequency diff --git a/widgets/displaytext.cpp b/widgets/displaytext.cpp index d784ead1b..c3e31f83c 100644 --- a/widgets/displaytext.cpp +++ b/widgets/displaytext.cpp @@ -404,6 +404,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con QColor bg; QColor fg; bool CQcall = false; + auto is_73 = decodedText.messageWords().filter (QRegularExpression {"^(73|RR73)$"}).size(); if (decodedText.string ().contains (" CQ ") || decodedText.string ().contains (" CQDX ") || decodedText.string ().contains (" QRZ ")) @@ -413,19 +414,6 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con else { if (bCQonly) return; - if (myCall.size ()) - { - QString regexp {"[ <]" + myCall + "[ >]"}; - if (Radio::is_compound_callsign (myCall)) - { - regexp = "(?:" + regexp + "|[ <]" + Radio::base_callsign (myCall) + "[ >])"; - } - if ((decodedText.clean_string () + " ").contains (QRegularExpression {regexp})) - { - highlight_types types {Highlight::MyCall}; - set_colours (m_config, &bg, &fg, types); - } - } } auto message = decodedText.string(); QString dxCall; @@ -446,14 +434,14 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con message = message.left (ap_pos).trimmed (); } m_CQPriority=""; - if (CQcall) + if (CQcall || (is_73 && (m_config->highlight_73 ()))) { if (displayDXCCEntity) { // if enabled add the DXCC entity and B4 status to the end of the // preformated text line t1 auto currentMode = mode; - message = appendWorkedB4 (message, decodedText.CQersCall(), dxGrid, &bg, &fg + message = appendWorkedB4 (message, dxCall, dxGrid, &bg, &fg , logBook, currentBand, currentMode, extra); } else @@ -472,6 +460,20 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con message = leftJustifyAppendage (message, extra); } + if (myCall.size ()) + { + QString regexp {"[ <]" + myCall + "[ >]"}; + if (Radio::is_compound_callsign (myCall)) + { + regexp = "(?:" + regexp + "|[ <]" + Radio::base_callsign (myCall) + "[ >])"; + } + if ((decodedText.clean_string () + " ").contains (QRegularExpression {regexp})) + { + highlight_types types {Highlight::MyCall}; + set_colours (m_config, &bg, &fg, types); + } + } + appendText (message.trimmed (), bg, fg, decodedText.call (), dxCall); } diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 5d9ae6ddf..62e75437d 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -90,6 +90,8 @@ #include "ui_mainwindow.h" #include "moc_mainwindow.cpp" +#define FCL fortran_charlen_t + extern "C" { //----------------------------------------------------- C and Fortran routines void symspec_(struct dec_data *, int* k, double* trperiod, int* nsps, int* ingain, @@ -133,8 +135,7 @@ extern "C" { void genmsk_128_90_(char* msg, int* ichk, char* msgsent, int itone[], int* itype, fortran_charlen_t, fortran_charlen_t); - void gen65_(char* msg, int* ichk, char* msgsent, int itone[], - int* itext, fortran_charlen_t, fortran_charlen_t); + void gen65(char* msg, int* ichk, char msgsent[], int itone[], int* itext); void genq65_(char* msg, int* ichk, char* msgsent, int itone[], int* i3, int* n3, fortran_charlen_t, fortran_charlen_t); @@ -147,8 +148,6 @@ extern "C" { void morse_(char* msg, int* icw, int* ncw, fortran_charlen_t); - int ptt_(int nport, int ntx, int* iptt, int* nopen); - void wspr_downsample_(short int d2[], int* k); int savec2_(char const * fname, int* TR_seconds, double* dial_freq, fortran_charlen_t); @@ -170,8 +169,6 @@ extern "C" { void freqcal_(short d2[], int* k, int* nkhz,int* noffset, int* ntol, char line[], fortran_charlen_t); - void fix_contest_msg_(char* MyGrid, char* msg, fortran_charlen_t, fortran_charlen_t); - void calibrate_(char const * data_dir, int* iz, double* a, double* b, double* rms, double* sigmaa, double* sigmab, int* irc, fortran_charlen_t); @@ -179,13 +176,9 @@ extern "C" { void plotsave_(float swide[], int* m_w , int* m_h1, int* irow); - void chkcall_(char* w, char* basc_call, bool cok, int len1, int len2); - - void get_ft4msg_(int* idecode, char* line, int len); - void chk_samples_(int* m_ihsym,int* k, int* m_hsymStop); - void save_dxbase_(char* dxbase, int len); + void save_dxbase_(char* dxbase, FCL len); } int volatile itone[MAX_NUM_SYMBOLS]; //Audio tones for all Tx symbols @@ -604,6 +597,12 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionSave_decoded->setActionGroup(saveGroup); ui->actionSave_all->setActionGroup(saveGroup); + QActionGroup* alltxtGroup = new QActionGroup(this); + ui->actionDon_t_split_ALL_TXT->setActionGroup(alltxtGroup); + ui->actionSplit_ALL_TXT_yearly->setActionGroup(alltxtGroup); + ui->actionSplit_ALL_TXT_monthly->setActionGroup(alltxtGroup); + ui->actionDisable_writing_of_ALL_TXT->setActionGroup(alltxtGroup); + QActionGroup* DepthGroup = new QActionGroup(this); ui->actionQuickDecode->setActionGroup(DepthGroup); ui->actionMediumDecode->setActionGroup(DepthGroup); @@ -954,7 +953,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->txFirstCheckBox->setChecked(m_txFirst); morse_(const_cast (m_config.my_callsign ().toLatin1().constData()), - const_cast (icw), &m_ncw, m_config.my_callsign ().length()); + const_cast (icw), &m_ncw, (FCL)m_config.my_callsign().length()); on_actionWide_Waterfall_triggered(); ui->cbShMsgs->setChecked(m_bShMsgs); ui->cbSWL->setChecked(m_bSWL); @@ -1188,6 +1187,10 @@ void MainWindow::writeSettings() } m_settings->setValue ("PhaseEqualizationCoefficients", QVariant {coeffs}); } + m_settings->setValue ("actionDontSplitALLTXT", ui->actionDon_t_split_ALL_TXT->isChecked() ); + m_settings->setValue ("splitAllTxtYearly", ui->actionSplit_ALL_TXT_yearly->isChecked() ); + m_settings->setValue ("splitAllTxtMonthly", ui->actionSplit_ALL_TXT_monthly->isChecked() ); + m_settings->setValue ("disableWritingOfAllTxt", ui->actionDisable_writing_of_ALL_TXT->isChecked() ); m_settings->endGroup(); } @@ -1230,6 +1233,10 @@ void MainWindow::readSettings() ui->actionAstronomical_data->setChecked (displayAstro); m_settings->beginGroup("Common"); + ui->actionDon_t_split_ALL_TXT->setChecked(m_settings->value("actionDontSplitALLTXT", true).toBool()); + ui->actionSplit_ALL_TXT_yearly->setChecked(m_settings->value("splitAllTxtYearly", false).toBool()); + ui->actionSplit_ALL_TXT_monthly->setChecked(m_settings->value("splitAllTxtMonthly", false).toBool()); + ui->actionDisable_writing_of_ALL_TXT->setChecked(m_settings->value("disableWritingOfAllTxt", false).toBool()); m_mode=m_settings->value("Mode","JT9").toString(); ui->actionNone->setChecked(m_settings->value("SaveNone",true).toBool()); ui->actionSave_decoded->setChecked(m_settings->value("SaveDecoded",false).toBool()); @@ -1306,7 +1313,7 @@ void MainWindow::readSettings() // use these initialisation settings to tune the audio o/p buffer // size and audio thread priority m_settings->beginGroup ("Tune"); - m_audioThreadPriority = static_cast (m_settings->value ("Audio/ThreadPriority", QThread::HighPriority).toInt () % 8); + m_audioThreadPriority = static_cast (m_settings->value ("Audio/ThreadPriority", QThread::TimeCriticalPriority).toInt () % 8); m_settings->endGroup (); checkMSK144ContestType(); @@ -1440,7 +1447,7 @@ void MainWindow::dataSink(qint64 frames) m_bUseRef=m_wideGraph->useRef(); if(!m_diskData) { refspectrum_(&dec_data.d2[k-m_nsps/2],&m_bClearRefSpec,&m_bRefSpec, - &m_bUseRef, fname.constData (), fname.size ()); + &m_bUseRef, fname.constData (), (FCL)fname.size ()); } m_bClearRefSpec=false; @@ -1480,7 +1487,7 @@ void MainWindow::dataSink(qint64 frames) int RxFreq=ui->RxFreqSpinBox->value (); int nkhz=(m_freqNominal+RxFreq)/1000; int ftol = ui->sbFtol->value (); - freqcal_(&dec_data.d2[0],&k,&nkhz,&RxFreq,&ftol,&line[0],80); + freqcal_(&dec_data.d2[0], &k, &nkhz, &RxFreq, &ftol, &line[0], (FCL)80); QString t=QString::fromLatin1(line); DecodedText decodedtext {t}; ui->decodedTextBrowser->displayDecodedText (decodedtext, m_config.my_callsign (), m_mode, m_config.DXCC (), @@ -1599,7 +1606,7 @@ void MainWindow::dataSink(qint64 frames) int nsec=120; int nbfo=1500; double f0m1500=m_freqNominal/1000000.0 + nbfo - 1500; - int err = savec2_(c2name.constData (),&nsec,&f0m1500, c2name.size ()); + int err = savec2_(c2name.constData (),&nsec,&f0m1500, (FCL)c2name.size()); if (err!=0) MessageBox::warning_message (this, tr ("Error saving c2 file"), c2name); } } @@ -1720,9 +1727,10 @@ void MainWindow::fastSink(qint64 frames) float rmsNoGain = 0; int ftol = ui->sbFtol->value (); hspec_(dec_data.d2,&k,&nutc0,&nTRpDepth,&RxFreq,&ftol,&bmsk144, - &m_bTrain,m_phaseEqCoefficients.constData(),&m_inGain,&dec_data.params.mycall[0], - &dec_data.params.hiscall[0],&bshmsg,&bswl, - data_dir.constData (),fast_green,fast_s,&fast_jh,&pxmax,&rmsNoGain,&line[0],12,12,data_dir.size (),80); + &m_bTrain,m_phaseEqCoefficients.constData(),&m_inGain,&dec_data.params.mycall[0], + &dec_data.params.hiscall[0],&bshmsg,&bswl, + data_dir.constData (),fast_green,fast_s,&fast_jh,&pxmax,&rmsNoGain,&line[0],(FCL)12, + (FCL)12,(FCL)data_dir.size (),(FCL)80); float px = fast_green[fast_jh]; QString t; t = t.asprintf(" Rx noise: %5.1f ",px); @@ -1824,7 +1832,7 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog m_baseCall = Radio::base_callsign (m_config.my_callsign ()); ui->tx1->setEnabled (elide_tx1_not_allowed () || ui->tx1->isEnabled ()); morse_(const_cast (m_config.my_callsign ().toLatin1().constData()), - const_cast (icw), &m_ncw, m_config.my_callsign ().length()); + const_cast (icw), &m_ncw, (FCL)m_config.my_callsign().length()); } if (m_config.my_callsign () != callsign || m_config.my_grid () != my_grid) { statusUpdate (); @@ -2537,7 +2545,7 @@ void MainWindow::on_actionSolve_FreqCal_triggered() auto data_dir {QDir::toNativeSeparators(m_config.writeable_data_dir().absolutePath()).toLocal8Bit ()}; int iz,irc; double a,b,rms,sigmaa,sigmab; - calibrate_(data_dir.constData (),&iz,&a,&b,&rms,&sigmaa,&sigmab,&irc,data_dir.size ()); + calibrate_(data_dir.constData(), &iz, &a, &b, &rms, &sigmaa, &sigmab, &irc, (FCL)data_dir.size()); QString t2; if(irc==-1) t2="Cannot open " + data_dir + "/fmt.all"; if(irc==-2) t2="Cannot open " + data_dir + "/fcal2.out"; @@ -2582,7 +2590,7 @@ void MainWindow::on_actionCopyright_Notice_triggered() "\"The algorithms, source code, look-and-feel of WSJT-X and related " "programs, and protocol specifications for the modes FSK441, FST4, FT8, " "JT4, JT6M, JT9, JT65, JTMS, QRA64, Q65, MSK144 are Copyright (C) " - "2001-2021 by one or more of the following authors: Joseph Taylor, " + "2001-2022 by one or more of the following authors: Joseph Taylor, " "K1JT; Bill Somerville, G4WJS; Steven Franke, K9AN; Nico Palermo, " "IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; " "Philip Karn, KA9Q; and other members of the WSJT Development Group.\""); @@ -3211,9 +3219,9 @@ void MainWindow::decode() //decode() narg[13]=-1; narg[14]=m_config.aggressive(); memcpy(d2b,dec_data.d2,2*360000); - watcher3.setFuture (QtConcurrent::run (std::bind (fast_decode_,&d2b[0], - &narg[0],&m_TRperiod,&m_msg[0][0], - dec_data.params.mycall,dec_data.params.hiscall,8000,12,12))); + watcher3.setFuture (QtConcurrent::run (std::bind (fast_decode_, &d2b[0], + &narg[0],&m_TRperiod, &m_msg[0][0], dec_data.params.mycall, + dec_data.params.hiscall, (FCL)8000, (FCL)12, (FCL)12))); } else { mem_jt9->lock (); memcpy(to, from, qMin(mem_jt9->size(), size)); @@ -3457,6 +3465,15 @@ void MainWindow::readFromStdout() //readFromStdout ui->cbCQonly->isVisible() && ui->cbCQonly->isChecked(), haveFSpread, fSpread); + if (m_config.highlight_DXcall () && (m_hisCall!="") && ((decodedtext.string().contains(QRegularExpression {"(\\w+) " + m_hisCall})) + || (decodedtext.string().contains(QRegularExpression {"(\\w+) <" + m_hisCall +">"})) + || (decodedtext.string().contains(QRegularExpression {"<(\\w+)> " + m_hisCall})))) { + ui->decodedTextBrowser->highlight_callsign(m_hisCall, QColor(255,0,0), QColor(255,255,255), true); // highlight dxCallEntry + } + if (m_config.highlight_DXgrid () && (m_hisGrid!="") && (decodedtext.string().contains(m_hisGrid))) { + ui->decodedTextBrowser->highlight_callsign(m_hisGrid, QColor(0,0,255), QColor(255,255,255), true); // highlight dxGridEntry + } + if(m_bBestSPArmed && m_mode=="FT4" && CALLING == m_QSOProgress) { QString messagePriority=ui->decodedTextBrowser->CQPriority(); if(messagePriority!="") { @@ -3709,7 +3726,8 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler void MainWindow::pskPost (DecodedText const& decodedtext) { - if (m_diskData || !m_config.spot_to_psk_reporter() || decodedtext.isLowConfidence ()) return; + if (m_diskData || !m_config.spot_to_psk_reporter() || decodedtext.isLowConfidence () + || (decodedtext.string().contains(m_baseCall) && decodedtext.string().contains(m_config.my_grid().left(4)))) return; // prevent self-spotting when running multiple instances QString msgmode=m_mode; QString deCall; @@ -4019,18 +4037,18 @@ void MainWindow::guiUpdate() if(m_QSOProgress==REPORT || m_QSOProgress==ROGER_REPORT) m_bSentReport=true; if(m_bSentReport and (m_QSOProgressROGER_REPORT)) m_bSentReport=false; if(m_mode=="JT4") gen4_(message, &ichk , msgsent, const_cast (itone), - &m_currentMessageType, 22, 22); + &m_currentMessageType, (FCL)22, (FCL)22); if(m_mode=="JT9") gen9_(message, &ichk, msgsent, const_cast (itone), - &m_currentMessageType, 22, 22); - if(m_mode=="JT65") gen65_(message, &ichk, msgsent, const_cast (itone), - &m_currentMessageType, 22, 22); + &m_currentMessageType, (FCL)22, (FCL)22); + if(m_mode=="JT65") gen65(message, &ichk, msgsent, const_cast (itone), + &m_currentMessageType); if(m_mode=="WSPR") genwspr_(message, msgsent, const_cast (itone), - 22, 22); + (FCL)22, (FCL)22); if(m_mode=="MSK144" or m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" or m_mode=="FST4W" || "Q65" == m_mode) { if(m_mode=="MSK144") { genmsk_128_90_(message, &ichk, msgsent, const_cast (itone), - &m_currentMessageType, 37, 37); + &m_currentMessageType, (FCL)37, (FCL)37); if(m_restart) { int nsym=144; if(itone[40]==-40) nsym=40; @@ -4046,7 +4064,7 @@ void MainWindow::guiUpdate() int n3=0; char ft8msgbits[77]; genft8_(message, &i3, &n3, msgsent, const_cast (ft8msgbits), - const_cast (itone), 37, 37); + const_cast (itone), (FCL)37, (FCL)37); int nsym=79; int nsps=4*1920; float fsample=48000.0; @@ -4073,7 +4091,7 @@ void MainWindow::guiUpdate() int ichk=0; char ft4msgbits[77]; genft4_(message, &ichk, msgsent, const_cast (ft4msgbits), - const_cast(itone), 37, 37); + const_cast(itone), (FCL)37, (FCL)37); int nsym=103; int nsps=4*576; float fsample=48000.0; @@ -4095,7 +4113,7 @@ void MainWindow::guiUpdate() ba2msg(ba,message); } genfst4_(message,&ichk,msgsent,const_cast (fst4msgbits), - const_cast(itone), &iwspr, 37, 37); + const_cast(itone), &iwspr, (FCL)37, (FCL)37); int hmod=1; if(m_config.x2ToneSpacing()) hmod=2; if(m_config.x4ToneSpacing()) hmod=4; @@ -4122,7 +4140,7 @@ void MainWindow::guiUpdate() if(m_mode=="Q65") { int i3=-1; int n3=-1; - genq65_(message,&ichk,msgsent,const_cast(itone),&i3,&n3,37,37); + genq65_(message, &ichk,msgsent, const_cast(itone), &i3, &n3, (FCL)37, (FCL)37); int nsps=1800; if(m_TRperiod==30) nsps=3600; if(m_TRperiod==60) nsps=7200; @@ -5374,7 +5392,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) auto is_type_one = !is77BitMode () && is_compound && shortList (my_callsign); auto const& my_grid = m_config.my_grid ().left (4); auto const& hisBase = Radio::base_callsign (hisCall); - save_dxbase_(const_cast ((hisBase + " ").left (6).toLatin1().constData()),6); + save_dxbase_(const_cast ((hisBase + " ").left(6).toLatin1().constData()), (FCL)6); auto eme_short_codes = m_config.enable_VHF_features () && ui->cbShMsgs->isChecked () && m_mode == "JT65"; @@ -5761,7 +5779,7 @@ void MainWindow::msgtype(QString t, QLineEdit* tx) //msgtype() QByteArray s=t.toUpper().toLocal8Bit(); ba2msg(s,message); int ichk=1,itype=0; - gen65_(message,&ichk,msgsent,const_cast(itone0),&itype,22,22); + gen65(message, &ichk,msgsent, const_cast(itone0), &itype); msgsent[22]=0; bool text=false; bool shortMsg=false; @@ -5859,7 +5877,7 @@ void MainWindow::on_dxCallEntry_textChanged (QString const& call) void MainWindow::on_dxCallEntry_editingFinished() { auto const& dxBase = Radio::base_callsign (m_hisCall); - save_dxbase_(const_cast ((dxBase + " ").left (6).toLatin1().constData()),6); + save_dxbase_(const_cast ((dxBase + " ").left (6).toLatin1().constData()), (FCL)6); } @@ -5880,7 +5898,7 @@ void MainWindow::on_dxGridEntry_textChanged (QString const& grid) int nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter; azdist_(const_cast ((m_config.my_grid () + " ").left (6).toLatin1().constData()), const_cast ((m_hisGrid + " ").left (6).toLatin1().constData()),&utch, - &nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,6,6); + &nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,(FCL)6,(FCL)6); QString t; int nd=nDkm; if(m_config.miles()) nd=nDmiles; @@ -6012,6 +6030,8 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, m_xSent.clear (); m_xRcvd.clear (); + if (m_config.clear_DXcall ()) ui->dxCallEntry->clear (); + if (m_config.clear_DXgrid ()) ui->dxGridEntry->clear (); } qint64 MainWindow::nWidgets(QString t) @@ -6221,7 +6241,6 @@ void MainWindow::on_actionFT8_triggered() m_bFast9=false; m_bFastMode=false; WSPR_config(false); - switch_mode (Modes::FT8); m_nsps=6912; m_FFTSize = m_nsps / 2; Q_EMIT FFTSize (m_FFTSize); @@ -6272,6 +6291,8 @@ void MainWindow::on_actionFT8_triggered() on_fox_log_action_triggered(); } if(SpecOp::HOUND == m_config.special_op_id()) { + ui->houndButton->setChecked(true); + ui->houndButton->setStyleSheet("background-color: #ff0000;"); ui->txFirstCheckBox->setChecked(false); ui->txFirstCheckBox->setEnabled(false); ui->cbAutoSeq->setEnabled(false); @@ -6289,6 +6310,8 @@ void MainWindow::on_actionFT8_triggered() ui->txb4->setEnabled(false); ui->txb5->setEnabled(false); ui->txb6->setEnabled(false); + } else { + switch_mode (Modes::FT8); } if (SpecOp::NONE < m_config.special_op_id () && SpecOp::FOX > m_config.special_op_id ()) { @@ -7034,6 +7057,7 @@ void MainWindow::on_rptSpinBox_valueChanged(int n) void MainWindow::on_tuneButton_clicked (bool checked) { + tuneATU_Timer.start (120000); // tune watchdog (120s) static bool lastChecked = false; if (lastChecked == checked) return; lastChecked = checked; @@ -7814,7 +7838,7 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de showNormal (); raise (); } - if (text.contains (QRegularExpression {R"(^(CQ |CQDX |QRZ ))"})) { + if ((text.contains (QRegularExpression {R"(^(CQ |CQDX |QRZ ))"})) || (ui->cbHoldTxFreq->isChecked ())) { // a message we are willing to accept and auto reply to m_bDoubleClicked = true; } @@ -8010,7 +8034,7 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout int nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter; azdist_(const_cast ((m_config.my_grid () + " ").left (6).toLatin1 ().constData ()), const_cast ((grid + " ").left (6).toLatin1 ().constData ()),&utch, - &nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,6,6); + &nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,(FCL)6,(FCL)6); QString t1; if(m_config.miles()) { t1 = t1.asprintf("%7d",nDmiles); @@ -9221,6 +9245,7 @@ void MainWindow::foxTest() void MainWindow::write_all(QString txRx, QString message) { + if (!(ui->actionDisable_writing_of_ALL_TXT->isChecked())) { QString line; QString t; QString msg; @@ -9261,6 +9286,8 @@ void MainWindow::write_all(QString txRx, QString message) } QString file_name="ALL.TXT"; + if (ui->actionSplit_ALL_TXT_yearly->isChecked()) file_name=(time.toString("yyyy") + "-" + "ALL.TXT"); + if (ui->actionSplit_ALL_TXT_monthly->isChecked()) file_name=(time.toString("yyyy-MM") + "-" + "ALL.TXT"); if (m_mode=="WSPR") file_name="ALL_WSPR.TXT"; QFile f{m_config.writeable_data_dir().absoluteFilePath(file_name)}; if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { @@ -9279,6 +9306,7 @@ void MainWindow::write_all(QString txRx, QString message) QTimer::singleShot (0, [=] { // don't block guiUpdate MessageBox::warning_message(this, tr ("Log File Error"), message2); }); } + } } void MainWindow::chkFT4() @@ -9443,3 +9471,55 @@ QString MainWindow::WSPR_message() } return msg2; } + +void MainWindow::on_houndButton_clicked (bool checked) +{ + if (checked) { + ui->houndButton->setStyleSheet("background-color: #ff0000;"); + m_config.setSpecial_Hound(); + } else { + ui->houndButton->setStyleSheet(""); + m_config.setSpecial_None(); + } + on_actionFT8_triggered(); +} + +void MainWindow::on_ft8Button_clicked() +{ + ui->houndButton->setChecked(false); + ui->houndButton->setStyleSheet(""); + m_config.setSpecial_None(); + on_actionFT8_triggered(); +} + +void MainWindow::on_ft4Button_clicked() +{ + ui->houndButton->setChecked(false); + ui->houndButton->setStyleSheet(""); + m_config.setSpecial_None(); + on_actionFT4_triggered(); +} + +void MainWindow::on_msk144Button_clicked() +{ + ui->houndButton->setChecked(false); + ui->houndButton->setStyleSheet(""); + m_config.setSpecial_None(); + on_actionMSK144_triggered(); +} + +void MainWindow::on_q65Button_clicked() +{ + ui->houndButton->setChecked(false); + ui->houndButton->setStyleSheet(""); + m_config.setSpecial_None(); + on_actionQ65_triggered(); +} + +void MainWindow::on_jt65Button_clicked() +{ + ui->houndButton->setChecked(false); + ui->houndButton->setStyleSheet(""); + m_config.setSpecial_None(); + on_actionJT65_triggered(); +} diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 139c30c3b..2fda134bb 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -141,6 +141,12 @@ private: private slots: void initialize_fonts (); + void on_houndButton_clicked(bool checked); + void on_ft8Button_clicked(); + void on_ft4Button_clicked(); + void on_msk144Button_clicked(); + void on_q65Button_clicked(); + void on_jt65Button_clicked(); void on_tx1_editingFinished(); void on_tx2_editingFinished(); void on_tx3_editingFinished(); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index bb9b22b77..b738dd2bf 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -2,6 +2,14 @@ MainWindow + + + 0 + 0 + 882 + 658 + + WSJT-X by K1JT @@ -552,362 +560,15 @@ - - - - - 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> - - - If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode. - - - 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; -} - - - ? - - - - + + Pwr - - - - Adjust Tx audio level - - - 450 - - - 0 - - - Qt::Vertical - - - true - - - true - - - QSlider::TicksBelow - - - 50 - - - - - - - - 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 - - - dxCallEntry - - - - - - - - - - - - 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 - - - dxGridEntry - - - - - - - - 0 - 0 - - - - Callsign of station to be worked - - - 11 - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - Locator of station to be worked - - - ` - - - 6 - - - Qt::AlignCenter - - - - - - - - - Search for callsign in database - - - &Lookup - - - - - - - Add callsign and locator to database - - - Add - - - - - - - true - - - Az: 251 16553 km - - - Qt::AlignCenter - - - 4 - - - - - - - - - + @@ -946,40 +607,7 @@ QPushButton[state="ok"] { - - - - - 0 - 0 - - - - USB dial frequency - - - QLabel { - font-family: MS Shell Dlg 2; - font-size: 16pt; - color : yellow; - background-color : black; -} -QLabel[oob="true"] { - background-color: red; -} - - - 14.078 000 - - - Qt::AlignCenter - - - 5 - - - - + @@ -2761,10 +2389,44 @@ Double-click to reset to the standard 73 message + + + + + 100 + 16777215 + + + + <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html> + + + Frequency entry + + + Select operating band or enter frequency in MHz or enter kHz increment followed by k. + + + true + + + QComboBox::NoInsert + + + QComboBox::AdjustToMinimumContentsLengthWithIcon + + + + + + 100 + 16777215 + + Qt::AlignCenter @@ -2818,28 +2480,489 @@ Yellow when too low - - + + + + + 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 + + + dxCallEntry + + + + + + + + + + + + 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 + + + dxGridEntry + + + + + + + + 0 + 0 + + + + Callsign of station to be worked + + + 11 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Locator of station to be worked + + + ` + + + 6 + + + Qt::AlignCenter + + + + + + + + + Search for callsign in database + + + &Lookup + + + + + + + Add callsign and locator to database + + + Add + + + + + + + true + + + Az: 251 16553 km + + + Qt::AlignCenter + + + 4 + + + + + + + + + + - <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html> + Adjust Tx audio level - - Frequency entry + + 450 - - Select operating band or enter frequency in MHz or enter kHz increment followed by k. + + 0 - + + Qt::Vertical + + true - - QComboBox::NoInsert + + true - - QComboBox::AdjustToMinimumContentsLengthWithIcon + + QSlider::TicksBelow + + + 50 + + + + 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> + + + If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode. + + + 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; +} + + + ? + + + + + + + + 0 + 0 + + + + USB dial frequency + + + QLabel { + font-family: MS Shell Dlg 2; + font-size: 16pt; + color : yellow; + background-color : black; +} +QLabel[oob="true"] { + background-color: red; +} + + + 14.078 000 + + + Qt::AlignCenter + + + 5 + + + + + + + + + + 32 + 16777215 + + + + Toggle FT8 hound mode On/Off + + + H + + + true + + + + + + + + 32 + 16777215 + + + + Switch to FT8 mode + + + FT8 + + + + + + + + 32 + 16777215 + + + + Switch to FT4 mode + + + FT4 + + + + + + + + 32 + 16777215 + + + + Switch to MSK144 mode + + + MSK + + + + + + + + 32 + 16777215 + + + + Switch to Q65 mode + + + Q65 + + + + + + + + 32 + 16777215 + + + + Switch to JT65 mode + + + JT65 + + + + + @@ -2852,7 +2975,7 @@ Yellow when too low 0 0 - 842 + 882 21 @@ -2913,6 +3036,11 @@ Yellow when too low + + + + + @@ -3461,6 +3589,41 @@ Yellow when too low Quick-Start Guide to WSJT-X 2.5.0 and MAP65 3.0 + + + true + + + true + + + Don't split ALL.TXT + + + + + true + + + Split ALL.TXT yearly + + + + + true + + + Split ALL.TXT monthly + + + + + true + + + Disable writing of ALL.TXT + + @@ -3521,7 +3684,6 @@ Yellow when too low tuneButton cbMenus bandComboBox - readFreq sbNB dxCallEntry dxGridEntry diff --git a/widgets/signalmeter.cpp b/widgets/signalmeter.cpp index 60e49b565..b9724d16a 100644 --- a/widgets/signalmeter.cpp +++ b/widgets/signalmeter.cpp @@ -77,7 +77,7 @@ SignalMeter::SignalMeter (QWidget * parent) outer_layout->setSpacing (0); auto inner_layout = new QHBoxLayout; - inner_layout->setContentsMargins (9, 0, 9, 0); + inner_layout->setContentsMargins (1, 0, 1, 0); inner_layout->setSpacing (0); m_meter = new MeterWidget;