diff --git a/CMakeLists.txt b/CMakeLists.txt index 06f9796..e899714 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,6 +304,8 @@ set (wsjt_FSRCS lib/js8c_decode.f90 lib/js8e_module.f90 lib/js8e_decode.f90 + lib/js8i_module.f90 + lib/js8i_decode.f90 # remaining non-module sources lib/addit.f90 @@ -420,6 +422,7 @@ set (wsjt_FSRCS lib/js8/ldpcsim174js8b.f90 lib/js8/ldpcsim174js8c.f90 lib/js8/ldpcsim174js8e.f90 + lib/js8/ldpcsim174js8i.f90 lib/ldpcsim40.f90 lib/libration.f90 lib/lorentzian.f90 @@ -1006,6 +1009,9 @@ target_link_libraries (ldpcsim174js8c wsjt_fort wsjt_cxx) add_executable (ldpcsim174js8e lib/js8/ldpcsim174js8e.f90 wsjtx.rc) target_link_libraries (ldpcsim174js8e wsjt_fort wsjt_cxx) +add_executable (ldpcsim174js8i lib/js8/ldpcsim174js8i.f90 wsjtx.rc) +target_link_libraries (ldpcsim174js8i wsjt_fort wsjt_cxx) + add_executable (js8 ${js8_FSRCS} ${js8_CXXSRCS} wsjtx.rc) if (${OPENMP_FOUND} OR APPLE) if (APPLE) diff --git a/Modulator.cpp b/Modulator.cpp index 15d8726..2367099 100644 --- a/Modulator.cpp +++ b/Modulator.cpp @@ -84,6 +84,9 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol, else if(m_TRperiod == JS8E_TX_SECONDS){ delay_ms = JS8E_START_DELAY_MS; } + else if(m_TRperiod == JS8I_TX_SECONDS){ + delay_ms = JS8I_START_DELAY_MS; + } // noise generator parameters if (m_addNoise) { diff --git a/commons.h b/commons.h index 6917abf..50da8ab 100644 --- a/commons.h +++ b/commons.h @@ -24,6 +24,7 @@ #define JS8_ENABLE_JS8B 1 #define JS8_ENABLE_JS8C 1 #define JS8_ENABLE_JS8E 1 +#define JS8_ENABLE_JS8I 0 #define JS8A_SYMBOL_SAMPLES 1920 #define JS8A_TX_SECONDS 15 @@ -37,16 +38,13 @@ #define JS8C_TX_SECONDS 6 #define JS8C_START_DELAY_MS 100 -#define JS8E_IS_ULTRA 0 -#if JS8E_IS_ULTRA -#define JS8E_SYMBOL_SAMPLES 384 -#define JS8E_TX_SECONDS 4 -#define JS8E_START_DELAY_MS 100 -#else #define JS8E_SYMBOL_SAMPLES 4000 #define JS8E_TX_SECONDS 30 #define JS8E_START_DELAY_MS 500 -#endif + +#define JS8I_SYMBOL_SAMPLES 384 +#define JS8I_TX_SECONDS 4 +#define JS8I_START_DELAY_MS 100 #ifndef TEST_FOX_WAVE_GEN #define TEST_FOX_WAVE_GEN 0 @@ -104,10 +102,12 @@ extern struct dec_data { int kposB; // starting position of decode for submode B int kposC; // starting position of decode for submode C int kposE; // starting position of decode for submode E + int kposI; // starting position of decode for submode I int kszA; // number of frames for decode for submode A int kszB; // number of frames for decode for submode B int kszC; // number of frames for decode for submode C int kszE; // number of frames for decode for submode E + int kszI; // number of frames for decode for submode I int nzhsym; // half symbol stop index int nsubmode; int nsubmodes; diff --git a/decodedtext.cpp b/decodedtext.cpp index ecb539e..5a2e5a8 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -259,7 +259,12 @@ bool DecodedText::tryUnpackFastData(){ return false; } - if(submode_ != Varicode::JS8CallFast && submode_ != Varicode::JS8CallTurbo && submode_ != Varicode::JS8CallUltraSlow){ + if( + submode_ != Varicode::JS8CallFast && + submode_ != Varicode::JS8CallTurbo && + submode_ != Varicode::JS8CallSlow && + submode_ != Varicode::JS8CallUltra + ){ return false; } diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 7555ed3..6bebc50 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -7,6 +7,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) use js8b_decode use js8c_decode use js8e_decode + use js8i_decode include 'jt9com.f90' include 'timer_common.inc' @@ -27,6 +28,10 @@ subroutine multimode_decoder(ss,id2,params,nfsample) integer :: decoded end type counting_js8e_decoder + type, extends(js8i_decoder) :: counting_js8i_decoder + integer :: decoded + end type counting_js8i_decoder + real ss(184,NSMAX) logical baddata,newdat65,newdat9,single_decode,bVHF,bad0,newdat,trydecode integer*2 id0(NTMAX*12000) @@ -40,6 +45,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) type(counting_js8b_decoder) :: my_js8b type(counting_js8c_decoder) :: my_js8c type(counting_js8e_decoder) :: my_js8e + type(counting_js8i_decoder) :: my_js8i !cast C character arrays to Fortran character strings datetime=transfer(params%datetime, datetime) @@ -53,6 +59,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) my_js8b%decoded = 0 my_js8c%decoded = 0 my_js8e%decoded = 0 + my_js8i%decoded = 0 single_decode=iand(params%nexp_decode,32).ne.0 bVHF=iand(params%nexp_decode,64).ne.0 @@ -74,6 +81,29 @@ subroutine multimode_decoder(ss,id2,params,nfsample) write(*,1012) params%nsubmode, params%nsubmodes 1012 format('',2i4) + if(params%nmode.eq.8 .and. (params%nsubmode.eq.8 .or. iand(params%nsubmodes, 16).eq.16)) then +! We're in JS8 mode I + call timer('decjs8i ',0) + newdat=params%newdat + write(*,*) ' mode I decode started' + + ! copy the relevant frames for decoding + pos = max(0,params%kposI) + sz = max(0,params%kszI) + id0=0 + id0(1:sz+1)=id2(pos+1:pos+sz+1) + + call my_js8i%decode(js8i_decoded,id0,params%nQSOProgress,params%nfqso, & + params%nftx,newdat,params%nutc,params%nfa,params%nfb, & + params%nexp_decode,params%ndepth,logical(params%nagain), & + logical(params%lft8apon),logical(params%lapcqonly),params%napwid, & + mycall,mygrid,hiscall,hisgrid) + + write(*,*) ' mode I decode finished' + + call timer('decjs8i ',1) + endif + if(params%nmode.eq.8 .and. (params%nsubmode.eq.4 .or. iand(params%nsubmodes, 8).eq.8)) then ! We're in JS8 mode E call timer('decjs8e ',0) @@ -229,6 +259,7 @@ contains if(submode.eq.1) m=' B ' if(submode.eq.2) m=' C ' if(submode.eq.4) m=' E ' + if(submode.eq.8) m=' I ' i0=index(decoded0,';') @@ -377,4 +408,30 @@ contains return end subroutine js8e_decoded + subroutine js8i_decoded (this,sync,snr,dt,freq,decoded,nap,qual) + use js8i_decode + implicit none + + class(js8i_decoder), intent(inout) :: this + real, intent(in) :: sync + integer, intent(in) :: snr + real, intent(in) :: dt + real, intent(in) :: freq + character(len=37), intent(in) :: decoded + integer, intent(in) :: nap + real, intent(in) :: qual + integer :: submode + save + + submode=8 + call js8_decoded(sync, snr, dt, freq, decoded, nap, qual, submode) + + select type(this) + type is (counting_js8i_decoder) + this%decoded = this%decoded + 1 + end select + + return + end subroutine js8i_decoded + end subroutine multimode_decoder diff --git a/lib/js8/js8i_params.f90 b/lib/js8/js8i_params.f90 new file mode 100644 index 0000000..ee99f46 --- /dev/null +++ b/lib/js8/js8i_params.f90 @@ -0,0 +1,37 @@ +!parameter (NSPS=480) !Samples per symbol at 12000 S/s +!parameter (NTXDUR=5) !TX Duration in Seconds +!parameter (NDOWNSPS=16) !Downsampled samples per symbol +!parameter (AZ=6.0) !Near dupe sync spacing +!parameter (NDD=136) !Downconverted FFT Bins - 100 Bins +!parameter (JZ=62) !Sync Search Space over +/- 2.5s relative to 0.5s TX start time. 2.48 = 62/4/(12000/1920) ? + + + parameter (NSPS=384, NTXDUR=4, NDOWNSPS=12, NDD=125, JZ=250) ! 250 Hz 31.25 baud 60 wpm -18.0dB (1.0Eb/N0) 2.52s +! parameter (NSPS=384, NTXDUR=5, NDOWNSPS=12, NDD=125, JZ=116) ! 250 Hz 31.25 baud 48 wpm -18.0dB (1.0Eb/N0) 2.52s +! parameter (NSPS=480, NTXDUR=5, NDOWNSPS=12, NDD=125, JZ=116) ! 200 Hz 25 baud 48 wpm -19.0dB (1.0Eb/N0) 3.16s +! parameter (NSPS=480, NTXDUR=6, NDOWNSPS=20, NDD=150, JZ=116) ! 200 Hz 25 baud 40 wpm -19.0dB (1.0Eb/N0) 3.16s +! parameter (NSPS=500, NTXDUR=6, NDOWNSPS=20, NDD=144, JZ=116) ! 192 Hz 24 baud 40 wpm -19.4dB (1.0Eb/N0) 3.29s +! parameter (NSPS=600, NTXDUR=6, NDOWNSPS=24, NDD=120, JZ=172) ! 160 Hz 20 baud 40 wpm -20.0dB (1.0Eb/N0) 3.95s +! parameter (NSPS=768, NTXDUR=8, NDOWNSPS=24, NDD=125, JZ=116) ! 125 Hz 15.625 baud 32 wpm -21.0dB (1.0Eb/N0) 5.05s +! parameter (NSPS=800, NTXDUR=8, NDOWNSPS=24, NDD=100, JZ=116) ! 120 Hz 15 baud 32 wpm -21.2dB (1.0Eb/N0) 5.26s +! parameter (NSPS=960, NTXDUR=8, NDOWNSPS=24, NDD=100, JZ=116) ! 100 Hz 12.50 baud 32 wpm -22.0dB (1.0Eb/N0) 5.92s +! parameter (NSPS=1200, NTXDUR=10, NDOWNSPS=20, NDD=100, JZ=116) ! 80 Hz 10 baud 24 wpm -23.0dB (1.0Eb/N0) 7.90s +! parameter (NSPS=1920, NTXDUR=15, NDOWNSPS=32, NDD=100, JZ=116) ! 50 Hz 6.250 baud 16 wpm -25.0dB (1.0Eb/N0) 12.64s +! parameter (NSPS=3840, NTXDUR=30, NDOWNSPS=32, NDD=94, JZ=116) ! 24 Hz 3.125 baud 8 wpm -28.0dB (1.0Eb/N0) 25.28s +! parameter (NSPS=4000, NTXDUR=28, NDOWNSPS=20, NDD=90, JZ=32) ! 24 Hz 3 baud 8 wpm -28.2dB (1.0Eb/N0) 26.33s + +parameter (AZ=12000.0/(1.0*NSPS)*0.8d0) !Dedupe overlap in Hz +parameter (ASTART=0.1) !Start delay in seconds +parameter (ASYNCMIN=1.5) !Minimum Sync + +parameter (KK=87) !Information bits (75 + CRC12) +parameter (ND=58) !Data symbols +parameter (NS=21) !Sync symbols (3 @ Costas 7x7) +parameter (NN=NS+ND) !Total channel symbols (79) +parameter (NZ=NSPS*NN) !Samples in full 15 s waveform (151,680) +parameter (NMAX=NTXDUR*12000) !Samples in iwave (180,000) +parameter (NFFT1=2*NSPS, NH1=NFFT1/2) !Length of FFTs for symbol spectra +parameter (NSTEP=NSPS/4) !Rough time-sync step size +parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps) +parameter (NDOWN=NSPS/NDOWNSPS) !Downsample factor to 32 samples per symbol +parameter (NQSYMBOL=NDOWNSPS/4) !Downsample factor of a quarter symbol diff --git a/lib/js8/ldpcsim174js8i.f90 b/lib/js8/ldpcsim174js8i.f90 new file mode 100644 index 0000000..aa77e47 --- /dev/null +++ b/lib/js8/ldpcsim174js8i.f90 @@ -0,0 +1,238 @@ +program ldpcsim174js8 +! End to end test of the (174,75)/crc12 encoder and decoder. +use crc +use packjt + +include 'js8_params.f90' +include 'js8i_params.f90' + +character*22 msg,msgsent,msgreceived +character*8 arg +character*6 grid +integer*1, allocatable :: codeword(:), decoded(:), message(:) +integer*1, target:: i1Msg8BitBytes(11) +integer*1 msgbits(87) +integer*1 apmask(174), cw(174) +integer*2 checksum +integer*4 i4Msg6BitWords(13) +integer colorder(174) +integer nerrtot(174),nerrdec(174),nmpcbad(87) +logical checksumok,fsk,bpsk +real*8, allocatable :: rxdata(:) +real, allocatable :: llr(:) + +data colorder/ & + 0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,& + 17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,& + 36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,& + 56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,& + 73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,& + 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,& + 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,& + 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,& + 160,161,162,163,164,165,166,167,168,169,170,171,172,173/ + +nerrtot=0 +nerrdec=0 +nmpcbad=0 ! Used to collect the number of errors in the message+crc part of the codeword + +nargs=iargc() +if(nargs.ne.4) then + print*,'Usage: ldpcsim niter ndepth #trials s ' + print*,'eg: ldpcsim 10 2 1000 0.84' + print*,'belief propagation iterations: niter, ordered-statistics depth: ndepth' + print*,'If s is negative, then value is ignored and sigma is calculated from SNR.' + return +endif +call getarg(1,arg) +read(arg,*) max_iterations +call getarg(2,arg) +read(arg,*) ndepth +call getarg(3,arg) +read(arg,*) ntrials +call getarg(4,arg) +read(arg,*) s + +fsk=.false. +bpsk=.true. + +! don't count crc bits as data bits +N=174 +K=87 +! scale Eb/No for a (174,87) code +rate=real(K)/real(N) + +write(*,*) "rate: ",rate +write(*,*) "niter= ",max_iterations," s= ",s + +allocate ( codeword(N), decoded(K), message(K) ) +allocate ( rxdata(N), llr(N) ) + + msg="0123456789012" +! msg="G4WJS K9AN EN50" + call packmsg(msg,i4Msg6BitWords,itype,.false.) !Pack into 12 6-bit bytes + call unpackmsg(i4Msg6BitWords,msgsent,.false.,grid) !Unpack to get msgsent + write(*,*) "message sent ",msgsent + + i4=0 + ik=0 + im=0 + do i=1,12 + nna=i4Msg6BitWords(i) + do j=1, 6 + ik=ik+1 + i4=i4+i4+iand(1,ishft(nna,j-6)) + i4=iand(i4,255) + if(ik.eq.8) then + im=im+1 +! if(i4.gt.127) i4=i4-256 + i1Msg8BitBytes(im)=i4 + ik=0 + endif + enddo + enddo + + i1Msg8BitBytes(10:11)=0 + checksum = crc12 (c_loc (i1Msg8BitBytes), 11) + checksum = xor(checksum, 42) ! TODO: jsherer - could change the crc here +! For reference, the next 3 lines show how to check the CRC + i1Msg8BitBytes(10)=checksum/256 + i1Msg8BitBytes(11)=iand(checksum,transfer(255,0_2)) + checksumok = crc12_check(c_loc (i1Msg8BitBytes), 11) + if( checksumok ) write(*,*) 'Good checksum' + +! K=87, For now: +! msgbits(1:72) JT message bits +! msgbits(73:75) 3 free message bits (set to 0) +! msgbits(76:87) CRC12 + mbit=0 + do i=1, 9 + i1=i1Msg8BitBytes(i) + do ibit=1,8 + mbit=mbit+1 + msgbits(mbit)=iand(1,ishft(i1,ibit-8)) + enddo + enddo + msgbits(73:75)=0 ! the three extra message bits go here + i1=i1Msg8BitBytes(10) ! First 4 bits of crc12 are LSB of this byte + do ibit=1,4 + msgbits(75+ibit)=iand(1,ishft(i1,ibit-4)) + enddo + i1=i1Msg8BitBytes(11) ! Now shift in last 8 bits of the CRC + do ibit=1,8 + msgbits(79+ibit)=iand(1,ishft(i1,ibit-8)) + enddo + + write(*,*) 'message' + write(*,'(11(8i1,1x))') msgbits + + call encode174(msgbits,codeword) + call init_random_seed() +! call sgran() + + write(*,*) 'codeword' + write(*,'(22(8i1,1x))') codeword + +write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma" +do idb = 20,-10,-1 +!do idb = -3,-3,-1 + db=idb/2.0-1.0 + sigma=1/sqrt( 2*(10**(db/10.0)) ) + ngood=0 + nue=0 + nbadcrc=0 + nberr=0 + do itrial=1, ntrials +! Create a realization of a noisy received word + do i=1,N + if( bpsk ) then + rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran() + elseif( fsk ) then + if( codeword(i) .eq. 1 ) then + r1=(1.0 + sigma*gran())**2 + (sigma*gran())**2 + r2=(sigma*gran())**2 + (sigma*gran())**2 + elseif( codeword(i) .eq. 0 ) then + r2=(1.0 + sigma*gran())**2 + (sigma*gran())**2 + r1=(sigma*gran())**2 + (sigma*gran())**2 + endif +! rxdata(i)=0.35*(sqrt(r1)-sqrt(r2)) +! rxdata(i)=0.35*(exp(r1)-exp(r2)) + rxdata(i)=0.12*(log(r1)-log(r2)) + endif + enddo + nerr=0 + do i=1,N + if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1 + enddo + if(nerr.ge.1) nerrtot(nerr)=nerrtot(nerr)+1 + nberr=nberr+nerr + +! Correct signal normalization is important for this decoder. + rxav=sum(rxdata)/N + rx2av=sum(rxdata*rxdata)/N + rxsig=sqrt(rx2av-rxav*rxav) + rxdata=rxdata/rxsig +! To match the metric to the channel, s should be set to the noise standard deviation. +! For now, set s to the value that optimizes decode probability near threshold. +! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of +! magnitude in UER + if( s .lt. 0 ) then + ss=sigma + else + ss=s + endif + + llr=2.0*rxdata/(ss*ss) + nap=0 ! number of AP bits + llr(colorder(174-87+1:174-87+nap)+1)=5*(2.0*msgbits(1:nap)-1.0) + apmask=0 + apmask(colorder(174-87+1:174-87+nap)+1)=1 + +! max_iterations is max number of belief propagation iterations + call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors,niterations) + if( ndepth .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, apmask, ndepth, decoded, cw, nharderrors, dmin) +! If the decoder finds a valid codeword, nharderrors will be .ge. 0. + if( nharderrors .ge. 0 ) then + call extractmessage174(decoded,msgreceived,ncrcflag) + if( ncrcflag .ne. 1 ) then + nbadcrc=nbadcrc+1 + endif + + nueflag=0 + nerrmpc=0 + do i=1,K ! find number of errors in message+crc part of codeword + if( msgbits(i) .ne. decoded(i) ) then + nueflag=1 + nerrmpc=nerrmpc+1 + endif + enddo + if(nerrmpc.ge.1) nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1 + if( ncrcflag .eq. 1 ) then + if( nueflag .eq. 0 ) then + ngood=ngood+1 + if(nerr.ge.1) nerrdec(nerr)=nerrdec(nerr)+1 + else if( nueflag .eq. 1 ) then + nue=nue+1; + endif + endif + endif + enddo + baud=12000.0/NSPS + snr2500=db+10.0*log10((baud/2500.0)) + pberr=real(nberr)/(real(ntrials*N)) + write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr + +enddo + +open(unit=23,file='nerrhisto.dat',status='unknown') +do i=1,174 + write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10) +enddo +close(23) +open(unit=25,file='nmpcbad.dat',status='unknown') +do i=1,87 + write(25,'(i4,2x,i10)') i,nmpcbad(i) +enddo +close(25) + +end program ldpcsim174js8 diff --git a/lib/js8i_decode.f90 b/lib/js8i_decode.f90 new file mode 100644 index 0000000..e176929 --- /dev/null +++ b/lib/js8i_decode.f90 @@ -0,0 +1,152 @@ +module js8i_decode + + type :: js8i_decoder + procedure(js8i_decode_callback), pointer :: callback + contains + procedure :: decode + end type js8i_decoder + + abstract interface + subroutine js8i_decode_callback (this,sync,snr,dt,freq,decoded,nap,qual) + import js8i_decoder + implicit none + class(js8i_decoder), intent(inout) :: this + real, intent(in) :: sync + integer, intent(in) :: snr + real, intent(in) :: dt + real, intent(in) :: freq + character(len=37), intent(in) :: decoded + integer, intent(in) :: nap + real, intent(in) :: qual + end subroutine js8i_decode_callback + end interface + +contains + + subroutine decode(this,callback,iwave,nQSOProgress,nfqso,nftx,newdat, & + nutc,nfa,nfb,nexp_decode,ndepth,nagain,lft8apon,lapcqonly,napwid, & + mycall12,mygrid6,hiscall12,hisgrid6) +! use wavhdr + use timer_module, only: timer +! type(hdr) h + use js8i_module + + class(js8i_decoder), intent(inout) :: this + procedure(js8i_decode_callback) :: callback + real s(NH1,NHSYM) + real sbase(NH1) + real candidate(3,200) + real dd(NMAX) + logical, intent(in) :: lft8apon,lapcqonly,nagain + logical newdat,lsubtract,ldupe,bcontest + character*12 mycall12, hiscall12 + character*6 mygrid6,hisgrid6 + integer*2 iwave(NMAX) + integer apsym(KK) + character datetime*13,message*22,msg37*37 + character*22 allmessages(100) + integer allsnrs(100) + save s,dd + + bcontest=iand(nexp_decode,128).ne.0 + this%callback => callback + write(datetime,1001) nutc !### TEMPORARY ### +1001 format("000000_",i6.6) + + call ft8apset(mycall12,mygrid6,hiscall12,hisgrid6,bcontest,apsym,iaptype) + + dd=iwave + ndecodes=0 + allmessages=' ' + allsnrs=0 + ifa=nfa + ifb=nfb + if(nagain) then + ifa=nfqso-10 + ifb=nfqso+10 + endif + +! For now: +! ndepth=1: no subtraction, 1 pass, belief propagation only +! ndepth=2: subtraction, 3 passes, belief propagation only +! ndepth=3: subtraction, 3 passes, bp+osd + if(ndepth.eq.1) npass=1 + if(ndepth.ge.2) npass=3 + do ipass=1,npass + newdat=.true. ! Is this a problem? I hijacked newdat. + syncmin=ASYNCMIN + if(ipass.eq.1) then + lsubtract=.true. + if(ndepth.eq.1) lsubtract=.false. + elseif(ipass.eq.2) then + n2=ndecodes + if(ndecodes.eq.0) cycle + lsubtract=.true. + elseif(ipass.eq.3) then + if((ndecodes-n2).eq.0) cycle + lsubtract=.false. + endif + + call timer('syncjs8 ',0) + call syncjs8(dd,ifa,ifb,syncmin,nfqso,s,candidate,ncand,sbase) + call timer('syncjs8 ',1) + + if(NWRITELOG.eq.1) then + write(*,*) '', ncand, "candidates" + flush(6) + endif + + do icand=1,ncand + sync=candidate(3,icand) + f1=candidate(1,icand) + xdt=candidate(2,icand) + xbase=10.0**(0.1*(sbase(nint(f1/(12000.0/NFFT1)))-40.0)) ! 3.125Hz + nsnr0=min(99,nint(10.0*log10(sync) - 25.5)) !### empirical ### + + if(NWRITELOG.eq.1) then + write(*,*) ' candidate', icand, 'f1', f1, 'sync', sync, 'xdt', xdt, 'xbase', xbase + flush(6) + endif + + call timer('js8dec ',0) + call js8dec(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lft8apon, & + lapcqonly,napwid,lsubtract,nagain,iaptype,mycall12,mygrid6, & + hiscall12,bcontest,sync,f1,xdt,xbase,apsym,nharderrors,dmin, & + nbadcrc,iappass,iera,msg37,xsnr) + message=msg37(1:22) !### + nsnr=nint(xsnr) + xdt=xdt-ASTART + hd=nharderrors+dmin + + if(NWRITELOG.eq.1) then + write(*,*) ' candidate', icand, 'hard', hd, 'nbadcrc', nbadcrc + flush(6) + endif + + call timer('js8dec ',1) + if(nbadcrc.eq.0) then + ldupe=.false. + do id=1,ndecodes + if(message.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true. + enddo + if(.not.ldupe) then + ndecodes=ndecodes+1 + allmessages(ndecodes)=message + allsnrs(ndecodes)=nsnr + endif + if(.not.ldupe .and. associated(this%callback)) then + qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0] + call this%callback(sync,nsnr,xdt,f1,msg37,iaptype,qual) + endif + endif + + if(NWRITELOG.eq.1) then + write(*,*) ' ---' + flush(6) + endif + enddo + enddo + return + end subroutine decode + +end module js8i_decode diff --git a/lib/js8i_module.f90 b/lib/js8i_module.f90 new file mode 100644 index 0000000..972e51b --- /dev/null +++ b/lib/js8i_module.f90 @@ -0,0 +1,13 @@ +module js8i_module + include 'js8/js8_params.f90' + include 'js8/js8i_params.f90' + +contains + include 'js8/baselinejs8.f90' + include 'js8/syncjs8.f90' + include 'js8/js8_downsample.f90' + include 'js8/syncjs8d.f90' + include 'js8/genjs8refsig.f90' + include 'js8/subtractjs8.f90' + include 'js8/js8dec.f90' +end module js8i_module diff --git a/lib/jt9com.f90 b/lib/jt9com.f90 index 2c5b01a..bb30d57 100644 --- a/lib/jt9com.f90 +++ b/lib/jt9com.f90 @@ -23,10 +23,12 @@ integer(c_int) :: kposB integer(c_int) :: kposC integer(c_int) :: kposE + integer(c_int) :: kposI integer(c_int) :: kszA integer(c_int) :: kszB integer(c_int) :: kszC integer(c_int) :: kszE + integer(c_int) :: kszI integer(c_int) :: nzhsym integer(c_int) :: nsubmode integer(c_int) :: nsubmodes diff --git a/mainwindow.cpp b/mainwindow.cpp index ce2f9bd..bac15c6 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -961,7 +961,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionModeJS8Normal->setActionGroup(modeActionGroup); ui->actionModeJS8Fast->setActionGroup(modeActionGroup); ui->actionModeJS8Turbo->setActionGroup(modeActionGroup); - ui->actionModeJS8UltraSlow->setActionGroup(modeActionGroup); + ui->actionModeJS8Slow->setActionGroup(modeActionGroup); + ui->actionModeJS8Ultra->setActionGroup(modeActionGroup); auto mbmp = new MousePressEater(); connect(mbmp, &MousePressEater::mousePressed, this, [this](QObject *, QMouseEvent * e, bool *pProcessed){ @@ -979,13 +980,10 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionModeJS8Turbo->setVisible(false); } if(!JS8_ENABLE_JS8E){ - ui->actionModeJS8UltraSlow->setVisible(false); + ui->actionModeJS8Slow->setVisible(false); } - if(JS8_ENABLE_JS8E && !JS8E_IS_ULTRA){ - // reorder so slow is at the top - ui->menuModeJS8->removeAction(ui->actionModeJS8UltraSlow); - ui->menuModeJS8->insertAction(ui->actionModeJS8Normal, ui->actionModeJS8UltraSlow); - ui->actionModeJS8UltraSlow->setText("JS8 (&Slow, 30s, 24Hz, ~8WPM)"); + if(!JS8_ENABLE_JS8I){ + ui->actionModeJS8Ultra->setVisible(false); } // prep @@ -2514,10 +2512,11 @@ void MainWindow::setDecodedTextFont (QFont const& font) int MainWindow::computePeriodForSubmode(int submode){ switch(submode){ - case Varicode::JS8CallNormal: return JS8A_TX_SECONDS; - case Varicode::JS8CallFast: return JS8B_TX_SECONDS; - case Varicode::JS8CallTurbo: return JS8C_TX_SECONDS; - case Varicode::JS8CallUltraSlow: return JS8E_TX_SECONDS; + case Varicode::JS8CallNormal: return JS8A_TX_SECONDS; + case Varicode::JS8CallFast: return JS8B_TX_SECONDS; + case Varicode::JS8CallTurbo: return JS8C_TX_SECONDS; + case Varicode::JS8CallSlow: return JS8E_TX_SECONDS; + case Varicode::JS8CallUltra: return JS8I_TX_SECONDS; } return 0; @@ -2542,21 +2541,13 @@ int MainWindow::computeStop(int submode, int period){ stop = int(period/0.288); #else int symbolSamples = 0; - float threshold = 1.0; + float threshold = 0.0; switch(submode){ - case Varicode::JS8CallNormal: symbolSamples = JS8A_SYMBOL_SAMPLES; /* threshold = 1.00 */ ; break; - case Varicode::JS8CallFast: symbolSamples = JS8B_SYMBOL_SAMPLES; /* threshold = 1.08 */ ; break; - case Varicode::JS8CallTurbo: symbolSamples = JS8C_SYMBOL_SAMPLES; /* threshold = 0.50 */ ; break; - case Varicode::JS8CallUltraSlow: - { - symbolSamples = JS8E_SYMBOL_SAMPLES; -#if JS8E_IS_ULTRA - threshold = 0.0; -#else - threshold = 1.25; -#endif - break; - } + case Varicode::JS8CallNormal: symbolSamples = JS8A_SYMBOL_SAMPLES; threshold = 1.00; break; + case Varicode::JS8CallFast: symbolSamples = JS8B_SYMBOL_SAMPLES; threshold = 1.00; break; + case Varicode::JS8CallTurbo: symbolSamples = JS8C_SYMBOL_SAMPLES; threshold = 1.00; break; + case Varicode::JS8CallSlow: symbolSamples = JS8E_SYMBOL_SAMPLES; threshold = 1.25; break; + case Varicode::JS8CallUltra: symbolSamples = JS8I_SYMBOL_SAMPLES; threshold = 0.50; break; } stop = qFloor(float(symbolSamples*JS8_NUM_SYMBOLS + threshold*RX_SAMPLE_RATE)/(float)m_nsps*2.0); #endif @@ -2591,7 +2582,8 @@ int MainWindow::computeFramesNeededForDecode(int submode){ case Varicode::JS8CallNormal: symbolSamples = JS8A_SYMBOL_SAMPLES; threshold = JS8A_START_DELAY_MS/1000.0 + 0.5; break; case Varicode::JS8CallFast: symbolSamples = JS8B_SYMBOL_SAMPLES; threshold = JS8B_START_DELAY_MS/1000.0 + 0.5; break; case Varicode::JS8CallTurbo: symbolSamples = JS8C_SYMBOL_SAMPLES; threshold = JS8C_START_DELAY_MS/1000.0 + 0.5; break; - case Varicode::JS8CallUltraSlow: symbolSamples = JS8E_SYMBOL_SAMPLES; threshold = JS8E_START_DELAY_MS/1000.0 + 0.5; break; + case Varicode::JS8CallSlow: symbolSamples = JS8E_SYMBOL_SAMPLES; threshold = JS8E_START_DELAY_MS/1000.0 + 0.5; break; + case Varicode::JS8CallUltra: symbolSamples = JS8I_SYMBOL_SAMPLES; threshold = JS8I_START_DELAY_MS/1000.0 + 0.5; break; } return int(qFloor(float(symbolSamples*JS8_NUM_SYMBOLS + threshold*RX_SAMPLE_RATE))); } @@ -2774,7 +2766,8 @@ void MainWindow::on_menuModeJS8_aboutToShow(){ ui->actionModeJS8Normal->setEnabled(canChangeMode); ui->actionModeJS8Fast->setEnabled(canChangeMode); ui->actionModeJS8Turbo->setEnabled(canChangeMode); - ui->actionModeJS8UltraSlow->setEnabled(canChangeMode); + ui->actionModeJS8Slow->setEnabled(canChangeMode); + ui->actionModeJS8Ultra->setEnabled(canChangeMode); } void MainWindow::on_menuControl_aboutToShow(){ @@ -3272,7 +3265,8 @@ void MainWindow::setSubmode(int submode){ ui->actionModeJS8Normal->setChecked(submode == Varicode::JS8CallNormal); ui->actionModeJS8Fast->setChecked(submode == Varicode::JS8CallFast); ui->actionModeJS8Turbo->setChecked(submode == Varicode::JS8CallTurbo); - ui->actionModeJS8UltraSlow->setChecked(submode == Varicode::JS8CallUltraSlow); + ui->actionModeJS8Slow->setChecked(submode == Varicode::JS8CallSlow); + ui->actionModeJS8Ultra->setChecked(submode == Varicode::JS8CallUltra); on_actionJS8_triggered(); } @@ -3288,8 +3282,11 @@ int MainWindow::submodeNameToSubmode(QString speedName){ if(speed == submodeName(Varicode::JS8CallTurbo)){ return Varicode::JS8CallTurbo; } - if(speed == submodeName(Varicode::JS8CallUltraSlow)){ - return Varicode::JS8CallUltraSlow; + if(speed == submodeName(Varicode::JS8CallSlow)){ + return Varicode::JS8CallSlow; + } + if(speed == submodeName(Varicode::JS8CallUltra)){ + return Varicode::JS8CallUltra; } // default to the current submode return m_nSubMode; @@ -3306,12 +3303,11 @@ QString MainWindow::submodeName(int submode){ else if(submode == Varicode::JS8CallTurbo){ return "TURBO"; } - else if(submode == Varicode::JS8CallUltraSlow){ -#if JS8E_IS_ULTRA - return "ULTRA"; -#else + else if(submode == Varicode::JS8CallSlow){ return "SLOW"; -#endif + } + else if(submode == Varicode::JS8CallUltra){ + return "ULTRA"; } return "?"; @@ -4161,8 +4157,8 @@ bool MainWindow::decodeEnqueueReady(qint32 k, qint32 k0){ qint32 startE = -1; qint32 szE = -1; qint32 cycleE = -1; - if(JS8_DEBUG_DECODE) qDebug() << "? ULTRASLOW" << currentDecodeStartE << nextDecodeStartE; - bool couldDecodeE = isDecodeReady(Varicode::JS8CallUltraSlow, k, k0, ¤tDecodeStartE, &nextDecodeStartE, &startE, &szE, &cycleE); + if(JS8_DEBUG_DECODE) qDebug() << "? SLOW" << currentDecodeStartE << nextDecodeStartE; + bool couldDecodeE = isDecodeReady(Varicode::JS8CallSlow, k, k0, ¤tDecodeStartE, &nextDecodeStartE, &startE, &szE, &cycleE); if(m_diskData){ startE = 0; szE = NTMAX*RX_SAMPLE_RATE-1; @@ -4170,6 +4166,21 @@ bool MainWindow::decodeEnqueueReady(qint32 k, qint32 k0){ } #endif +#if JS8_ENABLE_JS8I + static qint32 currentDecodeStartI = -1; + static qint32 nextDecodeStartI = -1; + qint32 startI = -1; + qint32 szI = -1; + qint32 cycleI = -1; + if(JS8_DEBUG_DECODE) qDebug() << "? ULTRA" << currentDecodeStartI << nextDecodeStartI; + bool couldDecodeI = isDecodeReady(Varicode::JS8CallUltra, k, k0, ¤tDecodeStartI, &nextDecodeStartI, &startI, &szI, &cycleI); + if(m_diskData){ + startI = 0; + szI = NTMAX*RX_SAMPLE_RATE-1; + couldDecodeI = true; + } +#endif + int decodes = 0; if(couldDecodeA){ @@ -4205,7 +4216,7 @@ bool MainWindow::decodeEnqueueReady(qint32 k, qint32 k0){ #if JS8_ENABLE_JS8E if(couldDecodeE){ DecodeParams d; - d.submode = Varicode::JS8CallUltraSlow; + d.submode = Varicode::JS8CallSlow; d.cycle = cycleE; d.start = startE; d.sz = szE; @@ -4214,6 +4225,18 @@ bool MainWindow::decodeEnqueueReady(qint32 k, qint32 k0){ } #endif +#if JS8_ENABLE_JS8E + if(couldDecodeI){ + DecodeParams d; + d.submode = Varicode::JS8CallUltra; + d.cycle = cycleI; + d.start = startI; + d.sz = szI; + m_decoderQueue.append(d); + decodes++; + } +#endif + return decodes > 0; } @@ -4291,11 +4314,18 @@ bool MainWindow::decodeProcessQueue(qint32 *pSubmode){ dec_data.params.nsubmodes |= (params.submode << 1); break; #if JS8_ENABLE_JS8E - case Varicode::JS8CallUltraSlow: + case Varicode::JS8CallSlow: dec_data.params.kposE = params.start; dec_data.params.kszE = params.sz; dec_data.params.nsubmodes |= (params.submode << 1); break; +#endif +#if JS8_ENABLE_JS8I + case Varicode::JS8CallUltra: + dec_data.params.kposI = params.start; + dec_data.params.kszI = params.sz; + dec_data.params.nsubmodes |= (params.submode << 1); + break; #endif } #if JS8_SINGLE_DECODE @@ -5249,8 +5279,10 @@ void MainWindow::guiUpdate() txDuration=JS8B_START_DELAY_MS/1000.0 + JS8_NUM_SYMBOLS * (double)JS8B_SYMBOL_SAMPLES/(double)RX_SAMPLE_RATE; } else if(m_nSubMode == Varicode::JS8CallTurbo){ txDuration=JS8C_START_DELAY_MS/1000.0 + JS8_NUM_SYMBOLS * (double)JS8C_SYMBOL_SAMPLES/(double)RX_SAMPLE_RATE; - } else if(m_nSubMode == Varicode::JS8CallUltraSlow){ + } else if(m_nSubMode == Varicode::JS8CallSlow){ txDuration=JS8E_START_DELAY_MS/1000.0 + JS8_NUM_SYMBOLS * (double)JS8E_SYMBOL_SAMPLES/(double)RX_SAMPLE_RATE; + } else if(m_nSubMode == Varicode::JS8CallUltra){ + txDuration=JS8I_START_DELAY_MS/1000.0 + JS8_NUM_SYMBOLS * (double)JS8I_SYMBOL_SAMPLES/(double)RX_SAMPLE_RATE; } } @@ -5336,9 +5368,12 @@ void MainWindow::guiUpdate() else if(m_nSubMode == Varicode::JS8CallTurbo){ ratio = (((double)m_TRperiod - (JS8_NUM_SYMBOLS*(double)JS8C_SYMBOL_SAMPLES/(double)RX_SAMPLE_RATE))/(double)m_TRperiod); } - else if(m_nSubMode == Varicode::JS8CallUltraSlow){ + else if(m_nSubMode == Varicode::JS8CallSlow){ ratio = (((double)m_TRperiod - (JS8_NUM_SYMBOLS*(double)JS8E_SYMBOL_SAMPLES/(double)RX_SAMPLE_RATE))/(double)m_TRperiod); } + else if(m_nSubMode == Varicode::JS8CallUltra){ + ratio = (((double)m_TRperiod - (JS8_NUM_SYMBOLS*(double)JS8I_SYMBOL_SAMPLES/(double)RX_SAMPLE_RATE))/(double)m_TRperiod); + } if(fTR > 1.0-ratio && fTR < 1.0){ if(!m_deadAirTone){ @@ -5362,6 +5397,10 @@ void MainWindow::guiUpdate() // for the turbo mode, only allow 1/2 late threshold lateThreshold *= 0.5; } + else if(m_nSubMode == Varicode::JS8CallUltra){ + // for the ultra mode, only allow 1/2 late threshold + lateThreshold *= 0.5; + } if(g_iptt==0 and ((m_bTxTime and fTR0) or m_tune)) { //### Allow late starts icw[0]=m_ncw; @@ -5424,7 +5463,7 @@ void MainWindow::guiUpdate() qDebug() << "gen ft8"; genft8_(message, MyGrid, &bcontest, &m_i3bit, msgsent, const_cast (ft8msgbits), const_cast (itone), 22, 6, 22); - } else if (m_nSubMode == Varicode::JS8CallFast || m_nSubMode == Varicode::JS8CallTurbo || m_nSubMode == Varicode::JS8CallUltraSlow){ + } else if (m_nSubMode == Varicode::JS8CallFast || m_nSubMode == Varicode::JS8CallTurbo || m_nSubMode == Varicode::JS8CallSlow || m_nSubMode == Varicode::JS8CallUltra){ qDebug() << "gen js8"; genjs8_(message, MyGrid, &bcontest, &m_i3bit, msgsent, const_cast (ft8msgbits), const_cast (itone), 22, 6, 22); @@ -7399,7 +7438,11 @@ void MainWindow::on_actionModeJS8Turbo_triggered(){ on_actionJS8_triggered(); } -void MainWindow::on_actionModeJS8UltraSlow_triggered(){ +void MainWindow::on_actionModeJS8Slow_triggered(){ + on_actionJS8_triggered(); +} + +void MainWindow::on_actionModeJS8Ultra_triggered(){ on_actionJS8_triggered(); } @@ -7418,7 +7461,7 @@ void MainWindow::prepareHeartbeatMode(bool enabled){ ui->hbMacroButton->setChecked(false); } ui->actionHeartbeat->setEnabled(enabled); - ui->actionModeJS8HB->setEnabled(m_nSubMode == Varicode::JS8CallNormal || (!JS8E_IS_ULTRA && m_nSubMode == Varicode::JS8CallUltraSlow)); + ui->actionModeJS8HB->setEnabled(m_nSubMode == Varicode::JS8CallNormal || m_nSubMode == Varicode::JS8CallSlow); ui->actionHeartbeatAcknowledgements->setEnabled(ui->actionModeAutoreply->isChecked() && enabled); #if 0 @@ -7461,12 +7504,15 @@ void MainWindow::on_actionJS8_triggered() else if(ui->actionModeJS8Turbo->isChecked()){ m_nSubMode=Varicode::JS8CallTurbo; } - else if(ui->actionModeJS8UltraSlow->isChecked()){ - m_nSubMode=Varicode::JS8CallUltraSlow; + else if(ui->actionModeJS8Slow->isChecked()){ + m_nSubMode=Varicode::JS8CallSlow; + } + else if(ui->actionModeJS8Ultra->isChecked()){ + m_nSubMode=Varicode::JS8CallUltra; } // Only enable heartbeat for normal mode - ui->actionModeJS8HB->setEnabled(m_nSubMode == Varicode::JS8CallNormal || (!JS8E_IS_ULTRA && m_nSubMode == Varicode::JS8CallUltraSlow)); + ui->actionModeJS8HB->setEnabled(m_nSubMode == Varicode::JS8CallNormal || m_nSubMode == Varicode::JS8CallSlow); prepareHeartbeatMode(ui->actionModeJS8HB->isEnabled() && ui->actionModeJS8HB->isChecked()); //if(m_nSubMode != Varicode::JS8CallNormal){ @@ -9559,10 +9605,14 @@ void MainWindow::transmit (double snr) symbolSamples=(double)JS8C_SYMBOL_SAMPLES; toneSpacing=(double)RX_SAMPLE_RATE/(double)JS8C_SYMBOL_SAMPLES; } - else if(m_nSubMode == Varicode::JS8CallUltraSlow){ + else if(m_nSubMode == Varicode::JS8CallSlow){ symbolSamples=(double)JS8E_SYMBOL_SAMPLES; toneSpacing=(double)RX_SAMPLE_RATE/(double)JS8E_SYMBOL_SAMPLES; } + else if(m_nSubMode == Varicode::JS8CallUltra){ + symbolSamples=(double)JS8I_SYMBOL_SAMPLES; + toneSpacing=(double)RX_SAMPLE_RATE/(double)JS8I_SYMBOL_SAMPLES; + } if(m_config.x2ToneSpacing()) toneSpacing*=2.0; if(m_config.x4ToneSpacing()) toneSpacing*=4.0; if(m_config.bFox() and !m_tune) toneSpacing=-1; @@ -9816,9 +9866,7 @@ int MainWindow::rxThreshold(int submode){ int threshold = 10; if(submode == Varicode::JS8CallFast){ threshold = 16; } if(submode == Varicode::JS8CallTurbo){ threshold = 32; } -#if JS8E_IS_ULTRA - if(submode == Varicode::JS8CallUltraSlow){ threshold = 50; } -#endif + if(submode == Varicode::JS8CallUltra){ threshold = 50; } return threshold; } @@ -9831,10 +9879,8 @@ int MainWindow::rxSnrThreshold(int submode){ return -22; case Varicode::JS8CallTurbo: return -20; -#if JS8E_IS_ULTRA - case Varicode::JS8CallUltraSlow: + case Varicode::JS8CallUltra: return -18; -#endif } return -28; @@ -12632,8 +12678,11 @@ void MainWindow::networkMessage(Message const &message) if(speed == Varicode::JS8CallTurbo){ ui->actionModeJS8Turbo->setChecked(true); } - if(speed == Varicode::JS8CallUltraSlow){ - ui->actionModeJS8UltraSlow->setChecked(true); + if(speed == Varicode::JS8CallSlow){ + ui->actionModeJS8Slow->setChecked(true); + } + if(speed == Varicode::JS8CallUltra){ + ui->actionModeJS8Ultra->setChecked(true); } } sendNetworkMessage("MODE.SPEED", "", { diff --git a/mainwindow.h b/mainwindow.h index b3d2ae3..11f7857 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -275,7 +275,8 @@ private slots: void on_actionModeJS8Normal_triggered(); void on_actionModeJS8Fast_triggered(); void on_actionModeJS8Turbo_triggered(); - void on_actionModeJS8UltraSlow_triggered(); + void on_actionModeJS8Slow_triggered(); + void on_actionModeJS8Ultra_triggered(); void on_actionHeartbeatAcknowledgements_toggled(bool checked); void on_actionModeMultiDecoder_toggled(bool checked); void on_actionModeAutoreply_toggled(bool checked); diff --git a/mainwindow.ui b/mainwindow.ui index abc185e..31208ab 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -4778,10 +4778,11 @@ list. The list can be maintained in Settings (F2). + - + @@ -5712,7 +5713,7 @@ list. The list can be maintained in Settings (F2). JS8 (&Turbo, 6s, 160Hz, ~40 WPM) - + true @@ -5763,6 +5764,14 @@ list. The list can be maintained in Settings (F2). Enable Autoreply (&AUTO) + + + true + + + JS8 (&Slow, 30s, 24Hz, ~8 WPM) + + diff --git a/plotter.cpp b/plotter.cpp index 46e6dd7..c65f7a0 100644 --- a/plotter.cpp +++ b/plotter.cpp @@ -422,9 +422,12 @@ void CPlotter::DrawOverlay() //DrawOverlay() else if(m_nSubMode == Varicode::JS8CallTurbo){ bw = 8.0*(double)RX_SAMPLE_RATE/(double)JS8C_SYMBOL_SAMPLES; } - else if(m_nSubMode == Varicode::JS8CallUltraSlow){ + else if(m_nSubMode == Varicode::JS8CallSlow){ bw = 8.0*(double)RX_SAMPLE_RATE/(double)JS8E_SYMBOL_SAMPLES; } + else if(m_nSubMode == Varicode::JS8CallUltra){ + bw = 8.0*(double)RX_SAMPLE_RATE/(double)JS8I_SYMBOL_SAMPLES; + } painter0.setPen(penGreen); diff --git a/varicode.h b/varicode.h index 99b6d1e..fdb9f73 100644 --- a/varicode.h +++ b/varicode.h @@ -28,7 +28,8 @@ public: JS8CallNormal = 0, JS8CallFast = 1, JS8CallTurbo = 2, - JS8CallUltraSlow = 4 + JS8CallSlow = 4, + JS8CallUltra = 8 }; // frame type transmitted via itype and decoded by the ft8 decoded