From c6bc3c64bb915f7abe197c655733b61a126e6000 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Jan 2019 07:45:59 -0500 Subject: [PATCH 1/5] Add parameters for FT8 and Ft2 to wavhdr.f90. --- lib/wavhdr.f90 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/wavhdr.f90 b/lib/wavhdr.f90 index b54fba787..6568c1fa6 100644 --- a/lib/wavhdr.f90 +++ b/lib/wavhdr.f90 @@ -37,17 +37,17 @@ module wavhdr subroutine set_wsjtx_wav_params(fMHz,mode,nsubmode,ntrperiod,id2) - parameter (NBANDS=23,NMODES=11) + parameter (NBANDS=23,NMODES=13) character*8 mode,modes(NMODES) integer*2 id2(4) - integer iperiod(7) + integer iperiod(8) real fband(NBANDS) data fband/0.137,0.474,1.8,3.5,5.1,7.0,10.14,14.0,18.1,21.0,24.9, & 28.0,50.0,144.0,222.0,432.0,902.0,1296.0,2304.0,3400.0, & 5760.0,10368.0,24048.0/ data modes/'Echo','FSK441','ISCAT','JT4','JT65','JT6M','JT9', & - 'JT9+JT65','JTMS','JTMSK','WSPR'/ - data iperiod/5,10,15,30,60,120,900/ + 'JT9+JT65','JTMS','JTMSK','WSPR','FT8','FT2'/ + data iperiod/5,10,15,30,60,120,900,0/ dmin=1.e30 iband=0 @@ -64,7 +64,7 @@ module wavhdr enddo ip=0 - do i=1,7 + do i=1,8 if(ntrperiod.eq.iperiod(i)) ip=i enddo @@ -78,15 +78,15 @@ module wavhdr subroutine get_wsjtx_wav_params(id2,band,mode,nsubmode,ntrperiod,ok) - parameter (NBANDS=23,NMODES=11) + parameter (NBANDS=23,NMODES=13) character*8 mode,modes(NMODES) character*6 band,bands(NBANDS) integer*2 id2(4) - integer iperiod(7) + integer iperiod(8) logical ok data modes/'Echo','FSK441','ISCAT','JT4','JT65','JT6M','JT9', & - 'JT9+JT65','JTMS','JTMSK','WSPR'/ - data iperiod/5,10,15,30,60,120,900/ + 'JT9+JT65','JTMS','JTMSK','WSPR','FT8','FT2'/ + data iperiod/5,10,15,30,60,120,900,0/ data bands/'2190m','630m','160m','80m','60m','40m','30m','20m', & '17m','15m','12m','10m','6m','2m','1.25m','70cm','33cm', & '23cm','13cm','9cm','6cm','3cm','1.25cm'/ @@ -95,7 +95,7 @@ module wavhdr if(id2(1).lt.1 .or. id2(1).gt.NBANDS) ok=.false. if(id2(2).lt.1 .or. id2(2).gt.NMODES) ok=.false. if(id2(3).lt.1 .or. id2(3).gt.8) ok=.false. - if(id2(4).lt.1 .or. id2(4).gt.7) ok=.false. + if(id2(4).lt.1 .or. id2(4).gt.8) ok=.false. if(ok) then band=bands(id2(1)) From c81af0bbe571a7d2cc1120a060bc03d9728d9c24 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Jan 2019 08:57:46 -0500 Subject: [PATCH 2/5] Updates to code for stand-alone ft2[.exe]. --- lib/ft2/ft2.f90 | 61 +++++++++++++++++++++++++++++++++++------ lib/ft2/g4.cmd | 3 +- lib/ft2/gcom1.f90 | 6 ++-- lib/ft2/libwsjt_fort.a | Bin 1699796 -> 1699980 bytes 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/lib/ft2/ft2.f90 b/lib/ft2/ft2.f90 index 129655feb..e5c389f90 100644 --- a/lib/ft2/ft2.f90 +++ b/lib/ft2/ft2.f90 @@ -6,8 +6,21 @@ program ft2 logical allok character*20 pttport character*8 arg -! integer*2 iwave2(30000) + character*80 fname + integer*2 id2(30000) + open(12,file='all_ft2.txt',status='unknown',position='append') + nargs=iargc() + if(nargs.eq.1) then + call getarg(1,fname) + open(10,file=fname,status='old',access='stream') + read(10) id2(1:22) !Read (and ignore) the header + read(10) id2 !Read the Rx data + close(10) + call ft2_decode(fname(1:17),nfqso,id2,ndecodes,mycall,hiscall,nrx) + go to 999 + endif + allok=.true. ! Get home-station details open(10,file='ft2.ini',status='old',err=1) @@ -26,13 +39,13 @@ program ft2 call padevsub(idevin,idevout) if(idevin.ne.ndevin .or. idevout.ne.ndevout) allok=.false. i1=0 + i1=ptt(nport,1,1,iptt) i1=ptt(nport,1,0,iptt) if(i1.lt.0 .and. nport.ne.0) allok=.false. if(.not.allok) then write(*,"('Please fix setup error(s) and restart.')") go to 999 endif - open(12,file='all_ft2.txt',status='unknown',position='append') nright=1 iwrite=0 @@ -52,7 +65,6 @@ program ft2 QSO_in_progress=.false. ntxed=0 - nargs=iargc() if(nargs.eq.3) then call getarg(1,txmsg) call getarg(2,arg) @@ -67,7 +79,7 @@ program ft2 ! Start the audio streams ierr=ft2audio(idevin,idevout,npabuf,nright,y1,y2,NRING,iwrite,itx, & - iwave,nwave,nfsample,nTxOK,nTransmitting,ngo) + iwave,nwave+3*1152,nfsample,nTxOK,nTransmitting,ngo) if(ierr.ne.0) then print*,'Error',ierr,' starting audio input and/or output.' endif @@ -76,13 +88,15 @@ program ft2 subroutine update(total_time,ic1,ic2) + use wavhdr + type(hdr) h real*8 total_time integer*8 count0,count1,clkfreq integer ptt integer*2 id(30000) - logical transmitted,level + logical transmitted,level,ok character*70 line - character cdatetime*17 + character cdatetime*17,fname*17,mode*8,band*6 include 'gcom1.f90' data nt0/-1/,transmitted/.false./,snr/-99.0/ data level/.false./ @@ -157,9 +171,39 @@ subroutine update(total_time,ic1,ic2) call ft2_decode(cdatetime(),nfqso,id,ndecodes,mycall,hiscall,nrx) call system_clock(count1,clkfreq) ! tdecode=float(count1-count0)/float(clkfreq) -! write(*,3001) trun -!3001 format(f10.3) + if(ndecodes.ge.1) then + fMHz=7.074 + mode='FT2' + nsubmode=1 + ntrperiod=0 + h=default_header(12000,30000) + k=0 + do i=1,250 + sq=0 + do n=1,120 + k=k+1 + x=id(k) + sq=sq + x*x + enddo + write(43,3043) i,0.01*i,1.e-4*sq +3043 format(i7,f12.6,f12.3) + enddo + call set_wsjtx_wav_params(fMHz,mode,nsubmode,ntrperiod,id) + band="" + mode="" + nsubmode=-1 + ntrperiod=-1 + call get_wsjtx_wav_params(id,band,mode,nsubmode,ntrperiod,ok) +! write(*,1010) band,ntrperiod,mode,char(ichar('A')-1+id(3)) +!1010 format('Band: ',a6,' T/R period:',i4,' Mode: ',a8,1x,a1) + + fname=cdatetime() + fname(14:17)='.wav' + open(13,file=fname,status='unknown',access='stream') + write(13) h,id + close(13) + endif if(autoseq .and.nrx.eq.2) QSO_in_progress=.true. if(autoseq .and. QSO_in_progress .and. nrx.ge.1 .and. nrx.le.4) then lrx(nrx)=.true. @@ -220,6 +264,7 @@ subroutine transmit(nfunc,ftx,iptt) if(nfunc.eq.4) txmsg=trim(hiscall)//' '//trim(mycall)//' RR73' if(nfunc.eq.5) txmsg='TNX 73 GL' call ft2_iwave(txmsg,ftx,snrdb,iwave) + iwave(23041:)=0 i1=ptt(nport,1,1,iptt) ntxok=1 n=len(trim(txmsg)) diff --git a/lib/ft2/g4.cmd b/lib/ft2/g4.cmd index 5abf200e6..0894dbebe 100644 --- a/lib/ft2/g4.cmd +++ b/lib/ft2/g4.cmd @@ -1,6 +1,7 @@ gcc -c ft2audio.c gcc -c ptt.c gfortran -c ../77bit/packjt77.f90 +gfortran -c ../wavhdr.f90 gfortran -c ../crc.f90 -gfortran -o ft2 -fbounds-check -fno-second-underscore -ffpe-trap=invalid,zero -Wall -Wno-conversion -Wno-character-truncation ft2.f90 ft2_iwave.f90 ft2_decode.f90 getcandidates2.f90 ft2audio.o ptt.o libwsjt_fort.a libwsjt_cxx.a libportaudio.a ../libfftw3f_win.a -lwinmm +gfortran -o ft2 -fbounds-check -fno-second-underscore -ffpe-trap=invalid,zero -Wall -Wno-conversion -Wno-character-truncation ft2.f90 ft2_iwave.f90 ft2_decode.f90 getcandidates2.f90 ft2audio.o ptt.o /JTSDK/wsjtx-output/qt55/2.1.0/Release/build/libwsjt_fort.a /JTSDK/wsjtx-output/qt55/2.1.0/Release/build/libwsjt_cxx.a libportaudio.a ../libfftw3f_win.a -lwinmm rm *.o *.mod diff --git a/lib/ft2/gcom1.f90 b/lib/ft2/gcom1.f90 index 48bf391c6..9402f9d9e 100644 --- a/lib/ft2/gcom1.f90 +++ b/lib/ft2/gcom1.f90 @@ -29,6 +29,6 @@ character*4 mygrid character*3 exch character*37 txmsg -common/gcom1/snrdb,ndevin,ndevout,iwrite,itx,ngo,nTransmitting,nTxOK,nport, & - ntxed,tx_once, y1(NRING),y2(NRING),iwave(NTZ),ltx(5),lrx(5),autoseq, & - QSO_in_progress,mycall,hiscall,hiscall_next,mygrid,exch,txmsg +common/gcom1/snrdb,ndevin,ndevout,iwrite,itx,ngo,nTransmitting,nTxOK,nport, & + ntxed,tx_once,y1(NRING),y2(NRING),iwave(NTZ+3*1152),ltx(5),lrx(5), & + autoseq,QSO_in_progress,mycall,hiscall,hiscall_next,mygrid,exch,txmsg diff --git a/lib/ft2/libwsjt_fort.a b/lib/ft2/libwsjt_fort.a index 53b9c28788462ae1b90759ef98ece412ef8abd85..7884c85bb645b2967400426a8c95083b78f366e3 100644 GIT binary patch delta 2182 zcmb8w4{(#^9S895n*<9`O$>fNvg*1)>tNmw@qSn(39J7(qy{`C;n zJq97x2ch*KgoFWs9WHNgKZN~_5c=969I1kEY$JrzW(a?)fXx(};Mfb>b?drdd$b&J z+m;^Ko({pb=RMdCWnmkB6SlKDY?q_3{c|Qny$|BlXCcmf2jXo-Gj9de;I(7 zh(O#WLELu$;^CDLUwseakQ3tPL5Slz#O%2|$&rOLeQ3h$SRB&qSiyo;NXxzt>8I6@ z9)Ekn<$lOz=OEwG3AxS-IkFFOdk8YEfSkSr`Pj>lk7o+L)S*Z*DBeLRHEW=Reh=l& zH=#tTpfsI_(tHrgh6I#H*}Oypl=k>bP_V1E+8RPNfab(jUNCyY5DHPB_D?_6t+N8x?Toe9~QTVi3;1OK>?3 z!!_-~cZq-3g#TUtpaQOujc|<-xXuUQx^faadZ3F7p;wxq&+3Ezqekef2cSO?nDDF9 z&~tXgBhY_cTQD#N{Z!Y4ub0AIeH8AtstLPB;NG_x?%@pFW5Y14>tU3~U{sI7Xgv+% z$V)KZ_#KRQ2Vo3tf^mE!j58q^SLVSZ$KdhY4Ns-Fpl&xj(;hhs&$k^Kf@h$*;3U~O zKF^b^v&RUx6G}bKc|MC`n1$=%?|{;`4+W>IUc#TS)DA2&+>P)0Je?V}QjK0b*&R2pYHq(Z(G{U)~VV|;8uN&4a>@&f1U z2>P~V-U|7wR#rL8rh$Dh8?0AD=g+bZ{bt%SnK*fGKD$8wJeeeE?_}bpKfj60G4+f2 zGJ9*eB^UBbZrqd|Grwt+^?%CU>GhpcVPE66j2gO z65(E@P4`*Kxem(hmv#Ew3}WSm)4!cTzToa3V<*o&btnG8M!Ba%K-j*8Y!Vw4GJi2! zSj?6cv(?3HZ83X-p1GOazT~T7>0+@YTdr?g#zuup{f3R~`OEJwj{1tDSLhvnvWGiK zKlPI(ra=pBdEZiIiLvi-Xy=BxQ|OvXvXnE^J60*K_SY&&`n5{F#be3;xznk~Wp{hS zBA&4_0%K!DMoKpQ>k8n42rjKTAKN7RA%9 sZ+9@IjFWLOdRpJ^E?2KjVmlh`%Xhic%Xb;|P1nNQdC~_i8@_M;1(ZKCtN;K2 delta 1998 zcmb8w3rrJt90&0475cySuD!dKYkTD-Xca`n2V@upXB6F3M6-~|6knTyZir|Y5;Rr^ zmMLg_Ab;bG(FGHenfPF#3&Ghr;*4{?hMNzDGd`zNi85u3js4q3h-TTcOFsSo?)&@S zFaM^OwE9MV%k}&%k+eNY({ss3`Y+MBT_8i4bOmIZJt(IJ~wM)!Oe z+2I1}bTA&QgR#CD#$&}Wo^6Ejb|#Eng%G%gK9*l0ypVqxLg_-dg>@YeHdjOVM1@d4 z9zu%*;qF`rza4<^*9wTXZiq3h5EHBrlL^EzEPG+jYKR|}L3HnhSd$HLe6kK2`F)qP=+0Vl92;tx(UiV2~gbg-iEU9K9p6bpsZUBA6&3RpMho37FgVO zVA-`9md`$hrRj3elQvjKX2CjhFRbftz3f~mtd|b{qp-J%@G5s8_%Rz{Kb=BYdk4Zg z)<89MLNzx-wR)f?AAVU{F4U>4S3D)Cxe%(~m0Lk=8q`0sVY33Z{-ghk`@c5)d;ek~ zY?m5gyO{;s<1*Nu$HUgs0lTmf_V_8V59@|~N*(Mo?Xc&T^;ww&yI(bXbL~4<2c1oX z{pZVl+PA=wWP)Q=ai1O0aO^(`M~eZDTanQCqtGH6pe4DWl_o(u_6%BcJG5^#XcwBG zU2TMRryAO`wQ!mm;M8`(8NWCvtqsop%Z9`Gs`_v^zbgs4p0)kaC}(*(UzyHxjE)Im zLK(d`ohRv*?S+X^YHISRn7}n($mDqVuah)3kwjQx2$0AD@#a8^arDSA&Y}0QD3flz zV;oQ$&c_pk045`yao#wcTIPxB_GKevp_M(6X#x(&)aNAQIe~_R6AvfSjp4+_U8aY^ ziI3eCMUbMf6gHqL!!@H(#~!+ZEBa2I_h|&#$LShFXi*eVIgQSUCQ))I>wlBs3XNf_ zoY79dk0Ry%4=XK*CaLbKY*+4j-*GX}eO{I6iXY*t8qLzg@*cfh<16nGyq#7Pw6J*mP_v!KS7-e?|B7Bb~HmP-r~;GKS;? zD(~1>vO9#fxkzN_=_iwy(=Gd*i|MBWNe)*+7tGQ}a$_m?*r3wHK}6sxys3l8ZEp5G zb_k74RH0+v!2hEV2&@Wb{d%*+-fU8Dmerfh?#({v&DPVE@np<^S$e<{82fH-wWPON z!72wme#q&h_Q7Ng*GhK`CU0At(>2z@krS;lQ&p4yK_CXhF|ZhGT5Z>uazAl|YB zzQ{>u Date: Fri, 18 Jan 2019 11:51:15 -0500 Subject: [PATCH 3/5] Implement basic Rx capability for FT2 in WSJT-X. --- CMakeLists.txt | 3 + lib/ft2/ft2_decode.f90 | 28 ++++-- ...getcandidates2.f90 => getcandidates2a.f90} | 4 +- models/Modes.cpp | 3 +- models/Modes.hpp | 1 + widgets/mainwindow.cpp | 97 ++++++++++++++++++- widgets/mainwindow.h | 3 + widgets/mainwindow.ui | 9 ++ 8 files changed, 132 insertions(+), 16 deletions(-) rename lib/ft2/{getcandidates2.f90 => getcandidates2a.f90} (93%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef0bac291..a058fa258 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -509,6 +509,8 @@ set (wsjt_FSRCS lib/mskrtd.f90 lib/fsk4hf/ft2sim.f90 lib/fsk4hf/ft2d.f90 + lib/ft2/cdatetime.f90 + lib/ft2/ft2_decode.f90 lib/77bit/my_hash.f90 lib/wsprd/osdwspr.f90 lib/ft8/osd174_91.f90 @@ -550,6 +552,7 @@ set (wsjt_FSRCS lib/sync64.f90 lib/sync65.f90 lib/fsk4hf/getcandidates2.f90 + lib/ft2/getcandidates2a.f90 lib/ft8/sync8.f90 lib/ft8/sync8d.f90 lib/sync9.f90 diff --git a/lib/ft2/ft2_decode.f90 b/lib/ft2/ft2_decode.f90 index e26fc5567..5f7eb95e0 100644 --- a/lib/ft2/ft2_decode.f90 +++ b/lib/ft2/ft2_decode.f90 @@ -1,13 +1,14 @@ -subroutine ft2_decode(cdatetime,nfqso,iwave,ndecodes,mycall,hiscall,nrx) +subroutine ft2_decode(cdatetime0,nfqso,iwave,ndecodes,mycall,hiscall,nrx,line) use crc use packjt77 include 'ft2_params.f90' character message*37,c77*77 + character*61 line character*37 decodes(100) character*120 data_dir - character*17 cdatetime - character*6 mycall,hiscall + character*17 cdatetime0,cdatetime,cdt + character*6 mycall,hiscall,hhmmss complex c2(0:NMAX/16-1) !Complex waveform complex cb(0:NMAX/16-1) complex cd(0:144*10-1) !Complex waveform @@ -30,6 +31,12 @@ subroutine ft2_decode(cdatetime,nfqso,iwave,ndecodes,mycall,hiscall,nrx) logical unpk77_success data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/ + hhmmss=' ' + if(cdatetime0==' ') then + cdt=cdatetime() + hhmmss=cdt(8:13) + endif + fs=12000.0/NDOWN !Sample rate dt=1/fs !Sample interval after downsample (s) tt=NSPS*dt !Duration of "itone" symbols (s) @@ -63,7 +70,7 @@ subroutine ft2_decode(cdatetime,nfqso,iwave,ndecodes,mycall,hiscall,nrx) syncmin=0.2 maxcand=100 nfqso=-1 - call getcandidates2(iwave,fa,fb,maxcand,savg,candidate,ncand) + call getcandidates2a(iwave,fa,fb,maxcand,savg,candidate,ncand) ndecodes=0 do icand=1,ncand f0=candidate(1,icand) @@ -191,11 +198,15 @@ subroutine ft2_decode(cdatetime,nfqso,iwave,ndecodes,mycall,hiscall,nrx) xsnr=db(sybest*sybest) - 115.0 !### Rough estimate of S/N ### nsnr=nint(xsnr) freq=f0+dfbest - write(*,1000) cdatetime,nsnr,ibest/750.0,nint(freq),message, & + write(line,1000) hhmmss,nsnr,ibest/750.0,nint(freq),message +1000 format(a6,i4,f5.2,i5,' + ',1x,a37) + open(24,file='all_ft2.txt',status='unknown',position='append') + write(24,1002) cdatetime0,nsnr,ibest/750.0,nint(freq),message, & nseq,nharderror,nhardmin - write(12,1000) cdatetime,nsnr,ibest/750.0,nint(freq),message, & - nseq,nharderror,nhardmin -1000 format(a17,i4,f6.2,i5,' Rx ',a37,3i5) + if(hhmmss.eq.' ') write(*,1002) cdatetime0,nsnr, & + ibest/750.0,nint(freq),message,nseq,nharderror,nhardmin +1002 format(a17,i4,f6.2,i5,' Rx ',a37,3i5) + close(24) !### Temporary: assume most recent decoded message conveys "hiscall". i0=index(message,' ') @@ -290,4 +301,3 @@ subroutine ft2_downsample(iwave,f0,c) c=c1(0:NMAX/16-1) return end subroutine ft2_downsample - diff --git a/lib/ft2/getcandidates2.f90 b/lib/ft2/getcandidates2a.f90 similarity index 93% rename from lib/ft2/getcandidates2.f90 rename to lib/ft2/getcandidates2a.f90 index dd5dac507..8e7209c9c 100644 --- a/lib/ft2/getcandidates2.f90 +++ b/lib/ft2/getcandidates2a.f90 @@ -1,4 +1,4 @@ -subroutine getcandidates2(id,fa,fb,maxcand,savg,candidate,ncand) +subroutine getcandidates2a(id,fa,fb,maxcand,savg,candidate,ncand) ! For now, hardwired to find the largest peak in the average spectrum @@ -61,4 +61,4 @@ subroutine getcandidates2(id,fa,fb,maxcand,savg,candidate,ncand) endif return -end subroutine getcandidates2 +end subroutine getcandidates2a diff --git a/models/Modes.cpp b/models/Modes.cpp index 9d21459c7..b823e3649 100644 --- a/models/Modes.cpp +++ b/models/Modes.cpp @@ -23,7 +23,8 @@ namespace "MSK144", "QRA64", "FreqCal", - "FT8" + "FT8", + "FT2" }; std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]); } diff --git a/models/Modes.hpp b/models/Modes.hpp index cdf299749..6af3e5ef3 100644 --- a/models/Modes.hpp +++ b/models/Modes.hpp @@ -49,6 +49,7 @@ public: QRA64, FreqCal, FT8, + FT2, MODES_END_SENTINAL_AND_COUNT // this must be last }; Q_ENUM (Mode) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index a3c031c53..54e37905f 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -159,6 +159,10 @@ 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 ft2_decode_(char* cdatetime, int* nfqso, short int id[], int* ndecodes, + char* mycall6, char* hiscall6, int* nrx, char* line, + int len1, int len2, int len3, int len4); } int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols @@ -544,6 +548,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, on_EraseButton_clicked (); QActionGroup* modeGroup = new QActionGroup(this); + ui->actionFT2->setActionGroup(modeGroup); ui->actionFT8->setActionGroup(modeGroup); ui->actionJT9->setActionGroup(modeGroup); ui->actionJT65->setActionGroup(modeGroup); @@ -874,6 +879,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, if(m_bFast9) m_bFastMode=true; ui->cbFast9->setChecked(m_bFast9 or m_bFastMode); + if(m_mode=="FT2") on_actionFT2_triggered(); if(m_mode=="FT8") on_actionFT8_triggered(); if(m_mode=="JT4") on_actionJT4_triggered(); if(m_mode=="JT9") on_actionJT9_triggered(); @@ -1345,7 +1351,8 @@ void MainWindow::dataSink(qint64 frames) if(m_monitoring || m_diskData) { m_wideGraph->dataSink2(s,m_df3,m_ihsym,m_diskData); } - if(m_mode=="MSK144") return; + if(m_mode=="FT2") ft2Data(k); + if(m_mode=="MSK144" or m_mode=="FT2") return; fixStop(); if (m_mode == "FreqCal" @@ -1546,7 +1553,6 @@ void MainWindow::fastSink(qint64 frames) { int k (frames); bool decodeNow=false; - if(k < m_k0) { //New sequence ? memcpy(fast_green2,fast_green,4*703); //Copy fast_green[] to fast_green2[] memcpy(fast_s2,fast_s,4*703*64); //Copy fast_s[] into fast_s2[] @@ -3836,6 +3842,7 @@ void MainWindow::guiUpdate() //Once per second: if(nsec != m_sec0) { +// qDebug() << "cc oneSec" << dec_data.params.kin << m_ihsym; // if((!m_msgAvgWidget or (m_msgAvgWidget and !m_msgAvgWidget->isVisible())) // and (SpecOp::NONE < m_config.special_op_id()) and (SpecOp::HOUND > m_config.special_op_id())) on_actionFox_Log_triggered(); if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { @@ -5497,6 +5504,52 @@ void MainWindow::displayWidgets(qint64 n) genStdMsgs (m_rpt, true); } +void MainWindow::on_actionFT2_triggered() +{ + m_mode="FT2"; + m_modeTx="FT2"; + m_TRperiod=2147483647; + bool bVHF=m_config.enable_VHF_features(); + m_bFast9=false; + m_bFastMode=false; + WSPR_config(false); + switch_mode (Modes::FT2); + m_nsps=6912; + m_FFTSize = m_nsps/2; + Q_EMIT FFTSize (m_FFTSize); + m_hsymStop=50; + setup_status_bar (bVHF); + m_toneSpacing=0.0; //??? + ui->actionFT2->setChecked(true); //??? + m_wideGraph->setMode(m_mode); + m_wideGraph->setModeTx(m_modeTx); + VHF_features_enabled(bVHF); + ui->cbAutoSeq->setChecked(false); + m_fastGraph->hide(); + m_wideGraph->show(); + ui->decodedTextLabel2->setText(" UTC dB DT Freq Message"); + m_wideGraph->setPeriod(m_TRperiod,m_nsps); + m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe + m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe + ui->label_7->setText("Rx Frequency"); + ui->label_6->setText("Band Activity"); + ui->decodedTextLabel->setText( " UTC dB DT Freq Message"); + displayWidgets(nWidgets("111010000100111000010000100110001")); + ui->txrb2->setEnabled(true); + ui->txrb4->setEnabled(true); + ui->txrb5->setEnabled(true); + ui->txrb6->setEnabled(true); + ui->txb2->setEnabled(true); + ui->txb4->setEnabled(true); + ui->txb5->setEnabled(true); + ui->txb6->setEnabled(true); + ui->txFirstCheckBox->setEnabled(true); + ui->cbAutoSeq->setEnabled(true); + ui->labDXped->setVisible(false); + ui->labDXped->setText(""); + statusChanged(); +} + void MainWindow::on_actionFT8_triggered() { m_mode="FT8"; @@ -5599,8 +5652,6 @@ void MainWindow::on_actionFT8_triggered() statusChanged(); } - - void MainWindow::on_actionJT4_triggered() { m_mode="JT4"; @@ -8499,3 +8550,41 @@ void MainWindow::write_all(QString txRx, QString message) MessageBox::warning_message(this, tr ("Log File Error"), message2); }); } } + +void MainWindow::ft2Data(int k) +{ + static int nhsec0=-1; + short id[30000]; + int nhsec=k/6000; + if(nhsec!=nhsec0) { + //Process FT2 data at 0.5 s intervals + int j=k-30000; + if(j<0) j+=NRING; + for(int i=0; i<30000; i++) { + id[i]=dec_data.d2[j]; + j++; + if(j>=NRING) j=j-NRING; + } + if(k>=NRING) { + k=k-NRING; + dec_data.params.kin=k; + } + char cdatetime[]=" "; + char mycall6[] ="K1JT "; + char hiscall6[]="K9AN "; + char line[61]; + int nfqso=1500; + int ndecodes=0; + int nrx=-1; + ft2_decode_(cdatetime,&nfqso,id,&ndecodes,mycall6,hiscall6,&nrx,&line[0], + 17,6,6,61); + line[60]=0; + if(ndecodes>0) { + QString sline{QString::fromLatin1(line)}; + DecodedText decodedtext {sline.replace(QChar::LineFeed,"")}; + ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_mode, + m_config.DXCC(),m_logBook,m_currentBand,m_config.ppfx()); + } + nhsec0=nhsec; + } +} diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index acabffe7f..fad9262c9 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -49,6 +49,7 @@ #define NUM_CW_SYMBOLS 250 #define TX_SAMPLE_RATE 48000 #define N_WIDGETS 33 +#define NRING 432000 extern int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols extern int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID @@ -200,6 +201,7 @@ private slots: void on_actionJT65_triggered(); void on_actionJT9_JT65_triggered(); void on_actionJT4_triggered(); + void on_actionFT2_triggered(); void on_actionFT8_triggered(); void on_TxFreqSpinBox_valueChanged(int arg1); void on_actionSave_decoded_triggered(); @@ -309,6 +311,7 @@ private slots: void on_comboBoxHoundSort_activated (int index); void not_GA_warning_message (); void checkMSK144ContestType(); + void ft2Data(int k); int setTxMsg(int n); bool stdCall(QString const& w); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 4e39e6d6c..ca9551ec2 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -2705,6 +2705,7 @@ list. The list can be maintained in Settings (F2). Mode + @@ -3338,6 +3339,14 @@ list. The list can be maintained in Settings (F2). Erase WSPR hashtable + + + true + + + FT2 + + From 2033a2b33d59d3425c0603caab94bae7652c8684 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Jan 2019 12:33:45 -0500 Subject: [PATCH 4/5] Add a missing file; tweak the FT2 decoder. --- lib/ft2/cdatetime.f90 | 6 ++++++ lib/ft2/ft2_decode.f90 | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 lib/ft2/cdatetime.f90 diff --git a/lib/ft2/cdatetime.f90 b/lib/ft2/cdatetime.f90 new file mode 100644 index 000000000..33deaf30a --- /dev/null +++ b/lib/ft2/cdatetime.f90 @@ -0,0 +1,6 @@ +character*17 function cdatetime() + character cdate*8,ctime*10 + call date_and_time(cdate,ctime) + cdatetime=cdate(3:8)//'_'//ctime + return +end function cdatetime diff --git a/lib/ft2/ft2_decode.f90 b/lib/ft2/ft2_decode.f90 index 5f7eb95e0..b250fca32 100644 --- a/lib/ft2/ft2_decode.f90 +++ b/lib/ft2/ft2_decode.f90 @@ -7,7 +7,7 @@ subroutine ft2_decode(cdatetime0,nfqso,iwave,ndecodes,mycall,hiscall,nrx,line) character*61 line character*37 decodes(100) character*120 data_dir - character*17 cdatetime0,cdatetime,cdt + character*17 cdatetime0,cdatetime character*6 mycall,hiscall,hhmmss complex c2(0:NMAX/16-1) !Complex waveform complex cb(0:NMAX/16-1) @@ -33,8 +33,8 @@ subroutine ft2_decode(cdatetime0,nfqso,iwave,ndecodes,mycall,hiscall,nrx,line) hhmmss=' ' if(cdatetime0==' ') then - cdt=cdatetime() - hhmmss=cdt(8:13) + cdatetime0=cdatetime() + hhmmss=cdatetime0(8:13) endif fs=12000.0/NDOWN !Sample rate From 568fc0810e7539c0d2feab79918fedac66958809 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Jan 2019 16:22:25 -0500 Subject: [PATCH 5/5] Tx now works, more or less, in FT2 mode. Needs testing! --- Modulator.cpp | 20 +++-- lib/ft2/ft2_decode.f90 | 7 +- widgets/displaytext.cpp | 1 + widgets/mainwindow.cpp | 185 +++++++++++++++++++++++++++++++--------- widgets/mainwindow.h | 4 +- 5 files changed, 163 insertions(+), 54 deletions(-) diff --git a/Modulator.cpp b/Modulator.cpp index a7564f6cf..9934e9ab1 100644 --- a/Modulator.cpp +++ b/Modulator.cpp @@ -47,14 +47,13 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol, SoundOutput * stream, Channel channel, bool synchronize, bool fastMode, double dBSNR, int TRperiod) { +// qDebug() << "Mod AA" << symbolsLength << framesPerSymbol << frequency +// << toneSpacing << synchronize << fastMode << dBSNR << TRperiod; Q_ASSERT (stream); // Time according to this computer which becomes our base time qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; - if (m_state != Idle) - { - stop (); - } + if(m_state != Idle) stop (); m_quickClose = false; @@ -92,6 +91,14 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol, if (synchronize && !m_tuning && !m_bFastMode) { m_silentFrames = m_ic + m_frameRate / (1000 / delay_ms) - (mstr * (m_frameRate / 1000)); } + if(symbolsLength==144 and framesPerSymbol==160 and toneSpacing==60) { + //### FT2 params + delay_ms=100; + mstr=1947; + m_ic=0; + m_silentFrames=0; + } +// qDebug() << "Mod AB" << delay_ms << mstr << m_ic << m_silentFrames; initialize (QIODevice::ReadOnly, channel); Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ? @@ -170,7 +177,8 @@ qint64 Modulator::readData (char * data, qint64 maxSize) case Active: { unsigned int isym=0; -// qDebug() << "Mod A" << m_toneSpacing << m_ic; +// qDebug() << "Mod A" << m_toneSpacing << m_frequency << m_nsps +// << m_ic << m_symbolsLength << icw[0]; if(!m_tuning) isym=m_ic/(4.0*m_nsps); // Actual fsample=48000 bool slowCwId=((isym >= m_symbolsLength) && (icw[0] > 0)) && (!m_bFastMode); if(m_TRperiod==3) slowCwId=false; @@ -289,6 +297,8 @@ qint64 Modulator::readData (char * data, qint64 maxSize) if (m_ic > i1) m_amp = 0.0; sample=qRound(m_amp*qSin(m_phi)); + +//Here's where we transmit from a precomputed wave[] array: if(m_toneSpacing < 0) sample=qRound(m_amp*foxcom_.wave[m_ic]); // if(m_ic < 100) qDebug() << "Mod C" << m_ic << m_amp << foxcom_.wave[m_ic] << sample; diff --git a/lib/ft2/ft2_decode.f90 b/lib/ft2/ft2_decode.f90 index b250fca32..1d1bb6a53 100644 --- a/lib/ft2/ft2_decode.f90 +++ b/lib/ft2/ft2_decode.f90 @@ -31,12 +31,7 @@ subroutine ft2_decode(cdatetime0,nfqso,iwave,ndecodes,mycall,hiscall,nrx,line) logical unpk77_success data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/ - hhmmss=' ' - if(cdatetime0==' ') then - cdatetime0=cdatetime() - hhmmss=cdatetime0(8:13) - endif - + hhmmss=cdatetime0(8:13) fs=12000.0/NDOWN !Sample rate dt=1/fs !Sample interval after downsample (s) tt=NSPS*dt !Duration of "itone" symbols (s) diff --git a/widgets/displaytext.cpp b/widgets/displaytext.cpp index 8058908ba..0f1a9ce1b 100644 --- a/widgets/displaytext.cpp +++ b/widgets/displaytext.cpp @@ -455,6 +455,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,bool bFastMode) { QString t1=" @ "; + if(modeTx=="FT2") t1=" + "; if(modeTx=="FT8") t1=" ~ "; if(modeTx=="JT4") t1=" $ "; if(modeTx=="JT65") t1=" # "; diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 54e37905f..5ae884a4d 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -99,6 +99,9 @@ extern "C" { void genft8_(char* msg, int* i3, int* n3, char* msgsent, char ft8msgbits[], int itone[], fortran_charlen_t, fortran_charlen_t); + void genft2_(char* msg, int* ichk, char* msgsent, int itone[], int* itype, + fortran_charlen_t, fortran_charlen_t); + void gen4_(char* msg, int* ichk, char* msgsent, int itone[], int* itext, fortran_charlen_t, fortran_charlen_t); @@ -1883,6 +1886,10 @@ void MainWindow::keyPressEvent (QKeyEvent * e) break; case Qt::Key_F1: if(bAltF1F5) { + if(m_mode=="FT2") { + ft2_tx(6); + return; + } auto_tx_mode(true); on_txb6_clicked(); return; @@ -1892,6 +1899,10 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } case Qt::Key_F2: if(bAltF1F5) { + if(m_mode=="FT2") { + ft2_tx(2); + return; + } auto_tx_mode(true); on_txb2_clicked(); return; @@ -1901,6 +1912,10 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } case Qt::Key_F3: if(bAltF1F5) { + if(m_mode=="FT2") { + ft2_tx(3); + return; + } auto_tx_mode(true); on_txb3_clicked(); return; @@ -1910,6 +1925,10 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } case Qt::Key_F4: if(bAltF1F5) { + if(m_mode=="FT2") { + ft2_tx(4); + return; + } auto_tx_mode(true); on_txb4_clicked(); return; @@ -1920,6 +1939,10 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } case Qt::Key_F5: if(bAltF1F5) { + if(m_mode=="FT2") { + ft2_tx(5); + return; + } auto_tx_mode(true); on_txb5_clicked(); return; @@ -3372,7 +3395,7 @@ void MainWindow::guiUpdate() double tx1=0.0; double tx2=txDuration; - if(m_mode=="FT8") icw[0]=0; //No CW ID in FT8 mode + if(m_mode=="FT8" or m_mode=="FT2") icw[0]=0; //No CW ID in FT2 or FT8 mode if((icw[0]>0) and (!m_bFast9)) tx2 += icw[0]*2560.0/48000.0; //Full length including CW ID if(tx2>m_TRperiod) tx2=m_TRperiod; @@ -3782,21 +3805,22 @@ void MainWindow::guiUpdate() } } - if (g_iptt == 1 && m_iptt0 == 0) - { - auto const& current_message = QString::fromLatin1 (msgsent); - if(m_config.watchdog () && !m_mode.startsWith ("WSPR") - && current_message != m_msgSent0) { - tx_watchdog (false); // in case we are auto sequencing - m_msgSent0 = current_message; - } + if (g_iptt == 1 && m_iptt0 == 0) { + auto const& current_message = QString::fromLatin1 (msgsent); + if(m_config.watchdog () && !m_mode.startsWith ("WSPR") + && current_message != m_msgSent0) { + tx_watchdog (false); // in case we are auto sequencing + m_msgSent0 = current_message; + } + if(m_mode!="FT2") { if(!m_tune) write_all("Tx",m_currentMessage); if (m_config.TX_messages () && !m_tune && SpecOp::FOX!=m_config.special_op_id()) { ui->decodedTextBrowser2->displayTransmittedText(current_message, m_modeTx, - ui->TxFreqSpinBox->value(),m_bFastMode); + ui->TxFreqSpinBox->value(),m_bFastMode); } + } switch (m_ntx) { @@ -3842,7 +3866,7 @@ void MainWindow::guiUpdate() //Once per second: if(nsec != m_sec0) { -// qDebug() << "cc oneSec" << dec_data.params.kin << m_ihsym; +// qDebug() << "cc onesec" << g_iptt << m_iptt0; // if((!m_msgAvgWidget or (m_msgAvgWidget and !m_msgAvgWidget->isVisible())) // and (SpecOp::NONE < m_config.special_op_id()) and (SpecOp::HOUND > m_config.special_op_id())) on_actionFox_Log_triggered(); if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { @@ -5519,7 +5543,7 @@ void MainWindow::on_actionFT2_triggered() Q_EMIT FFTSize (m_FFTSize); m_hsymStop=50; setup_status_bar (bVHF); - m_toneSpacing=0.0; //??? + m_toneSpacing=0.8*75.0; //??? ui->actionFT2->setChecked(true); //??? m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); @@ -6815,6 +6839,15 @@ void MainWindow::transmit (double snr) true, false, snr, m_TRperiod); } + if (m_modeTx == "FT2") { + toneSpacing=0.8*12000.0/160.0; +// if(SpecOp::FOX==m_config.special_op_id() and !m_tune) toneSpacing=-1; + Q_EMIT sendMessage (NUM_FT2_SYMBOLS, + 160.0, ui->TxFreqSpinBox->value() - m_XIT, + toneSpacing, m_soundOutput, m_config.audio_output_channel (), + true, false, snr, 2); + } + if (m_modeTx == "QRA64") { if(m_nSubMode==0) toneSpacing=12000.0/6912.0; if(m_nSubMode==1) toneSpacing=2*12000.0/6912.0; @@ -8555,36 +8588,104 @@ void MainWindow::ft2Data(int k) { static int nhsec0=-1; short id[30000]; + int nhsec=k/6000; - if(nhsec!=nhsec0) { - //Process FT2 data at 0.5 s intervals - int j=k-30000; - if(j<0) j+=NRING; - for(int i=0; i<30000; i++) { - id[i]=dec_data.d2[j]; - j++; - if(j>=NRING) j=j-NRING; - } - if(k>=NRING) { - k=k-NRING; - dec_data.params.kin=k; - } - char cdatetime[]=" "; - char mycall6[] ="K1JT "; - char hiscall6[]="K9AN "; - char line[61]; - int nfqso=1500; - int ndecodes=0; - int nrx=-1; - ft2_decode_(cdatetime,&nfqso,id,&ndecodes,mycall6,hiscall6,&nrx,&line[0], - 17,6,6,61); - line[60]=0; - if(ndecodes>0) { - QString sline{QString::fromLatin1(line)}; - DecodedText decodedtext {sline.replace(QChar::LineFeed,"")}; - ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_mode, - m_config.DXCC(),m_logBook,m_currentBand,m_config.ppfx()); - } - nhsec0=nhsec; + if(nhsec==nhsec0) return; + +//Process FT2 data at 0.5 s intervals + int j=k/6000; + j=6000*j-30000; + if(j<0) j+=NRING; + for(int i=0; i<30000; i++) { + id[i]=dec_data.d2[j]; + j++; + if(j>=NRING) j=j-NRING; } + + if(k>=NRING) { +//Wrap the ring buffer pointer + k=k-NRING; + dec_data.params.kin=k; + } + + auto time = QDateTime::currentDateTimeUtc (); + QString t=time.toString("yyMMdd_hhmmss.sss"); + QByteArray ba=time.toString("yyMMdd_hhmmss.sss").toLatin1(); + char* cdatetime=ba.data(); + char mycall6[] ="K1JT "; + char hiscall6[]="K9AN "; + char line[61]; + int nfqso=1500; + int ndecodes=0; + int nrx=-1; + ft2_decode_(cdatetime,&nfqso,id,&ndecodes,mycall6,hiscall6,&nrx,&line[0], + 17,6,6,61); + line[60]=0; + if(ndecodes>0) { + QString sline{QString::fromLatin1(line)}; + DecodedText decodedtext {sline.replace(QChar::LineFeed,"")}; + ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_mode, + m_config.DXCC(),m_logBook,m_currentBand,m_config.ppfx()); + } + nhsec0=nhsec; +} + +void MainWindow::ft2_tx(int ntx) +{ + if(g_iptt!=0) return; //Alreadt transmitting? + static char message[38]; + static char msgsent[38]; + QByteArray ba; + m_ntx=ntx; + if(m_ntx == 1) ba=ui->tx1->text().toLocal8Bit(); + if(m_ntx == 2) ba=ui->tx2->text().toLocal8Bit(); + if(m_ntx == 3) ba=ui->tx3->text().toLocal8Bit(); + if(m_ntx == 4) ba=ui->tx4->text().toLocal8Bit(); + if(m_ntx == 5) ba=ui->tx5->currentText().toLocal8Bit(); + if(m_ntx == 6) ba=ui->tx6->text().toLocal8Bit(); + if(m_ntx == 7) ba=ui->genMsg->text().toLocal8Bit(); + if(m_ntx == 8) ba=ui->freeTextMsg->currentText().toLocal8Bit(); + ba2msg(ba,message); + int ichk=0; + int itype=-1; + genft2_(message, &ichk, msgsent, const_cast(itone), &itype, 37, 37); + msgsent[37]=0; + m_currentMessage = QString::fromLatin1(msgsent); + on_txb6_clicked(); + auto_tx_mode(true); + + icw[0]=0; + g_iptt = 1; + setRig (); + setXIT (ui->TxFreqSpinBox->value ()); + Q_EMIT m_config.transceiver_ptt (true); //Assert the PTT + m_tx_when_ready = true; + + if (g_iptt == 1 && m_iptt0 == 0) { + auto const& current_message = QString::fromLatin1 (msgsent); + write_all("Tx",m_currentMessage); + + if (m_config.TX_messages () && !m_tune && SpecOp::FOX!=m_config.special_op_id()) { + ui->decodedTextBrowser2->displayTransmittedText(current_message, m_modeTx, + ui->TxFreqSpinBox->value(),m_bFastMode); + } + + switch (m_ntx) + { + case 1: m_QSOProgress = REPLYING; break; + case 2: m_QSOProgress = REPORT; break; + case 3: m_QSOProgress = ROGER_REPORT; break; + case 4: m_QSOProgress = ROGERS; break; + case 5: m_QSOProgress = SIGNOFF; break; + case 6: m_QSOProgress = CALLING; break; + default: break; // determined elsewhere + } + m_transmitting = true; + transmitDisplay (true); + statusUpdate (); + } + + if(!m_btxok && m_btxok0 && g_iptt==1) stopTx(); + +// if(!m_bTxTime and !m_tune) m_btxok=false; //Time to stop transmitting } diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index fad9262c9..942ccd563 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -46,10 +46,11 @@ #define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80 #define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync #define NUM_FT8_SYMBOLS 79 +#define NUM_FT2_SYMBOLS 144 #define NUM_CW_SYMBOLS 250 #define TX_SAMPLE_RATE 48000 #define N_WIDGETS 33 -#define NRING 432000 +#define NRING 3456000 extern int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols extern int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID @@ -312,6 +313,7 @@ private slots: void not_GA_warning_message (); void checkMSK144ContestType(); void ft2Data(int k); + void ft2_tx(int ntx); int setTxMsg(int n); bool stdCall(QString const& w);