From d5bc774641231d0d7dc826d155d40c226d4fc677 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Thu, 17 Dec 2015 20:29:55 +0000 Subject: [PATCH] Get rid of jt9com and npar common blocks Also use correct C binding and have compilers determine sizes and offsets. The wsjtx.exe program now owns the decoder shared data that is shared with symspec. It is now in struct dec_data, still a global variable for now but hopefully a MainWindow member variable soon. The struct dec_data (in both C/C++ and Fortran) has a sub structure with the decoder parameters which enables copying and manipulating a lot cleaner. New of changed types of shared data must still be modified in commons.h and a new file lib/jt9com.f90, they must stay in sync as a pointer to the structure is passed between C and Fortran. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6290 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- CMakeLists.txt | 3 +- Detector.cpp | 36 +++---- commons.h | 90 +++++++++-------- getfile.cpp | 22 +++-- getfile.h | 1 - lib/decoder.f90 | 76 +++++++-------- lib/fillcom.f90 | 50 ---------- lib/ipcomm.cpp | 10 +- lib/jt65.f90 | 252 ++++++++++++++++++++++++------------------------ lib/jt9.f90 | 120 +++++++++++++++++------ lib/jt9a.f90 | 22 +++-- lib/jt9b.f90 | 12 --- lib/jt9c.f90 | 27 ------ lib/jt9com.f90 | 50 ++++++++++ lib/symspec.f90 | 26 ++--- main.cpp | 9 +- mainwindow.cpp | 213 ++++++++++++++++++++++++---------------- mainwindow.h | 48 +-------- plotter.cpp | 5 +- plotter.h | 1 - 20 files changed, 550 insertions(+), 523 deletions(-) delete mode 100644 lib/fillcom.f90 delete mode 100644 lib/jt9b.f90 delete mode 100644 lib/jt9c.f90 create mode 100644 lib/jt9com.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c15494c8..4cf9030b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,7 +308,6 @@ set (wsjt_FSRCS lib/fil4.f90 lib/fil6521.f90 lib/filbig.f90 - lib/fillcom.f90 lib/flat1.f90 lib/flat1a.f90 lib/flat2.f90 @@ -940,7 +939,7 @@ target_link_libraries (jt4code wsjt_fort wsjt_cxx) add_executable (jt65 lib/jt65.f90 ${jt65_CXXSRCS} wsjtx.rc) target_link_libraries (jt65 wsjt_fort wsjt_cxx ${FFTW3_LIBRARIES}) -add_executable (jt9 lib/jt9.f90 lib/jt9a.f90 lib/jt9b.f90 lib/jt9c.f90 ${jt9_CXXSRCS} wsjtx.rc) +add_executable (jt9 lib/jt9.f90 lib/jt9a.f90 ${jt9_CXXSRCS} wsjtx.rc) if (${OPENMP_FOUND} OR APPLE) if (APPLE) # On Mac we don't have working OpenMP support in the C/C++ diff --git a/Detector.cpp b/Detector.cpp index d2f9240ac..fe9048b5c 100644 --- a/Detector.cpp +++ b/Detector.cpp @@ -40,19 +40,19 @@ void Detector::clear () // set index to roughly where we are in time (1ms resolution) // qint64 now (QDateTime::currentMSecsSinceEpoch ()); // unsigned msInPeriod ((now % 86400000LL) % (m_period * 1000)); - // jt9com_.kin = qMin ((msInPeriod * m_frameRate) / 1000, static_cast (sizeof (jt9com_.d2) / sizeof (jt9com_.d2[0]))); - jt9com_.kin = 0; + // dec_data.params.kin = qMin ((msInPeriod * m_frameRate) / 1000, static_cast (sizeof (dec_data.d2) / sizeof (dec_data.d2[0]))); + dec_data.params.kin = 0; m_bufferPos = 0; // fill buffer with zeros (G4WJS commented out because it might cause decoder hangs) - // qFill (jt9com_.d2, jt9com_.d2 + sizeof (jt9com_.d2) / sizeof (jt9com_.d2[0]), 0); + // qFill (dec_data.d2, dec_data.d2 + sizeof (dec_data.d2) / sizeof (dec_data.d2[0]), 0); } qint64 Detector::writeData (char const * data, qint64 maxSize) { int ns=secondInPeriod(); if(ns < m_ns) { // When ns has wrapped around to zero, restart the buffers - jt9com_.kin = 0; + dec_data.params.kin = 0; m_bufferPos = 0; } m_ns=ns; @@ -60,15 +60,15 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) // no torn frames Q_ASSERT (!(maxSize % static_cast (bytesPerFrame ()))); // these are in terms of input frames (not down sampled) - size_t framesAcceptable ((sizeof (jt9com_.d2) / - sizeof (jt9com_.d2[0]) - jt9com_.kin) * m_downSampleFactor); + size_t framesAcceptable ((sizeof (dec_data.d2) / + sizeof (dec_data.d2[0]) - dec_data.params.kin) * m_downSampleFactor); size_t framesAccepted (qMin (static_cast (maxSize / bytesPerFrame ()), framesAcceptable)); if (framesAccepted < static_cast (maxSize / bytesPerFrame ())) { qDebug () << "dropped " << maxSize / bytesPerFrame () - framesAccepted << " frames of data on the floor!" - << jt9com_.kin << ns; + << dec_data.params.kin << ns; } for (unsigned remaining = framesAccepted; remaining; ) { @@ -83,28 +83,28 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) if(m_bufferPos==m_samplesPerFFT*m_downSampleFactor) { qint32 framesToProcess (m_samplesPerFFT * m_downSampleFactor); qint32 framesAfterDownSample (m_samplesPerFFT); - if(framesToProcess==13824 and jt9com_.kin>=0 and - jt9com_.kin < (NTMAX*12000 - framesAfterDownSample)) { - fil4_(&m_buffer[0], &framesToProcess, &jt9com_.d2[jt9com_.kin], + if(framesToProcess==13824 and dec_data.params.kin>=0 and + dec_data.params.kin < (NTMAX*12000 - framesAfterDownSample)) { + fil4_(&m_buffer[0], &framesToProcess, &dec_data.d2[dec_data.params.kin], &framesAfterDownSample); - jt9com_.kin += framesAfterDownSample; + dec_data.params.kin += framesAfterDownSample; } else { - qDebug() << "framesToProcess = " << framesToProcess; - qDebug() << "jt9com_.kin = " << jt9com_.kin; - qDebug() << "secondInPeriod = " << secondInPeriod(); + qDebug() << "framesToProcess = " << framesToProcess; + qDebug() << "dec_data.params.kin = " << dec_data.params.kin; + qDebug() << "secondInPeriod = " << secondInPeriod(); qDebug() << "framesAfterDownSample" << framesAfterDownSample; } - Q_EMIT framesWritten (jt9com_.kin); + Q_EMIT framesWritten (dec_data.params.kin); m_bufferPos = 0; } } else { store (&data[(framesAccepted - remaining) * bytesPerFrame ()], - numFramesProcessed, &jt9com_.d2[jt9com_.kin]); + numFramesProcessed, &dec_data.d2[dec_data.params.kin]); m_bufferPos += numFramesProcessed; - jt9com_.kin += numFramesProcessed; + dec_data.params.kin += numFramesProcessed; if (m_bufferPos == static_cast (m_samplesPerFFT)) { - Q_EMIT framesWritten (jt9com_.kin); + Q_EMIT framesWritten (dec_data.params.kin); m_bufferPos = 0; } } diff --git a/commons.h b/commons.h index 302d66653..970221bdf 100644 --- a/commons.h +++ b/commons.h @@ -5,51 +5,61 @@ #define NTMAX 120 #define RX_SAMPLE_RATE 12000 -extern struct FortranCommon { - float ss[184*NSMAX]; //This is "common/jt9com/..." in fortran +#ifdef __cplusplus +extern "C" { +#endif + + /* + * This structure is shared with Fortran code, it MUST be kept in + * sync with lib/jt9com.f90 + */ +extern struct dec_data { + float ss[184*NSMAX]; float savg[NSMAX]; short int d2[NTMAX*RX_SAMPLE_RATE]; - int nutc; //UTC as integer, HHMM - int ndiskdat; //1 ==> data read from *.wav file - int ntrperiod; //TR period (seconds) - int nfqso; //User-selected QSO freq (kHz) - int newdat; //1 ==> new data, must do long FFT - int npts8; //npts for c0() array - int nfa; //Low decode limit (Hz) - int nfSplit; //JT65 | JT9 split frequency - int nfb; //High decode limit (Hz) - int ntol; //+/- decoding range around fQSO (Hz) - int kin; - int nzhsym; - int nsubmode; - int nagain; - int ndepth; - int ntxmode; - int nmode; - int minw; - int nclearave; - int minSync; - float emedelay; - float dttol; - int nlist; - int listutc[10]; - int n2pass; - int nranera; - int naggressive; - int nrobust; - int nexp_decode; - int nspare[9]; - char datetime[20]; - char mycall[12]; - char mygrid[6]; - char hiscall[12]; - char hisgrid[6]; -} jt9com_; + struct + { + int nutc; //UTC as integer, HHMM + int ndiskdat; //1 ==> data read from *.wav file + int ntrperiod; //TR period (seconds) + int nfqso; //User-selected QSO freq (kHz) + int newdat; //1 ==> new data, must do long FFT + int npts8; //npts for c0() array + int nfa; //Low decode limit (Hz) + int nfSplit; //JT65 | JT9 split frequency + int nfb; //High decode limit (Hz) + int ntol; //+/- decoding range around fQSO (Hz) + int kin; + int nzhsym; + int nsubmode; + int nagain; + int ndepth; + int ntxmode; + int nmode; + int minw; + int nclearave; + int minSync; + float emedelay; + float dttol; + int nlist; + int listutc[10]; + int n2pass; + int nranera; + int naggressive; + int nrobust; + int nexp_decode; + char datetime[20]; + char mycall[12]; + char mygrid[6]; + char hiscall[12]; + char hisgrid[6]; + } params; +} dec_data; -extern "C" { extern struct { float syellow[NSMAX]; } jt9w_; + extern struct { int nclearave; int nsum; @@ -57,6 +67,8 @@ extern struct { float red[4096]; } echocom_; +#ifdef __cplusplus } +#endif #endif // COMMONS_H diff --git a/getfile.cpp b/getfile.cpp index d24aa695f..d04f9ce58 100644 --- a/getfile.cpp +++ b/getfile.cpp @@ -16,6 +16,8 @@ #include #endif +#include "commons.h" + void getfile(QString fname, int ntrperiod) { struct WAVHDR { @@ -44,27 +46,27 @@ void getfile(QString fname, int ntrperiod) QString baseName=fname.mid(i1+1); i1=fname.indexOf(".wav",0,Qt::CaseInsensitive); - jt9com_.nutc=0; + dec_data.params.nutc=0; if(i1>0) { int i0=fname.indexOf("_",-11); if(i1==i0+7) { - jt9com_.nutc=fname.mid(i1-6,6).toInt(); + dec_data.params.nutc=fname.mid(i1-6,6).toInt(); } else { - jt9com_.nutc=100*fname.mid(i1-4,4).toInt(); + dec_data.params.nutc=100*fname.mid(i1-4,4).toInt(); } } if(ntrperiod > 120 or ntrperiod <0) ntrperiod=120; int npts=ntrperiod*12000; - memset(jt9com_.d2,0,2*npts); + memset(dec_data.d2,0,2*npts); if(fp != NULL) { // Read (and ignore) a 44-byte WAV header; then read data int n=fread(&hdr,1,44,fp); - n=fread(jt9com_.d2,2,npts,fp); - if(hdr.nsamrate==11025) wav12_(jt9com_.d2,jt9com_.d2,&n,&hdr.nbitsam2); + n=fread(dec_data.d2,2,npts,fp); + if(hdr.nsamrate==11025) wav12_(dec_data.d2,dec_data.d2,&n,&hdr.nbitsam2); fclose(fp); - jt9com_.newdat=1; - jt9com_.kin=n; + dec_data.params.newdat=1; + dec_data.params.kin=n; } } @@ -122,9 +124,9 @@ void savewav(QString fname, int ntrperiod) hdr.ndata=2*npts; fwrite(&hdr,sizeof(hdr),1,fp); -// memcpy(jt9com_.d2,buf,2*npts); +// memcpy(dec_data.d2,buf,2*npts); // fwrite(buf,2,npts,fp); - fwrite(jt9com_.d2,2,npts,fp); + fwrite(dec_data.d2,2,npts,fp); fclose(fp); } // free(buf); diff --git a/getfile.h b/getfile.h index 916ba7bb4..4dfd1dbbe 100644 --- a/getfile.h +++ b/getfile.h @@ -4,7 +4,6 @@ #include #include #include -#include "commons.h" void getfile(QString fname, int ntrperiod); float gran(); diff --git a/lib/decoder.f90 b/lib/decoder.f90 index eb78a517a..bdb40e0f2 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -1,50 +1,47 @@ -subroutine decoder(ss,id2,nfsample) +subroutine decoder(ss,id2,params,nfsample) use prog_args !$ use omp_lib - include 'constants.f90' + include 'jt9com.f90' real ss(184,NSMAX) logical baddata integer*2 id2(NTMAX*12000) + type(params_block) :: params real*4 dd(NTMAX*12000) - character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6 - common/npar/nutc,ndiskdat,ntrperiod,nfqso,newdat,npts8,nfa,nfsplit,nfb, & - ntol,kin,nzhsym,nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave, & - minsync,emedelay,dttol,nlist,listutc(10),n2pass,nranera,naggressive, & - nrobust,nexp_decode,nspare(9),datetime,mycall,mygrid,hiscall,hisgrid common/tracer/limtrace,lu integer onlevel(0:10) common/tracer_priv/level,onlevel !$omp threadprivate(/tracer_priv/) save - if(mod(nranera,2).eq.0) ntrials=10**(nranera/2) - if(mod(nranera,2).eq.1) ntrials=3*10**(nranera/2) - if(nranera.eq.0) ntrials=0 + if(mod(params%nranera,2).eq.0) ntrials=10**(params%nranera/2) + if(mod(params%nranera,2).eq.1) ntrials=3*10**(params%nranera/2) + if(params%nranera.eq.0) ntrials=0 rms=sqrt(dot_product(float(id2(300000:310000)), & float(id2(300000:310000)))/10000.0) if(rms.lt.2.0) go to 800 - if (nagain .eq. 0) then + if (params%nagain .eq. 0) then open(13,file=trim(temp_dir)//'/decoded.txt',status='unknown') else open(13,file=trim(temp_dir)//'/decoded.txt',status='unknown', & position='append') end if - if(nmode.eq.4 .or. nmode.eq.65) open(14,file=trim(temp_dir)//'/avemsg.txt', & + if(params%nmode.eq.4 .or. params%nmode.eq.65) open(14,file=trim(temp_dir)//'/avemsg.txt', & status='unknown') - if(nmode.eq.4) then + if(params%nmode.eq.4) then jz=52*nfsample - if(newdat.ne.0) then + if(params%newdat.ne.0) then if(nfsample.eq.12000) call wav11(id2,jz,dd) if(nfsample.eq.11025) dd(1:jz)=id2(1:jz) endif - call jt4a(dd,jz,nutc,nfqso,ntol,emedelay,dttol,nagain,ndepth, & - nclearave,minsync,minw,nsubmode,mycall,hiscall,hisgrid, & - nlist,listutc) + call jt4a(dd,jz,params%nutc,params%nfqso,params%ntol,params%emedelay,params%dttol, & + params%nagain,params%ndepth,params%nclearave,params%minsync,params%minw, & + params%nsubmode,params%mycall,params%hiscall,params%hisgrid, & + params%nlist,params%listutc) go to 800 endif @@ -55,48 +52,49 @@ subroutine decoder(ss,id2,nfsample) go to 800 endif - ntol65=ntol !### is this OK? ### - newdat65=newdat - newdat9=newdat + ntol65=params%ntol !### is this OK? ### + newdat65=params%newdat + newdat9=params%newdat !$ call omp_set_dynamic(.true.) !$omp parallel sections num_threads(2) copyin(/tracer_priv/) shared(ndecoded) if(.true.) !iif() needed on Mac !$omp section - if(nmode.eq.65 .or. (nmode.eq.(65+9) .and. ntxmode.eq.65)) then + if(params%nmode.eq.65 .or. (params%nmode.eq.(65+9) .and. params%ntxmode.eq.65)) then ! We're in JT65 mode, or should do JT65 first if(newdat65.ne.0) dd(1:npts65)=id2(1:npts65) - nf1=nfa - nf2=nfb + nf1=params%nfa + nf2=params%nfb call timer('jt65a ',0) - call jt65a(dd,npts65,newdat65,nutc,nf1,nf2,nfqso,ntol65,nsubmode, & - minsync,nagain,n2pass,nrobust,ntrials,naggressive,ndepth, & - mycall,hiscall,hisgrid,nexp_decode,ndecoded) + call jt65a(dd,npts65,newdat65,params%nutc,nf1,nf2,params%nfqso,ntol65,params%nsubmode, & + params%minsync,params%nagain,params%n2pass,params%nrobust,ntrials,params%naggressive, & + params%ndepth,params%mycall,params%hiscall,params%hisgrid,params%nexp_decode,ndecoded) call timer('jt65a ',1) - else if(nmode.eq.9 .or. (nmode.eq.(65+9) .and. ntxmode.eq.9)) then + else if(params%nmode.eq.9 .or. (params%nmode.eq.(65+9) .and. params%ntxmode.eq.9)) then ! We're in JT9 mode, or should do JT9 first call timer('decjt9 ',0) - call decjt9(ss,id2,nutc,nfqso,newdat9,npts8,nfa,nfsplit,nfb,ntol,nzhsym, & - nagain,ndepth,nmode) + call decjt9(ss,id2,params%nutc,params%nfqso,newdat9,params%npts8,params%nfa,params%nfsplit, & + params%nfb,params%ntol,params%nzhsym,params%nagain,params%ndepth,params%nmode) call timer('decjt9 ',1) endif !$omp section - if(nmode.eq.(65+9)) then !Do the other mode (we're in dual mode) - if (ntxmode.eq.9) then + if(params%nmode.eq.(65+9)) then !Do the other mode (we're in dual mode) + if (params%ntxmode.eq.9) then if(newdat65.ne.0) dd(1:npts65)=id2(1:npts65) - nf1=nfa - nf2=nfb + nf1=params%nfa + nf2=params%nfb call timer('jt65a ',0) - call jt65a(dd,npts65,newdat65,nutc,nf1,nf2,nfqso,ntol65,nsubmode, & - minsync,nagain,n2pass,nrobust,ntrials,naggressive,ndepth, & - mycall,hiscall,hisgrid,nexp_decode,ndecoded) + call jt65a(dd,npts65,newdat65,params%nutc,nf1,nf2,params%nfqso,ntol65,params%nsubmode, & + params%minsync,params%nagain,params%n2pass,params%nrobust,ntrials, & + params%naggressive,params%ndepth,params%mycall,params%hiscall,params%hisgrid, & + params%nexp_decode,ndecoded) call timer('jt65a ',1) else call timer('decjt9 ',0) - call decjt9(ss,id2,nutc,nfqso,newdat9,npts8,nfa,nfsplit,nfb,ntol, & - nzhsym,nagain,ndepth,nmode) + call decjt9(ss,id2,params%nutc,params%nfqso,newdat9,params%npts8,params%nfa,params%nfsplit, & + params%nfb,params%ntol,params%nzhsym,params%nagain,params%ndepth,params%nmode) call timer('decjt9 ',1) end if endif @@ -108,7 +106,7 @@ subroutine decoder(ss,id2,nfsample) 1010 format('',2i4) call flush(6) close(13) - if(nmode.eq.4 .or. nmode.eq.65) close(14) + if(params%nmode.eq.4 .or. params%nmode.eq.65) close(14) return end subroutine decoder diff --git a/lib/fillcom.f90 b/lib/fillcom.f90 deleted file mode 100644 index 42f725d66..000000000 --- a/lib/fillcom.f90 +++ /dev/null @@ -1,50 +0,0 @@ -subroutine fillcom(nutc0,ndepth0,nrxfreq,mode,tx9,flow,fsplit,fhigh) - integer mode,flow,fsplit,fhigh - logical tx9 - - character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6 - common/npar/nutc,ndiskdat,ntrperiod,nfqso,newdat,npts8,nfa,nfsplit,nfb, & - ntol,kin,nzhsym,nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave, & - minsync,emedelay,dttol,nlist,listutc(10),n2pass,nranera,naggressive, & - nrobust,nexp_decode,nspare(9),datetime,mycall,mygrid,hiscall,hisgrid - save - - nutc=nutc0 - ndiskdat=1 - ntrperiod=60 - nfqso=nrxfreq - newdat=1 - npts8=74736 - nfa=flow - nfsplit=fsplit - nfb=fhigh - ntol=20 - kin=648000 - nzhsym=181 - ndepth=ndepth0 - dttol=3.0 - minsync=-1 !### TEST ONLY - naggressive=1 - mycall='K1ABC' - hiscall='W9XYZ' - hisgrid='EN37' - - n2pass=1 - nranera=8 !ntrials=10000 - nrobust=0 - - if (tx9) then - ntxmode=9 - else - ntxmode=65 - end if - if (mode.eq.0) then - nmode=65+9 - else - nmode=mode - end if - datetime="2013-Apr-16 15:13" !### Temp - if(mode.eq.9 .and. nfsplit.ne.2700) nfa=nfsplit - - return -end subroutine fillcom diff --git a/lib/ipcomm.cpp b/lib/ipcomm.cpp index d845a604b..6f65dcae9 100644 --- a/lib/ipcomm.cpp +++ b/lib/ipcomm.cpp @@ -3,6 +3,8 @@ #include #include +#include "../commons.h" + // Multiple instances: KK1D, 17 Jul 2013 QSharedMemory mem_jt9; @@ -16,17 +18,13 @@ extern "C" { bool detach_jt9_(); bool lock_jt9_(); bool unlock_jt9_(); - char* address_jt9_(); + struct jt9com * address_jt9_(); int size_jt9_(); // Multiple instances: wrapper for QSharedMemory::setKey() bool setkey_jt9_(char* mykey, int mykey_len); bool acquire_jt9_(); bool release_jt9_(); - - extern struct { - char c[10]; - } jt9com_; } bool attach_jt9_() {return mem_jt9.attach();} @@ -34,7 +32,7 @@ bool create_jt9_(int nsize) {return mem_jt9.create(nsize);} bool detach_jt9_() {return mem_jt9.detach();} bool lock_jt9_() {return mem_jt9.lock();} bool unlock_jt9_() {return mem_jt9.unlock();} -char* address_jt9_() {return (char*)mem_jt9.constData();} +struct jt9com * address_jt9_() {return reinterpret_cast(mem_jt9.data());} int size_jt9_() {return (int)mem_jt9.size();} // Multiple instances: diff --git a/lib/jt65.f90 b/lib/jt65.f90 index 477aaab60..b11b5206b 100644 --- a/lib/jt65.f90 +++ b/lib/jt65.f90 @@ -1,126 +1,126 @@ -program jt65 - -! Test the JT65 decoder for WSJT-X - - use options - character c - logical :: display_help=.false. - parameter (NZMAX=60*12000) - integer*4 ihdr(11) - integer*2 id2(NZMAX) - real*4 dd(NZMAX) - character*80 infile - character(len=500) optarg - character*6 mycall,hiscall,hisgrid - common/tracer/limtrace,lu - equivalence (lenfile,ihdr(2)) - type (option) :: long_options(9) = [ & - option ('freq',.true.,'f','signal frequency, default FREQ=1270','FREQ'), & - option ('help',.false.,'h','Display this help message',''), & - option ('ntrials',.true.,'n','number of trials, default TRIALS=10000','TRIALS'), & - option ('robust-sync',.false.,'r','robust sync',''), & - option ('my-call',.true.,'c','my callsign',''), & - option ('his-call',.true.,'d','his callsign',''), & - option ('his-grid',.true.,'g','his grid locator',''), & - option ('experience-decoding',.true.,'e' & - ,'experience decoding options (1..n), default FLAGS=0','FLAGS'), & - option ('single-signal-mode',.false.,'s','decode at signal frequency only','') ] - -limtrace=0 -lu=12 -ntol=10 -nfqso=1270 -nagain=0 -nsubmode=0 -ntrials=10000 -nlow=200 -nhigh=4000 -n2pass=2 -nrobust=0 -nexp_decoded=0 - - do - call getopt('f:hn:rc:d:g:s',long_options,c,optarg,narglen,nstat,noffset,nremain,.true.) - if( nstat .ne. 0 ) then - exit - end if - select case (c) - case ('f') - read (optarg(:narglen), *) nfqso - case ('h') - display_help = .true. - case ('n') - read (optarg(:narglen), *) ntrials - case ('r') - nrobust=1 - case ('c') - read (optarg(:narglen), *) mycall - case ('d') - read (optarg(:narglen), *) hiscall - case ('g') - read (optarg(:narglen), *) hisgrid - case ('e') - read (optarg(:narglen), *) nexp_decoded - case ('s') - nlow=nfqso-ntol - nhigh=nfqso+ntol - n2pass=1 - end select - end do - - if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then - print *, '' - print *, 'Usage: jt65 [OPTIONS] file1 [file2 ...]' - print *, '' - print *, ' JT65 decode pre-recorded .WAV file(s)' - print *, '' - print *, 'OPTIONS:' - print *, '' - do i = 1, size (long_options) - call long_options(i) % print (6) - end do - go to 999 - endif - - open(12,file='timer.out',status='unknown') - call timer('jt65 ',0) - - ndecoded=0 - do ifile=noffset+1,noffset+nremain - newdat=1 - nfa=nlow - nfb=nhigh - call get_command_argument(ifile,optarg,narglen) - infile=optarg(:narglen) - open(10,file=infile,access='stream',status='old',err=998) - call timer('read ',0) - read(10) ihdr - i1=index(infile,'.wav') - if( i1 .eq. 0 ) i1=index(infile,'.WAV') - read(infile(i1-4:i1-1),*,err=998) nutc - npts=52*12000 - read(10) id2(1:npts) - call timer('read ',1) - dd(1:npts)=id2(1:npts) - dd(npts+1:)=0. - call timer('jt65a ',0) - -! open(56,file='subtracted.wav',access='stream',status='unknown') -! write(56) ihdr(1:11) - - call jt65a(dd,npts,newdat,nutc,nfa,nfb,nfqso,ntol,nsubmode, & - minsync,nagain,n2pass,nrobust,ntrials, naggressive,ndepth, & - mycall,hiscall,hisgrid,nexp_decoded,ndecoded) - call timer('jt65a ',1) - enddo - - call timer('jt65 ',1) - call timer('jt65 ',101) -! call four2a(a,-1,1,1,1) !Free the memory used for plans -! call filbig(a,-1,1,0.0,0,0,0,0,0) ! (ditto) - go to 999 - -998 print*,'Cannot read from file:' - print*,infile - -999 end program jt65 +program jt65 + +! Test the JT65 decoder for WSJT-X + + use options + character c + logical :: display_help=.false. + parameter (NZMAX=60*12000) + integer*4 ihdr(11) + integer*2 id2(NZMAX) + real*4 dd(NZMAX) + character*80 infile + character(len=500) optarg + character*6 mycall,hiscall,hisgrid + common/tracer/limtrace,lu + equivalence (lenfile,ihdr(2)) + type (option) :: long_options(9) = [ & + option ('freq',.true.,'f','signal frequency, default FREQ=1270','FREQ'), & + option ('help',.false.,'h','Display this help message',''), & + option ('ntrials',.true.,'n','number of trials, default TRIALS=10000','TRIALS'), & + option ('robust-sync',.false.,'r','robust sync',''), & + option ('my-call',.true.,'c','my callsign',''), & + option ('his-call',.true.,'x','his callsign',''), & + option ('his-grid',.true.,'g','his grid locator',''), & + option ('experience-decoding',.true.,'X' & + ,'experience decoding options (1..n), default FLAGS=0','FLAGS'), & + option ('single-signal-mode',.false.,'s','decode at signal frequency only','') ] + +limtrace=0 +lu=12 +ntol=10 +nfqso=1270 +nagain=0 +nsubmode=0 +ntrials=10000 +nlow=200 +nhigh=4000 +n2pass=2 +nrobust=0 +nexp_decoded=0 + + do + call getopt('f:hn:rc:x:g:X',long_options,c,optarg,narglen,nstat,noffset,nremain,.true.) + if( nstat .ne. 0 ) then + exit + end if + select case (c) + case ('f') + read (optarg(:narglen), *) nfqso + case ('h') + display_help = .true. + case ('n') + read (optarg(:narglen), *) ntrials + case ('r') + nrobust=1 + case ('c') + read (optarg(:narglen), *) mycall + case ('x') + read (optarg(:narglen), *) hiscall + case ('g') + read (optarg(:narglen), *) hisgrid + case ('X') + read (optarg(:narglen), *) nexp_decoded + case ('s') + nlow=nfqso-ntol + nhigh=nfqso+ntol + n2pass=1 + end select + end do + + if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then + print *, '' + print *, 'Usage: jt65 [OPTIONS] file1 [file2 ...]' + print *, '' + print *, ' JT65 decode pre-recorded .WAV file(s)' + print *, '' + print *, 'OPTIONS:' + print *, '' + do i = 1, size (long_options) + call long_options(i) % print (6) + end do + go to 999 + endif + + open(12,file='timer.out',status='unknown') + call timer('jt65 ',0) + + ndecoded=0 + do ifile=noffset+1,noffset+nremain + newdat=1 + nfa=nlow + nfb=nhigh + call get_command_argument(ifile,optarg,narglen) + infile=optarg(:narglen) + open(10,file=infile,access='stream',status='old',err=998) + call timer('read ',0) + read(10) ihdr + i1=index(infile,'.wav') + if( i1 .eq. 0 ) i1=index(infile,'.WAV') + read(infile(i1-4:i1-1),*,err=998) nutc + npts=52*12000 + read(10) id2(1:npts) + call timer('read ',1) + dd(1:npts)=id2(1:npts) + dd(npts+1:)=0. + call timer('jt65a ',0) + +! open(56,file='subtracted.wav',access='stream',status='unknown') +! write(56) ihdr(1:11) + + call jt65a(dd,npts,newdat,nutc,nfa,nfb,nfqso,ntol,nsubmode, & + minsync,nagain,n2pass,nrobust,ntrials, naggressive,ndepth, & + mycall,hiscall,hisgrid,nexp_decoded,ndecoded) + call timer('jt65a ',1) + enddo + + call timer('jt65 ',1) + call timer('jt65 ',101) +! call four2a(a,-1,1,1,1) !Free the memory used for plans +! call filbig(a,-1,1,0.0,0,0,0,0,0) ! (ditto) + go to 999 + +998 print*,'Cannot read from file:' + print*,infile + +999 end program jt65 diff --git a/lib/jt9.f90 b/lib/jt9.f90 index d50c80294..e2d6ef414 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -8,7 +8,8 @@ program jt9 use, intrinsic :: iso_c_binding use FFTW3 - include 'constants.f90' + include 'jt9com.f90' + integer(C_INT) iret integer*4 ihdr(11) real*4 s(NSMAX) @@ -17,10 +18,10 @@ program jt9 character(len=500) optarg, infile character wisfile*80 integer :: arglen,stat,offset,remain,mode=0,flow=200,fsplit=2700, & - fhigh=4000,nrxfreq=1500,ntrperiod=1,ndepth=60001 + fhigh=4000,nrxfreq=1500,ntrperiod0=1,ndepth=60001,nexp_decode=0 logical :: shmem = .false., read_files = .false., & tx9 = .false., display_help = .false. - type (option) :: long_options(17) = [ & + type (option) :: long_options(22) = [ & option ('help', .false., 'h', 'Display this help message', ''), & option ('shmem',.true.,'s','Use shared memory for sample data','KEY'), & option ('tr-period', .true., 'p', 'Tx/Rx period, default MINUTES=1', & @@ -50,22 +51,25 @@ program jt9 option ('jt4', .false., '4', 'JT4 mode', ''), & option ('depth', .true., 'd', & 'JT9 decoding depth (1-3), default DEPTH=1', 'DEPTH'), & - option ('tx-jt9', .false., 'T', 'Tx mode is JT9', '') ] - - character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6 - common/jt9com/ss(184,NSMAX),savg(NSMAX),id2(NMAX),nutc,ndiskdat, & - ntr,mousefqso,newdat,npts8a,nfa,nfsplit,nfb,ntol,kin,nzhsym, & - nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave,minsync, & - emedelay,dttol,nlist,listutc(10),n2pass,nranera,naggressive, & - nrobust,nexp_decode,nspare(9),datetime,mycall,mygrid,hiscall,hisgrid + option ('tx-jt9', .false., 'T', 'Tx mode is JT9', ''), & + option ('my-call', .true., 'c', 'my callsign', 'CALL'), & + option ('my-grid', .true., 'G', 'my grid locator', 'GRID'), & + option ('his-call', .true., 'x', 'his callsign', 'CALL'), & + option ('his-grid', .true., 'g', 'his grid locator', 'GRID'), & + option ('experience-decode', .true., 'X', & + 'experience based decoding flags (1..n), default FLAGS=0', & + 'FLAGS') ] + type(dec_data), allocatable :: shared_data + character(len=12) :: mycall, hiscall + character(len=6) :: mygrid, hisgrid common/tracer/limtrace,lu common/patience/npatience,nthreads common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano data npatience/1/,nthreads/1/ do - call getopt('hs:e:a:r:m:p:d:f:w:t:964TL:S:H:',long_options,c, & + call getopt('hs:e:a:r:m:p:d:f:w:t:964TL:S:H:c:G:x:g:X:',long_options,c, & optarg,arglen,stat,offset,remain,.true.) if (stat .ne. 0) then exit @@ -86,7 +90,7 @@ program jt9 read (optarg(:arglen), *) nthreads case ('p') read_files = .true. - read (optarg(:arglen), *) ntrperiod + read (optarg(:arglen), *) ntrperiod0 case ('d') read_files = .true. read (optarg(:arglen), *) ndepth @@ -116,6 +120,21 @@ program jt9 tx9 = .true. case ('w') read (optarg(:arglen), *) npatience + case ('c') + read_files = .true. + read (optarg(:arglen), *) mycall + case ('G') + read_files = .true. + read (optarg(:arglen), *) mygrid + case ('x') + read_files = .true. + read (optarg(:arglen), *) hiscall + case ('g') + read_files = .true. + read (optarg(:arglen), *) hisgrid + case ('X') + read_files = .true. + read (optarg(:arglen), *) nexp_decode end select end do @@ -159,6 +178,7 @@ program jt9 go to 999 endif + allocate(shared_data) limtrace=0 !We're running jt9 in stand-alone mode lu=12 nflatten=0 @@ -169,32 +189,32 @@ program jt9 open(10,file=infile,access='stream',status='old',err=998) read(10) ihdr nfsample=ihdr(7) - nutc0=ihdr(1) !Silence compiler warning + nutc=ihdr(1) !Silence compiler warning i1=index(infile,'.wav') if(i1.lt.1) i1=index(infile,'.WAV') if(infile(i1-5:i1-5).eq.'_') then - read(infile(i1-4:i1-1),*,err=1) nutc0 + read(infile(i1-4:i1-1),*,err=1) nutc else - read(infile(i1-6:i1-3),*,err=1) nutc0 + read(infile(i1-6:i1-3),*,err=1) nutc endif go to 2 -1 nutc0=0 +1 nutc=0 2 nsps=0 - if(ntrperiod.eq.1) then + if(ntrperiod0.eq.1) then nsps=6912 - nzhsym=181 - else if(ntrperiod.eq.2) then + shared_data%params%nzhsym=181 + else if(ntrperiod0.eq.2) then nsps=15360 - nzhsym=178 - else if(ntrperiod.eq.5) then + shared_data%params%nzhsym=178 + else if(ntrperiod0.eq.5) then nsps=40960 - nzhsym=172 - else if(ntrperiod.eq.10) then + shared_data%params%nzhsym=172 + else if(ntrperiod0.eq.10) then nsps=82944 - nzhsym=171 - else if(ntrperiod.eq.30) then + shared_data%params%nzhsym=171 + else if(ntrperiod0.eq.30) then nsps=252000 - nzhsym=167 + shared_data%params%nzhsym=167 endif if(nsps.eq.0) stop 'Error: bad TRperiod' @@ -212,7 +232,7 @@ program jt9 do iblk=1,npts/kstep k=iblk*kstep call timer('read_wav',0) - read(10,end=3) id2(k-kstep+1:k) + read(10,end=3) shared_data%id2(k-kstep+1:k) go to 4 3 call timer('read_wav',1) print*,'EOF on input file ',infile @@ -225,7 +245,7 @@ program jt9 ingain=0 call timer('symspec ',0) nminw=1 - call symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3, & + call symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3, & ihsym,npts8) call timer('symspec ',1) endif @@ -234,8 +254,46 @@ program jt9 endif enddo close(10) - call fillcom(nutc0,ndepth,nrxfreq,mode,tx9,flow,fsplit,fhigh) - call decoder(ss,id2,nfsample) + shared_data%params%nutc=nutc + shared_data%params%ndiskdat=1 + shared_data%params%ntr=60 + shared_data%params%nfqso=nrxfreq + shared_data%params%newdat=1 + shared_data%params%npts8=74736 + shared_data%params%nfa=flow + shared_data%params%nfsplit=fsplit + shared_data%params%nfb=fhigh + shared_data%params%ntol=20 + shared_data%params%kin=64800 + shared_data%params%nzhsym=181 + shared_data%params%ndepth=ndepth + shared_data%params%dttol=3. + shared_data%params%minsync=-1 !### TEST ONLY + shared_data%params%naggressive=1 + shared_data%params%n2pass=1 + shared_data%params%nranera=8 ! ntrials=10000 + shared_data%params%nrobust=0 + shared_data%params%nexp_decode=nexp_decode + shared_data%params%mycall=mycall + shared_data%params%mygrid=mygrid + shared_data%params%hiscall=hiscall + shared_data%params%hisgrid=hisgrid + if (shared_data%params%mycall == '') shared_data%params%mycall='K1ABC' + if (shared_data%params%hiscall == '') shared_data%params%hiscall='W9XYZ' + if (shared_data%params%hisgrid == '') shared_data%params%hiscall='EN37' + if (tx9) then + shared_data%params%ntxmode=9 + else + shared_data%params%ntxmode=65 + end if + if (mode.eq.0) then + shared_data%params%nmode=65+9 + else + shared_data%params%nmode=mode + end if + shared_data%params%datetime="2013-Apr-16 15:13" !### Temp + if(mode.eq.9 .and. fsplit.ne.2700) shared_data%params%nfa=fsplit + call decoder(shared_data%ss,shared_data%id2,shared_data%params,nfsample) enddo call timer('jt9 ',1) diff --git a/lib/jt9a.f90 b/lib/jt9a.f90 index 8b8b3f7ee..4af00c6aa 100644 --- a/lib/jt9a.f90 +++ b/lib/jt9a.f90 @@ -1,21 +1,25 @@ subroutine jt9a() - + use, intrinsic :: iso_c_binding, only: c_f_pointer use prog_args + include 'jt9com.f90' + ! These routines connect the shared memory region to the decoder. interface function address_jt9() - integer*1, pointer :: address_jt9 + use, intrinsic :: iso_c_binding, only: c_ptr + type(c_ptr) :: address_jt9 end function address_jt9 end interface integer*1 attach_jt9 ! integer*1 lock_jt9,unlock_jt9 integer size_jt9 - integer*1, pointer :: p_jt9 character*80 cwd ! Multiple instances: character*80 mykey + type(dec_data), pointer :: shared_data + type(params_block) :: local_params logical fileExists common/tracer/limtrace,lu @@ -56,17 +60,19 @@ subroutine jt9a() print*,"Must start 'jt9 -s ' from within WSJT-X." go to 999 endif - p_jt9=>address_jt9() - call timer('jt9b ',0) - call jt9b(p_jt9,nbytes) - call timer('jt9b ',1) + call c_f_pointer(address_jt9(),shared_data) + local_params=shared_data%params !save a copy because wsjtx carries on accessing + call flush(6) + call timer('decoder ',0) + call decoder(shared_data%ss,shared_data%id2,local_params,12000) + call timer('decoder ',1) 100 inquire(file=trim(temp_dir)//'/.lock',exist=fileExists) if(fileExists) go to 10 call sleep_msec(100) go to 100 -999 call timer('jt9b ',101) +999 call timer('decoder ',101) return end subroutine jt9a diff --git a/lib/jt9b.f90 b/lib/jt9b.f90 deleted file mode 100644 index 63de536b6..000000000 --- a/lib/jt9b.f90 +++ /dev/null @@ -1,12 +0,0 @@ -subroutine jt9b(jt9com,nbytes) - - include 'constants.f90' - integer*1 jt9com(0:nbytes-1) - kss=0 - ksavg=kss + 4*184*NSMAX - kid2=ksavg + 4*NSMAX - knutc=kid2 + 2*NTMAX*12000 - call jt9c(jt9com(kss),jt9com(ksavg),jt9com(kid2),jt9com(knutc)) - - return -end subroutine jt9b diff --git a/lib/jt9c.f90 b/lib/jt9c.f90 deleted file mode 100644 index f669264f8..000000000 --- a/lib/jt9c.f90 +++ /dev/null @@ -1,27 +0,0 @@ -subroutine jt9c(ss,savg,id2,nparams0) - - include 'constants.f90' - real*4 ss(184*NSMAX),savg(NSMAX) - integer*2 id2(NTMAX*12000) - - integer nparams0(61),nparams(61) - character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6 - common/npar/nutc,ndiskdat,ntrperiod,nfqso,newdat,npts8,nfa,nfsplit,nfb, & - ntol,kin,nzhsym,nsave,nagain,ndepth,ntxmode,nmode,minw,nclearave, & - minsync,emedelay,dttol,nlist,listutc(10),n2pass,nranera, & - naggressive,nrobust,nexp_decode,nspare(9),datetime,mycall,mygrid, & - hiscall,hisgrid - - common/patience/npatience,nthreads - equivalence (nparams,nutc) - - nutc=id2(1)+int(savg(1)) !Silence compiler warning - nparams=nparams0 !Copy parameters into common/npar/ -! if(ndiskdat.ne.0) npatience=2 - - call flush(6) - nfsample=12000 - call decoder(ss,id2,nfsample) - - return -end subroutine jt9c diff --git a/lib/jt9com.f90 b/lib/jt9com.f90 new file mode 100644 index 000000000..a0a63c03b --- /dev/null +++ b/lib/jt9com.f90 @@ -0,0 +1,50 @@ + use, intrinsic :: iso_c_binding, only: c_int, c_short, c_float, c_char + + include 'constants.f90' + + ! + ! these structures must be kept in sync with ../commons.h + ! + type, bind(C) :: params_block + integer(c_int) :: nutc + integer(c_int) :: ndiskdat + integer(c_int) :: ntr + integer(c_int) :: nfqso + integer(c_int) :: newdat + integer(c_int) :: npts8 + integer(c_int) :: nfa + integer(c_int) :: nfsplit + integer(c_int) :: nfb + integer(c_int) :: ntol + integer(c_int) :: kin + integer(c_int) :: nzhsym + integer(c_int) :: nsubmode + integer(c_int) :: nagain + integer(c_int) :: ndepth + integer(c_int) :: ntxmode + integer(c_int) :: nmode + integer(c_int) :: minw + integer(c_int) :: nclearave + integer(c_int) :: minsync + real(c_float) :: emedelay + real(c_float) :: dttol + integer(c_int) :: nlist + integer(c_int) :: listutc(10) + integer(c_int) :: n2pass + integer(c_int) :: nranera + integer(c_int) :: naggressive + integer(c_int) :: nrobust + integer(c_int) :: nexp_decode + character(kind=c_char, len=20) :: datetime + character(kind=c_char, len=12) :: mycall + character(kind=c_char, len=6) :: mygrid + character(kind=c_char, len=12) :: hiscall + character(kind=c_char, len=6) :: hisgrid + end type params_block + + type, bind(C) :: dec_data + real(c_float) :: ss(184,NSMAX) + real(c_float) :: savg(NSMAX) + integer(c_short) :: id2(NMAX) + type(params_block) :: params + end type dec_data diff --git a/lib/symspec.f90 b/lib/symspec.f90 index b00ef6ae1..41181453d 100644 --- a/lib/symspec.f90 +++ b/lib/symspec.f90 @@ -1,4 +1,4 @@ -subroutine symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3,ihsym,npts8) +subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3,ihsym,npts8) ! Input: ! k pointer to the most recent new data @@ -17,23 +17,17 @@ subroutine symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3,ihsym,npts8) ! ss() JT9 symbol spectra at half-symbol steps ! savg() average spectra for waterfall display - include 'constants.f90' + include 'jt9com.f90' + + type(dec_data) :: shared_data real*4 w3(MAXFFT3) real*4 s(NSMAX) real*4 ssum(NSMAX) real*4 xc(0:MAXFFT3-1) real*4 tmp(NSMAX) complex cx(0:MAXFFT3/2) - integer*2 id2 integer nch(7) - character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6 - common/jt9com/ss(184,NSMAX),savg(NSMAX),id2(NMAX),nutc,ndiskdat, & - ntr,mousefqso,newdat,npts8a,nfa,nfsplit,nfb,ntol,kin,nzhsym, & - nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave,minsync, & - emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid, & - hiscall,hisgrid - common/jt9w/syellow(NSMAX) data rms/999.0/,k0/99999999/,nfft3z/0/ data nch/1,2,4,9,18,36,72/ @@ -64,12 +58,12 @@ subroutine symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3,ihsym,npts8) ja=0 ssum=0. ihsym=0 - if(ndiskdat.eq.0) id2(k+1:)=0 !Needed to prevent "ghosts". Not sure why. + if(shared_data%params%ndiskdat.eq.0) shared_data%id2(k+1:)=0 !Needed to prevent "ghosts". Not sure why. endif gain=10.0**(0.1*ingain) sq=0. do i=k0+1,k - x1=id2(i) + x1=shared_data%id2(i) sq=sq + x1*x1 enddo sq=sq * gain @@ -85,7 +79,7 @@ subroutine symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3,ihsym,npts8) do i=0,nfft3-1 !Copy data into cx j=ja+i-(nfft3-1) xc(i)=0. - if(j.ge.1 .and.j.le.NMAX) xc(i)=fac0*id2(j) + if(j.ge.1 .and.j.le.NMAX) xc(i)=fac0*shared_data%id2(j) enddo ihsym=ihsym+1 @@ -99,18 +93,18 @@ subroutine symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3,ihsym,npts8) j=i-1 if(j.lt.0) j=j+nfft3 sx=fac*(real(cx(j))**2 + aimag(cx(j))**2) - if(ihsym.le.184) ss(ihsym,i)=sx + if(ihsym.le.184) shared_data%ss(ihsym,i)=sx ssum(i)=ssum(i) + sx s(i)=1000.0*gain*sx enddo - savg=ssum/ihsym + shared_data%savg=ssum/ihsym if(mod(ihsym,10).eq.0) then mode4=nch(nminw+1) nsmo=min(10*mode4,150) nsmo=4*nsmo - call flat1(savg,iz,nsmo,syellow) + call flat1(shared_data%savg,iz,nsmo,syellow) if(mode4.ge.2) call smo(syellow,iz,tmp,mode4) if(mode4.ge.2) call smo(syellow,iz,tmp,mode4) syellow(1:250)=0. diff --git a/main.cpp b/main.cpp index c388b09ff..94d71134f 100644 --- a/main.cpp +++ b/main.cpp @@ -28,6 +28,7 @@ #include "SettingsGroup.hpp" #include "TraceFile.hpp" #include "mainwindow.h" +#include "commons.h" #include "lib/init_random_seed.h" namespace @@ -181,16 +182,12 @@ int main(int argc, char *argv[]) mem_jt9.setKey(a.applicationName ()); if(!mem_jt9.attach()) { - if (!mem_jt9.create(sizeof(jt9com_))) { + if (!mem_jt9.create(sizeof(struct dec_data))) { QMessageBox::critical (nullptr, "Error", "Unable to create shared memory segment."); exit(1); } } - char *to = (char*)mem_jt9.data(); - int size=sizeof(jt9com_); - if(jt9com_.newdat==0) { - } - memset(to,0,size); //Zero all decoding params in shared memory + memset(mem_jt9.data(),0,sizeof(struct dec_data)); //Zero all decoding params in shared memory unsigned downSampleFactor; { diff --git a/mainwindow.cpp b/mainwindow.cpp index 155f75f44..0a7b59ee5 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -51,8 +51,57 @@ #include "ui_mainwindow.h" #include "moc_mainwindow.cpp" + +extern "C" { + //----------------------------------------------------- C and Fortran routines + void symspec_(struct dec_data *, int* k, int* ntrperiod, int* nsps, int* ingain, int* minw, + float* px, float s[], float* df3, int* nhsym, int* npts8); + + void hspec_(short int d2[], int* k, int* ingain, float green[], float s[], int* jh); + + void gen4_(char* msg, int* ichk, char* msgsent, int itone[], + int* itext, int len1, int len2); + + void gen9_(char* msg, int* ichk, char* msgsent, int itone[], + int* itext, int len1, int len2); + + void genmsk_(char* msg, int* ichk, char* msgsent, int itone[], + int* itext, int len1, int len2); + + void gen65_(char* msg, int* ichk, char* msgsent, int itone[], + int* itext, int len1, int len2); + + void genwspr_(char* msg, char* msgsent, int itone[], int len1, int len2); + + void geniscat_(char* msg, char* msgsent, int itone[], int len1, int len2); + + bool stdmsg_(const char* msg, int len); + + void azdist_(char* MyGrid, char* HisGrid, double* utch, int* nAz, int* nEl, + int* nDmiles, int* nDkm, int* nHotAz, int* nHotABetter, + int len1, int len2); + + void morse_(char* msg, int* icw, int* ncw, int len); + + int ptt_(int nport, int ntx, int* iptt, int* nopen); + + int fftwf_import_wisdom_from_filename(const char *); + int fftwf_export_wisdom_to_filename(const char *); + + void wspr_downsample_(short int d2[], int* k); + void savec2_(char* fname, int* m_TRseconds, double* m_dialFreq, int len1); + + void avecho_( short id2[], int* dop, int* nfrit, int* nqual, float* f1, + float* level, float* sigdb, float* snr, float* dfreq, + float* width); + + void fast_decode_(short id2[], int narg[], char msg[], int len); + void degrade_snr_(short d2[], int* n, float* db); +} + int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID +struct dec_data dec_data; // for sharing with Fortran int outBufSize; int rc; @@ -810,9 +859,9 @@ void MainWindow::dataSink(qint64 frames) static float df3; if(m_diskData) { - jt9com_.ndiskdat=1; + dec_data.params.ndiskdat=1; } else { - jt9com_.ndiskdat=0; + dec_data.params.ndiskdat=0; } if(m_mode=="ISCAT" or m_mode=="JTMSK" or m_bFast9) { @@ -824,13 +873,13 @@ void MainWindow::dataSink(qint64 frames) trmin=m_TRperiod/60; // int k (frames - 1); int k (frames); - jt9com_.nfa=m_wideGraph->nStartFreq(); - jt9com_.nfb=m_wideGraph->Fmax(); + dec_data.params.nfa=m_wideGraph->nStartFreq(); + dec_data.params.nfb=m_wideGraph->Fmax(); int nsps=m_nsps; if(m_bFastMode) nsps=6912; int nsmo=m_wideGraph->smoothYellow()-1; - symspec_(&k,&trmin,&nsps,&m_inGain,&nsmo,&px,s,&df3,&ihsym,&npts8); - if(m_mode=="WSPR-2") wspr_downsample_(jt9com_.d2,&k); + symspec_(&dec_data,&k,&trmin,&nsps,&m_inGain,&nsmo,&px,s,&df3,&ihsym,&npts8); + if(m_mode=="WSPR-2") wspr_downsample_(dec_data.d2,&k); if(ihsym <=0) return; QString t; m_pctZap=nzap*100.0/m_nsps; @@ -867,7 +916,7 @@ void MainWindow::dataSink(qint64 frames) float width=0.0; echocom_.nclearave=m_nclearave; int nDop=0; - avecho_(&jt9com_.d2[0],&nDop,&nfrit,&nqual,&f1,&xlevel,&sigdb, + avecho_(dec_data.d2,&nDop,&nfrit,&nqual,&f1,&xlevel,&sigdb, &snr,&dfreq,&width); QString t; t.sprintf("%3d %7.1f %7.1f %7.1f %7.1f %3d",echocom_.nsum,xlevel,sigdb, @@ -885,10 +934,10 @@ void MainWindow::dataSink(qint64 frames) } if( m_dialFreqRxWSPR==0) m_dialFreqRxWSPR=m_dialFreq; m_dataAvailable=true; - jt9com_.npts8=(ihsym*m_nsps)/16; - jt9com_.newdat=1; - jt9com_.nagain=0; - jt9com_.nzhsym=m_hsymStop; + dec_data.params.npts8=(ihsym*m_nsps)/16; + dec_data.params.newdat=1; + dec_data.params.nagain=0; + dec_data.params.nzhsym=m_hsymStop; QDateTime t = QDateTime::currentDateTimeUtc(); m_dateTime=t.toString("yyyy-MMM-dd hh:mm"); if(m_mode.mid(0,4)!="WSPR") decode(); //Start decoder @@ -963,7 +1012,7 @@ void MainWindow::fastSink(qint64 frames) 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[] fast_jh2=fast_jh; - if(!m_diskData) memset(jt9com_.d2,0,2*30*12000); //Zero the d2[] array + if(!m_diskData) memset(dec_data.d2,0,2*30*12000); //Zero the d2[] array decodeEarly=false; m_bFastDecodeCalled=false; QDateTime t=QDateTime::currentDateTimeUtc(); //.addSecs(2-m_TRperiod); @@ -978,7 +1027,7 @@ void MainWindow::fastSink(qint64 frames) } } - hspec_(&jt9com_.d2[0], &k, &m_inGain, fast_green, fast_s, &fast_jh); + hspec_(dec_data.d2, &k, &m_inGain, fast_green, fast_s, &fast_jh); px=fast_green[fast_jh] - 5.0; QString t; t.sprintf(" Rx noise: %5.1f ",px); @@ -987,7 +1036,7 @@ void MainWindow::fastSink(qint64 frames) decodeNow=false; m_k0=k; - if(m_diskData and m_k0 >= jt9com_.kin-3456) decodeNow=true; + if(m_diskData and m_k0 >= dec_data.params.kin-3456) decodeNow=true; if(!m_diskData and m_tRemaining<0.35 and !m_bFastDecodeCalled) decodeNow=true; if(decodeNow) { @@ -995,7 +1044,7 @@ void MainWindow::fastSink(qint64 frames) m_t0=0.0; m_t1=k/12000.0; m_kdone=k; - jt9com_.newdat=1; + dec_data.params.newdat=1; if(!m_decoderBusy) { m_bFastDecodeCalled=true; decode(); @@ -1156,8 +1205,8 @@ void MainWindow::keyPressEvent( QKeyEvent *e ) //keyPressEvent case Qt::Key_D: if(m_mode != "WSPR-2" && e->modifiers() & Qt::ShiftModifier) { if(!m_decoderBusy) { - jt9com_.newdat=0; - jt9com_.nagain=0; + dec_data.params.newdat=0; + dec_data.params.nagain=0; decode(); return; } @@ -1539,12 +1588,12 @@ void MainWindow::diskDat() //diskDat() m_diskData=true; float db=m_config.degrade(); - if(db > 0.0) degrade_snr_(jt9com_.d2,&jt9com_.kin,&db); + if(db > 0.0) degrade_snr_(dec_data.d2,&dec_data.params.kin,&db); for(int n=1; n<=m_hsymStop; n++) { // Do the waterfall spectra k=(n+1)*kstep; - if(k > jt9com_.kin) break; - jt9com_.npts8=k/8; + if(k > dec_data.params.kin) break; + dec_data.params.npts8=k/8; dataSink(k); qApp->processEvents(); //Update the waterfall } @@ -1618,8 +1667,8 @@ void MainWindow::on_actionSpecial_mouse_commands_triggered() void MainWindow::on_DecodeButton_clicked (bool /* checked */) //Decode request { if(m_mode != "WSPR-2" && !m_decoderBusy) { - jt9com_.newdat=0; - jt9com_.nagain=1; + dec_data.params.newdat=0; + dec_data.params.nagain=1; m_blankLine=false; // don't insert the separator again decode(); } @@ -1647,14 +1696,14 @@ void MainWindow::decode() //decode() { if(!m_dataAvailable or m_TRperiod==0) return; ui->DecodeButton->setChecked (true); - if(m_diskData and !m_bFastMode) jt9com_.nutc=jt9com_.nutc/100; - if(jt9com_.newdat==1 && (!m_diskData)) { + if(m_diskData and !m_bFastMode) dec_data.params.nutc=dec_data.params.nutc/100; + if(dec_data.params.newdat==1 && (!m_diskData)) { qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; int imin=ms/60000; int ihr=imin/60; imin=imin % 60; if(m_TRperiod>=60) imin=imin - (imin % (m_TRperiod/60)); - jt9com_.nutc=100*ihr + imin; + dec_data.params.nutc=100*ihr + imin; if(m_mode=="ISCAT" or m_bFast9) { QDateTime t=QDateTime::currentDateTimeUtc().addSecs(2-m_TRperiod); @@ -1662,71 +1711,71 @@ void MainWindow::decode() //decode() imin=t.toString("mm").toInt(); int isec=t.toString("ss").toInt(); isec=isec - isec%m_TRperiod; - jt9com_.nutc=10000*ihr + 100*imin + isec; + dec_data.params.nutc=10000*ihr + 100*imin + isec; } } - jt9com_.nfqso=m_wideGraph->rxFreq(); - jt9com_.ndepth=m_ndepth; - jt9com_.n2pass=1; - if(m_config.twoPass()) jt9com_.n2pass=2; - jt9com_.nranera=m_config.ntrials(); - jt9com_.naggressive=m_config.aggressive(); - jt9com_.nrobust=0; - if(m_config.sync1Bit()) jt9com_.nrobust=1; - jt9com_.ndiskdat=0; - if(m_diskData) jt9com_.ndiskdat=1; - jt9com_.nfa=m_wideGraph->nStartFreq(); - jt9com_.nfSplit=m_wideGraph->Fmin(); - jt9com_.nfb=m_wideGraph->Fmax(); - jt9com_.ntol=m_Ftol; - if(m_mode=="JT9+JT65") jt9com_.ntol=20; - if(jt9com_.nutc < m_nutc0) m_RxLog = 1; //Date and Time to all.txt - m_nutc0=jt9com_.nutc; - jt9com_.ntxmode=9; - if(m_modeTx=="JT65") jt9com_.ntxmode=65; - jt9com_.nmode=9; - if(m_mode=="JT65") jt9com_.nmode=65; - if(m_mode=="JT9+JT65") jt9com_.nmode=9+65; // = 74 + dec_data.params.nfqso=m_wideGraph->rxFreq(); + dec_data.params.ndepth=m_ndepth; + dec_data.params.n2pass=1; + if(m_config.twoPass()) dec_data.params.n2pass=2; + dec_data.params.nranera=m_config.ntrials(); + dec_data.params.naggressive=m_config.aggressive(); + dec_data.params.nrobust=0; + if(m_config.sync1Bit()) dec_data.params.nrobust=1; + dec_data.params.ndiskdat=0; + if(m_diskData) dec_data.params.ndiskdat=1; + dec_data.params.nfa=m_wideGraph->nStartFreq(); + dec_data.params.nfSplit=m_wideGraph->Fmin(); + dec_data.params.nfb=m_wideGraph->Fmax(); + dec_data.params.ntol=m_Ftol; + if(m_mode=="JT9+JT65") dec_data.params.ntol=20; + if(dec_data.params.nutc < m_nutc0) m_RxLog = 1; //Date and Time to all.txt + m_nutc0=dec_data.params.nutc; + dec_data.params.ntxmode=9; + if(m_modeTx=="JT65") dec_data.params.ntxmode=65; + dec_data.params.nmode=9; + if(m_mode=="JT65") dec_data.params.nmode=65; + if(m_mode=="JT9+JT65") dec_data.params.nmode=9+65; // = 74 if(m_mode=="JT4") { - jt9com_.nmode=4; - jt9com_.ntxmode=4; + dec_data.params.nmode=4; + dec_data.params.ntxmode=4; } - jt9com_.ntrperiod=m_TRperiod; - jt9com_.nsubmode=m_nSubMode; - jt9com_.minw=0; - jt9com_.nclearave=m_nclearave; + dec_data.params.ntrperiod=m_TRperiod; + dec_data.params.nsubmode=m_nSubMode; + dec_data.params.minw=0; + dec_data.params.nclearave=m_nclearave; if(m_nclearave!=0) { QFile f(m_config.temp_dir ().absoluteFilePath ("avemsg.txt")); f.remove(); } - jt9com_.dttol=m_DTtol; - jt9com_.emedelay=0.0; - if(m_bEME) jt9com_.emedelay=2.5; - jt9com_.minSync=m_minSync; - jt9com_.nexp_decode=0; - if(m_config.MyDx()) jt9com_.nexp_decode += 1; - if(m_config.CQMyN()) jt9com_.nexp_decode += 2; - if(m_config.NDxG()) jt9com_.nexp_decode += 4; - if(m_config.NN()) jt9com_.nexp_decode += 8; - if(m_config.EMEonly()) jt9com_.nexp_decode += 16; + dec_data.params.dttol=m_DTtol; + dec_data.params.emedelay=0.0; + if(m_bEME) dec_data.params.emedelay=2.5; + dec_data.params.minSync=m_minSync; + dec_data.params.nexp_decode=0; + if(m_config.MyDx()) dec_data.params.nexp_decode += 1; + if(m_config.CQMyN()) dec_data.params.nexp_decode += 2; + if(m_config.NDxG()) dec_data.params.nexp_decode += 4; + if(m_config.NN()) dec_data.params.nexp_decode += 8; + if(m_config.EMEonly()) dec_data.params.nexp_decode += 16; - strncpy(jt9com_.datetime, m_dateTime.toLatin1(), 20); - strncpy(jt9com_.mycall, (m_config.my_callsign()+" ").toLatin1(),12); - strncpy(jt9com_.mygrid, (m_config.my_grid()+" ").toLatin1(),6); + strncpy(dec_data.params.datetime, m_dateTime.toLatin1(), 20); + strncpy(dec_data.params.mycall, (m_config.my_callsign()+" ").toLatin1(),12); + strncpy(dec_data.params.mygrid, (m_config.my_grid()+" ").toLatin1(),6); QString hisCall=ui->dxCallEntry->text().toUpper().trimmed(); QString hisGrid=ui->dxGridEntry->text().toUpper().trimmed(); - strncpy(jt9com_.hiscall,(hisCall+" ").toLatin1(),12); - strncpy(jt9com_.hisgrid,(hisGrid+" ").toLatin1(),6); + strncpy(dec_data.params.hiscall,(hisCall+" ").toLatin1(),12); + strncpy(dec_data.params.hisgrid,(hisGrid+" ").toLatin1(),6); //newdat=1 ==> this is new data, must do the big FFT //nagain=1 ==> decode only at fQSO +/- Tol char *to = (char*)mem_jt9->data(); - char *from = (char*) jt9com_.ss; - int size=sizeof(jt9com_); - if(jt9com_.newdat==0) { - int noffset = 4*184*NSMAX + 4*NSMAX + 2*NTMAX*12000; + char *from = (char*) dec_data.ss; + int size=sizeof(struct dec_data); + if(dec_data.params.newdat==0) { + int noffset {offsetof (struct dec_data, params.nutc)}; to += noffset; from += noffset; size -= noffset; @@ -1742,25 +1791,25 @@ void MainWindow::decode() //decode() } static int narg[12]; static short int d2b[360000]; - narg[0]=jt9com_.nutc; + narg[0]=dec_data.params.nutc; if(m_kdone>12000*m_TRperiod) { m_kdone=12000*m_TRperiod; } narg[1]=m_kdone; narg[2]=m_nSubMode; - narg[3]=jt9com_.newdat; - narg[4]=jt9com_.minSync; + narg[3]=dec_data.params.newdat; + narg[4]=dec_data.params.minSync; narg[5]=m_nPick; narg[6]=1000.0*t0; narg[7]=1000.0*t1; narg[8]=2; //Max decode lines per decode attempt - if(jt9com_.minSync<0) narg[8]=50; + if(dec_data.params.minSync<0) narg[8]=50; if(m_mode=="ISCAT") narg[9]=101; //ISCAT if(m_mode=="JT9") narg[9]=102; //Fast JT9 if(m_mode=="JTMSK") narg[9]=103; //JTMSK narg[10]=ui->RxFreqSpinBox->value(); narg[11]=m_Ftol; - memcpy(d2b,jt9com_.d2,2*360000); + memcpy(d2b,dec_data.d2,2*360000); *future3 = QtConcurrent::run(fast_decode_,&d2b[0],&narg[0],&m_msg[0][0],80); watcher3->setFuture(*future3); } else { @@ -1870,8 +1919,8 @@ void MainWindow::readFromStdout() //readFromStdout if(t.indexOf("") >= 0) { m_bDecoded = (t.mid(23,1).toInt()==1); if(!m_diskData) killFileTimer->start (3*1000*m_TRperiod/4); //Kill in 45 s - jt9com_.nagain=0; - jt9com_.ndiskdat=0; + dec_data.params.nagain=0; + dec_data.params.ndiskdat=0; m_nclearave=0; QFile {m_config.temp_dir ().absoluteFilePath (".lock")}.open(QIODevice::ReadWrite); ui->DecodeButton->setChecked (false); @@ -5017,8 +5066,8 @@ void MainWindow::fastPick(int x0, int x1, int y) { if(m_mode!="ISCAT") return; if(!m_decoderBusy) { - jt9com_.newdat=0; - jt9com_.nagain=1; + dec_data.params.newdat=0; + dec_data.params.nagain=1; m_blankLine=false; // don't insert the separator again m_nPick=1; if(y > 120) m_nPick=2; diff --git a/mainwindow.h b/mainwindow.h index 027281655..189c05a19 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -28,6 +28,7 @@ #include "psk_reporter.h" #include "logbook/logbook.h" #include "decodedtext.h" +#include "commons.h" #define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync #define NUM_JT65_SYMBOLS 126 //63 data + 63 sync @@ -563,51 +564,4 @@ extern void getDev(int* numDevices,char hostAPI_DeviceName[][50], extern int ptt(int nport, int ntx, int* iptt, int* nopen); extern int next_tx_state(int pctx); -extern "C" { - //----------------------------------------------------- C and Fortran routines - void symspec_(int* k, int* ntrperiod, int* nsps, int* ingain, int* minw, - float* px, float s[], float* df3, int* nhsym, int* npts8); - - void hspec_(short int d2[], int* k, int* ingain, float green[], float s[], int* jh); - - void gen4_(char* msg, int* ichk, char* msgsent, int itone[], - int* itext, int len1, int len2); - - void gen9_(char* msg, int* ichk, char* msgsent, int itone[], - int* itext, int len1, int len2); - - void genmsk_(char* msg, int* ichk, char* msgsent, int itone[], - int* itext, int len1, int len2); - - void gen65_(char* msg, int* ichk, char* msgsent, int itone[], - int* itext, int len1, int len2); - - void genwspr_(char* msg, char* msgsent, int itone[], int len1, int len2); - - void geniscat_(char* msg, char* msgsent, int itone[], int len1, int len2); - - bool stdmsg_(const char* msg, int len); - - void azdist_(char* MyGrid, char* HisGrid, double* utch, int* nAz, int* nEl, - int* nDmiles, int* nDkm, int* nHotAz, int* nHotABetter, - int len1, int len2); - - void morse_(char* msg, int* icw, int* ncw, int len); - - int ptt_(int nport, int ntx, int* iptt, int* nopen); - - int fftwf_import_wisdom_from_filename(const char *); - int fftwf_export_wisdom_to_filename(const char *); - - void wspr_downsample_(short int d2[], int* k); - void savec2_(char* fname, int* m_TRseconds, double* m_dialFreq, int len1); - - void avecho_( short id2[], int* dop, int* nfrit, int* nqual, float* f1, - float* level, float* sigdb, float* snr, float* dfreq, - float* width); - - void fast_decode_(short id2[], int narg[], char msg[], int len); - void degrade_snr_(short d2[], int* n, float* db); -} - #endif // MAINWINDOW_H diff --git a/plotter.cpp b/plotter.cpp index cb0174c20..8f5d12b2a 100644 --- a/plotter.cpp +++ b/plotter.cpp @@ -1,6 +1,7 @@ #include "plotter.h" #include #include +#include "commons.h" #include "moc_plotter.cpp" @@ -130,7 +131,7 @@ void CPlotter::draw(float swide[], bool bScroll) //dr if(bScroll) { flat4_(swide,&iz,&m_Flatten); - flat4_(&jt9com_.savg[j0],&jz,&m_Flatten); + flat4_(&dec_data.savg[j0],&jz,&m_Flatten); } ymin=1.e30; @@ -157,7 +158,7 @@ void CPlotter::draw(float swide[], bool bScroll) //dr float sum=0.0; int j=j0+m_binsPerPixel*i; for(int k=0; k #include #include -#include "commons.h" #define VERT_DIVS 7 //specify grid screen divisions #define HORZ_DIVS 20