diff --git a/about.cpp b/about.cpp index 227123324..d128e10b7 100644 --- a/about.cpp +++ b/about.cpp @@ -1,23 +1,23 @@ -#include "about.h" -#include "ui_about.h" - -CAboutDlg::CAboutDlg(QWidget *parent, QString Revision) : - QDialog(parent), - m_Revision(Revision), - ui(new Ui::CAboutDlg) -{ - ui->setupUi(this); - ui->labelTxt->clear(); - m_Str = "

" + m_Revision + "

\n\n"; - m_Str += "MAP65 implements a wideband polarization-matching receiver
"; - m_Str += "for the JT65 protocol, with a matching transmitting facility.
"; - m_Str += "It is primarily intended for amateur radio EME communication.

"; - m_Str += "Copyright 2001-2012 by Joe Taylor, K1JT. Additional
"; - m_Str += "acknowledgments are contained in the source code.
"; - ui->labelTxt->setText(m_Str); -} - -CAboutDlg::~CAboutDlg() -{ - delete ui; -} +#include "about.h" +#include "ui_about.h" + +CAboutDlg::CAboutDlg(QWidget *parent, QString Revision) : + QDialog(parent), + m_Revision(Revision), + ui(new Ui::CAboutDlg) +{ + ui->setupUi(this); + ui->labelTxt->clear(); + m_Str = "

" + m_Revision + "

\n\n"; + m_Str += "MAP65 implements a wideband polarization-matching receiver
"; + m_Str += "for the JT65 protocol, with a matching transmitting facility.
"; + m_Str += "It is primarily intended for amateur radio EME communication.

"; + m_Str += "Copyright 2001-2012 by Joe Taylor, K1JT. Additional
"; + m_Str += "acknowledgments are contained in the source code.
"; + ui->labelTxt->setText(m_Str); +} + +CAboutDlg::~CAboutDlg() +{ + delete ui; +} diff --git a/about.h b/about.h index 3fe089598..ca45d1996 100644 --- a/about.h +++ b/about.h @@ -1,24 +1,24 @@ -#ifndef ABOUTDLG_H -#define ABOUTDLG_H - -#include - -namespace Ui { - class CAboutDlg; -} - -class CAboutDlg : public QDialog -{ - Q_OBJECT - -public: - explicit CAboutDlg(QWidget *parent=0, QString Revision=""); - ~CAboutDlg(); - -private: - QString m_Revision; - Ui::CAboutDlg *ui; - QString m_Str; -}; - -#endif // ABOUTDLG_H +#ifndef ABOUTDLG_H +#define ABOUTDLG_H + +#include + +namespace Ui { + class CAboutDlg; +} + +class CAboutDlg : public QDialog +{ + Q_OBJECT + +public: + explicit CAboutDlg(QWidget *parent=0, QString Revision=""); + ~CAboutDlg(); + +private: + QString m_Revision; + Ui::CAboutDlg *ui; + QString m_Str; +}; + +#endif // ABOUTDLG_H diff --git a/astro.cpp b/astro.cpp index 5ee2e3a79..d566485ed 100644 --- a/astro.cpp +++ b/astro.cpp @@ -1,102 +1,102 @@ -#include "astro.h" -#include "ui_astro.h" -#include -#include -#include -#include -#include "commons.h" - -Astro::Astro(QWidget *parent) : - QWidget(parent), - ui(new Ui::Astro) -{ - ui->setupUi(this); - ui->astroTextBrowser->setStyleSheet( - "QTextBrowser { background-color : cyan; color : black; }"); - ui->astroTextBrowser->clear(); -} - -Astro::~Astro() -{ - delete ui; -} - -void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, - int fQSO, int nsetftx, int ntxFreq, QString azelDir) -{ - static int ntxFreq0=-99; - static bool astroBusy=false; - char cc[300]; - double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx; - double ramoon,decmoon,dgrd,poloffset,xnr; - int ntsky,ndop,ndop00; - QString date = t.date().toString("yyyy MMM dd"); - QString utc = t.time().toString(); - int nyear=t.date().year(); - int month=t.date().month(); - int nday=t.date().day(); - int nhr=t.time().hour(); - int nmin=t.time().minute(); - double sec=t.time().second() + 0.001*t.time().msec(); - int isec=sec; - double uth=nhr + nmin/60.0 + sec/3600.0; - int nfreq=(int)datcom_.fcenter; - if(nfreq<10 or nfreq > 50000) nfreq=144; - - if(!astroBusy) { - astroBusy=true; - astrosub_(&nyear, &month, &nday, &uth, &nfreq, mygrid.toAscii(), - hisgrid.toAscii(), &azsun, &elsun, &azmoon, &elmoon, - &azmoondx, &elmoondx, &ntsky, &ndop, &ndop00,&ramoon, &decmoon, - &dgrd, &poloffset, &xnr, 6, 6); - astroBusy=false; - } - - sprintf(cc,"Az: %6.1f\n" - "El: %6.1f\n" - "Dop: %6d\n" - "DxAz: %6.1f\n" - "DxEl: %6.1f\n" - "DxDop: %6d\n" - "Dec: %6.1f\n" - "SunAz: %6.1f\n" - "SunEl: %6.1f\n" - "Tsky: %6d\n" - "MNR: %6.1f\n" - "Dgrd: %6.1f", - azmoon,elmoon,ndop00,azmoondx,elmoondx,ndop,decmoon,azsun,elsun, - ntsky,xnr,dgrd); - ui->astroTextBrowser->setText(" "+ date + "\nUTC: " + utc + "\n" + cc); - - QString fname=azelDir+"/azel.dat"; - QFile f(fname); - if(!f.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox mb; - mb.setText("Cannot open " + fname); - mb.exec(); - return; - } - int ndiff=0; - if(ntxFreq != ntxFreq0) ndiff=1; - ntxFreq0=ntxFreq; - QTextStream out(&f); - sprintf(cc,"%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Moon\n" - "%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Sun\n" - "%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Source\n" - "%4d,%6d,Doppler\n" - "%3d,%1d,fQSO\n" - "%3d,%1d,fQSO2\n", - nhr,nmin,isec,azmoon,elmoon, - nhr,nmin,isec,azsun,elsun, - nhr,nmin,isec,0.0,0.0, - nfreq,ndop, - fQSO,nsetftx, - ntxFreq,ndiff); - out << cc; - f.close(); -} - -void Astro::setFontSize(int n) -{ - ui->astroTextBrowser->setFontPointSize(n); -} +#include "astro.h" +#include "ui_astro.h" +#include +#include +#include +#include +#include "commons.h" + +Astro::Astro(QWidget *parent) : + QWidget(parent), + ui(new Ui::Astro) +{ + ui->setupUi(this); + ui->astroTextBrowser->setStyleSheet( + "QTextBrowser { background-color : cyan; color : black; }"); + ui->astroTextBrowser->clear(); +} + +Astro::~Astro() +{ + delete ui; +} + +void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, + int fQSO, int nsetftx, int ntxFreq, QString azelDir) +{ + static int ntxFreq0=-99; + static bool astroBusy=false; + char cc[300]; + double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx; + double ramoon,decmoon,dgrd,poloffset,xnr; + int ntsky,ndop,ndop00; + QString date = t.date().toString("yyyy MMM dd"); + QString utc = t.time().toString(); + int nyear=t.date().year(); + int month=t.date().month(); + int nday=t.date().day(); + int nhr=t.time().hour(); + int nmin=t.time().minute(); + double sec=t.time().second() + 0.001*t.time().msec(); + int isec=sec; + double uth=nhr + nmin/60.0 + sec/3600.0; + int nfreq=(int)datcom_.fcenter; + if(nfreq<10 or nfreq > 50000) nfreq=144; + + if(!astroBusy) { + astroBusy=true; + astrosub_(&nyear, &month, &nday, &uth, &nfreq, mygrid.toAscii(), + hisgrid.toAscii(), &azsun, &elsun, &azmoon, &elmoon, + &azmoondx, &elmoondx, &ntsky, &ndop, &ndop00,&ramoon, &decmoon, + &dgrd, &poloffset, &xnr, 6, 6); + astroBusy=false; + } + + sprintf(cc,"Az: %6.1f\n" + "El: %6.1f\n" + "Dop: %6d\n" + "DxAz: %6.1f\n" + "DxEl: %6.1f\n" + "DxDop: %6d\n" + "Dec: %6.1f\n" + "SunAz: %6.1f\n" + "SunEl: %6.1f\n" + "Tsky: %6d\n" + "MNR: %6.1f\n" + "Dgrd: %6.1f", + azmoon,elmoon,ndop00,azmoondx,elmoondx,ndop,decmoon,azsun,elsun, + ntsky,xnr,dgrd); + ui->astroTextBrowser->setText(" "+ date + "\nUTC: " + utc + "\n" + cc); + + QString fname=azelDir+"/azel.dat"; + QFile f(fname); + if(!f.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox mb; + mb.setText("Cannot open " + fname); + mb.exec(); + return; + } + int ndiff=0; + if(ntxFreq != ntxFreq0) ndiff=1; + ntxFreq0=ntxFreq; + QTextStream out(&f); + sprintf(cc,"%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Moon\n" + "%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Sun\n" + "%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Source\n" + "%4d,%6d,Doppler\n" + "%3d,%1d,fQSO\n" + "%3d,%1d,fQSO2\n", + nhr,nmin,isec,azmoon,elmoon, + nhr,nmin,isec,azsun,elsun, + nhr,nmin,isec,0.0,0.0, + nfreq,ndop, + fQSO,nsetftx, + ntxFreq,ndiff); + out << cc; + f.close(); +} + +void Astro::setFontSize(int n) +{ + ui->astroTextBrowser->setFontPointSize(n); +} diff --git a/astro.h b/astro.h index bf8f0107c..a142f0e3c 100644 --- a/astro.h +++ b/astro.h @@ -1,35 +1,35 @@ -#ifndef ASTRO_H -#define ASTRO_H - -#include -#include - -namespace Ui { - class Astro; -} - -class Astro : public QWidget -{ - Q_OBJECT - -public: - explicit Astro(QWidget *parent = 0); - void astroUpdate(QDateTime t, QString mygrid, QString hisgrid, - int fQSO, int nsetftx, int ntxFreq, QString azelDir); - void setFontSize(int n); - ~Astro(); - -private: - Ui::Astro *ui; -}; - -extern "C" { - void astrosub_(int* nyear, int* month, int* nday, double* uth, int* nfreq, - const char* mygrid, const char* hisgrid, double* azsun, - double* elsun, double* azmoon, double* elmoon, double* azmoondx, - double* elmoondx, int* ntsky, int* ndop, int* ndop00, - double* ramoon, double* decmoon, double* dgrd, double* poloffset, - double* xnr, int len1, int len2); -} - -#endif // ASTRO_H +#ifndef ASTRO_H +#define ASTRO_H + +#include +#include + +namespace Ui { + class Astro; +} + +class Astro : public QWidget +{ + Q_OBJECT + +public: + explicit Astro(QWidget *parent = 0); + void astroUpdate(QDateTime t, QString mygrid, QString hisgrid, + int fQSO, int nsetftx, int ntxFreq, QString azelDir); + void setFontSize(int n); + ~Astro(); + +private: + Ui::Astro *ui; +}; + +extern "C" { + void astrosub_(int* nyear, int* month, int* nday, double* uth, int* nfreq, + const char* mygrid, const char* hisgrid, double* azsun, + double* elsun, double* azmoon, double* elmoon, double* azmoondx, + double* elmoondx, int* ntsky, int* ndop, int* ndop00, + double* ramoon, double* decmoon, double* dgrd, double* poloffset, + double* xnr, int len1, int len2); +} + +#endif // ASTRO_H diff --git a/bandmap.cpp b/bandmap.cpp index deb3ed775..49b681259 100644 --- a/bandmap.cpp +++ b/bandmap.cpp @@ -1,89 +1,89 @@ -#include "bandmap.h" -#include "ui_bandmap.h" -#include - -BandMap::BandMap(QWidget *parent) : - QWidget(parent), - ui(new Ui::BandMap) -{ - ui->setupUi(this); - ui->bmTextBrowser->setStyleSheet( - "QTextBrowser { background-color : #000066; color : red; }"); - m_bandMapText=""; - ui->bmTextBrowser->clear(); -} - -BandMap::~BandMap() -{ - delete ui; -} - -void BandMap::setText(QString t) -{ - m_bandMapText=t; - int w=ui->bmTextBrowser->size().width(); - int ncols=1; - if(w>220) ncols=2; - QString s="QTextBrowser{background-color: "+m_colorBackground+"}"; - ui->bmTextBrowser->setStyleSheet(s); - QString t0="" - "
\n"; - QString tfreq,tspace,tcall; - QString s0,s1,s2,s3,bg; - bg="."; - s0=""; - s1=""; - s2=""; - s3=""; - - ui->bmTextBrowser->clear(); - QStringList lines = t.split( "\n", QString::SkipEmptyParts ); - int nrows=(lines.length()+ncols-1)/ncols; - - for(int i=0; i=3) t0 += s3; - t0 += (tfreq + tspace + tcall + "
\n"); - } - - if(ncols==2) { //2-column display - t0 += "

\n"; - for(int i=nrows; i=3) t0 += s3; - t0 += (tfreq + tspace + tcall + "
\n"); - } - if(2*nrows>lines.length()) t0 += (s0 + "
\n"); - } - ui->bmTextBrowser->setHtml(t0); -} - -void BandMap::resizeEvent(QResizeEvent* ) -{ - setText(m_bandMapText); -} - -void BandMap::setColors(QString t) -{ - m_colorBackground = "#"+t.mid(0,6); - m_color0 = "#"+t.mid(6,6); - m_color1 = "#"+t.mid(12,6); - m_color2 = "#"+t.mid(18,6); - m_color3 = "#"+t.mid(24,6); - setText(m_bandMapText); -} +#include "bandmap.h" +#include "ui_bandmap.h" +#include + +BandMap::BandMap(QWidget *parent) : + QWidget(parent), + ui(new Ui::BandMap) +{ + ui->setupUi(this); + ui->bmTextBrowser->setStyleSheet( + "QTextBrowser { background-color : #000066; color : red; }"); + m_bandMapText=""; + ui->bmTextBrowser->clear(); +} + +BandMap::~BandMap() +{ + delete ui; +} + +void BandMap::setText(QString t) +{ + m_bandMapText=t; + int w=ui->bmTextBrowser->size().width(); + int ncols=1; + if(w>220) ncols=2; + QString s="QTextBrowser{background-color: "+m_colorBackground+"}"; + ui->bmTextBrowser->setStyleSheet(s); + QString t0="" + "
\n"; + QString tfreq,tspace,tcall; + QString s0,s1,s2,s3,bg; + bg="."; + s0=""; + s1=""; + s2=""; + s3=""; + + ui->bmTextBrowser->clear(); + QStringList lines = t.split( "\n", QString::SkipEmptyParts ); + int nrows=(lines.length()+ncols-1)/ncols; + + for(int i=0; i=3) t0 += s3; + t0 += (tfreq + tspace + tcall + "
\n"); + } + + if(ncols==2) { //2-column display + t0 += "

\n"; + for(int i=nrows; i=3) t0 += s3; + t0 += (tfreq + tspace + tcall + "
\n"); + } + if(2*nrows>lines.length()) t0 += (s0 + "
\n"); + } + ui->bmTextBrowser->setHtml(t0); +} + +void BandMap::resizeEvent(QResizeEvent* ) +{ + setText(m_bandMapText); +} + +void BandMap::setColors(QString t) +{ + m_colorBackground = "#"+t.mid(0,6); + m_color0 = "#"+t.mid(6,6); + m_color1 = "#"+t.mid(12,6); + m_color2 = "#"+t.mid(18,6); + m_color3 = "#"+t.mid(24,6); + setText(m_bandMapText); +} diff --git a/bandmap.h b/bandmap.h index c20069375..2c3f8a21e 100644 --- a/bandmap.h +++ b/bandmap.h @@ -1,34 +1,34 @@ -#ifndef BANDMAP_H -#define BANDMAP_H - -#include - -namespace Ui { - class BandMap; -} - -class BandMap : public QWidget -{ - Q_OBJECT - -public: - explicit BandMap(QWidget *parent = 0); - void setText(QString t); - void setColors(QString t); - - ~BandMap(); - -protected: - void resizeEvent(QResizeEvent* event); - -private: - Ui::BandMap *ui; - QString m_bandMapText; - QString m_colorBackground; - QString m_color0; - QString m_color1; - QString m_color2; - QString m_color3; -}; - -#endif // BANDMAP_H +#ifndef BANDMAP_H +#define BANDMAP_H + +#include + +namespace Ui { + class BandMap; +} + +class BandMap : public QWidget +{ + Q_OBJECT + +public: + explicit BandMap(QWidget *parent = 0); + void setText(QString t); + void setColors(QString t); + + ~BandMap(); + +protected: + void resizeEvent(QResizeEvent* event); + +private: + Ui::BandMap *ui; + QString m_bandMapText; + QString m_colorBackground; + QString m_color0; + QString m_color1; + QString m_color2; + QString m_color3; +}; + +#endif // BANDMAP_H diff --git a/commons.h b/commons.h index b27217579..985119f98 100644 --- a/commons.h +++ b/commons.h @@ -1,42 +1,42 @@ -#ifndef COMMONS_H -#define COMMONS_H - -#define NFFT 32768 - -extern "C" { - -extern struct { //This is "common/datcom/..." in Fortran - float d4[4*5760000]; //Raw I/Q data from Linrad - float ss[4*322*NFFT]; //Half-symbol spectra at 0,45,90,135 deg pol - float savg[4*NFFT]; //Avg spectra at 0,45,90,135 deg pol - double fcenter; //Center freq from Linrad (MHz) - int nutc; //UTC as integer, HHMM - int idphi; //Phase correction for Y pol'n, degrees - int mousedf; //User-selected DF - int mousefqso; //User-selected QSO freq (kHz) - int nagain; //1 ==> decode only at fQSO +/- Tol - int ndepth; //How much hinted decoding to do? - int ndiskdat; //1 ==> data read from *.tf2 or *.iq file - int neme; //Hinted decoding tries only for EME calls - int newdat; //1 ==> new data, must do long FFT - int nfa; //Low decode limit (kHz) - int nfb; //High decode limit (kHz) - int nfcal; //Frequency correction, for calibration (Hz) - int nfshift; //Shift of displayed center freq (kHz) - int mcall3; //1 ==> CALL3.TXT has been modified - int ntimeout; //Max for timeouts in Messages and BandMap - int ntol; //+/- decoding range around fQSO (Hz) - int nxant; //1 ==> add 45 deg to measured pol angle - int map65RxLog; //Flags to control log files - int nfsample; //Input sample rate - int nxpol; //1 if using xpol antennas, 0 otherwise - int mode65; //JT65 sub-mode: A=1, B=2, C=4 - char mycall[12]; - char mygrid[6]; - char hiscall[12]; - char hisgrid[6]; - char datetime[20]; -} datcom_; -} - -#endif // COMMONS_H +#ifndef COMMONS_H +#define COMMONS_H + +#define NFFT 32768 + +extern "C" { + +extern struct { //This is "common/datcom/..." in Fortran + float d4[4*5760000]; //Raw I/Q data from Linrad + float ss[4*322*NFFT]; //Half-symbol spectra at 0,45,90,135 deg pol + float savg[4*NFFT]; //Avg spectra at 0,45,90,135 deg pol + double fcenter; //Center freq from Linrad (MHz) + int nutc; //UTC as integer, HHMM + int idphi; //Phase correction for Y pol'n, degrees + int mousedf; //User-selected DF + int mousefqso; //User-selected QSO freq (kHz) + int nagain; //1 ==> decode only at fQSO +/- Tol + int ndepth; //How much hinted decoding to do? + int ndiskdat; //1 ==> data read from *.tf2 or *.iq file + int neme; //Hinted decoding tries only for EME calls + int newdat; //1 ==> new data, must do long FFT + int nfa; //Low decode limit (kHz) + int nfb; //High decode limit (kHz) + int nfcal; //Frequency correction, for calibration (Hz) + int nfshift; //Shift of displayed center freq (kHz) + int mcall3; //1 ==> CALL3.TXT has been modified + int ntimeout; //Max for timeouts in Messages and BandMap + int ntol; //+/- decoding range around fQSO (Hz) + int nxant; //1 ==> add 45 deg to measured pol angle + int map65RxLog; //Flags to control log files + int nfsample; //Input sample rate + int nxpol; //1 if using xpol antennas, 0 otherwise + int mode65; //JT65 sub-mode: A=1, B=2, C=4 + char mycall[12]; + char mygrid[6]; + char hiscall[12]; + char hisgrid[6]; + char datetime[20]; +} datcom_; +} + +#endif // COMMONS_H diff --git a/devsetup.cpp b/devsetup.cpp index b4db9393a..ec00f6243 100644 --- a/devsetup.cpp +++ b/devsetup.cpp @@ -1,325 +1,325 @@ -#include "devsetup.h" -#include "mainwindow.h" -#include -#include - -#define MAXDEVICES 100 - -//----------------------------------------------------------- DevSetup() -DevSetup::DevSetup(QWidget *parent) : QDialog(parent) -{ - ui.setupUi(this); //setup the dialog form - m_restartSoundIn=false; - m_restartSoundOut=false; -} - -DevSetup::~DevSetup() -{ -} - -void DevSetup::initDlg() -{ - int k,id; - int valid_devices=0; - int minChan[MAXDEVICES]; - int maxChan[MAXDEVICES]; - int minSpeed[MAXDEVICES]; - int maxSpeed[MAXDEVICES]; - char hostAPI_DeviceName[MAXDEVICES][50]; - char s[60]; - int numDevices=Pa_GetDeviceCount(); - getDev(&numDevices,hostAPI_DeviceName,minChan,maxChan,minSpeed,maxSpeed); - k=0; - for(id=0; id= minSpeed[id] && 96000 <= maxSpeed[id]) { - m_inDevList[k]=id; - k++; - sprintf(s,"%2d %d %-49s",id,maxChan[id],hostAPI_DeviceName[id]); - QString t(s); - ui.comboBoxSndIn->addItem(t); - valid_devices++; - } - } - - const PaDeviceInfo *pdi; - int nchout; - char *p,*p1; - char p2[50]; - char pa_device_name[128]; - char pa_device_hostapi[128]; - - k=0; - for(id=0; idmaxOutputChannels; - if(nchout>=2) { - m_outDevList[k]=id; - k++; - sprintf((char*)(pa_device_name),"%s",pdi->name); - sprintf((char*)(pa_device_hostapi),"%s", - Pa_GetHostApiInfo(pdi->hostApi)->name); - - p1=(char*)""; - p=strstr(pa_device_hostapi,"MME"); - if(p!=NULL) p1=(char*)"MME"; - p=strstr(pa_device_hostapi,"Direct"); - if(p!=NULL) p1=(char*)"DirectX"; - p=strstr(pa_device_hostapi,"WASAPI"); - if(p!=NULL) p1=(char*)"WASAPI"; - p=strstr(pa_device_hostapi,"ASIO"); - if(p!=NULL) p1=(char*)"ASIO"; - p=strstr(pa_device_hostapi,"WDM-KS"); - if(p!=NULL) p1=(char*)"WDM-KS"; - - sprintf(p2,"%2d %-8s %-39s",id,p1,pa_device_name); - QString t(p2); - ui.comboBoxSndOut->addItem(t); - } - } - - ui.myCallEntry->setText(m_myCall); - ui.myGridEntry->setText(m_myGrid); - ui.idIntSpinBox->setValue(m_idInt); - ui.pttComboBox->setCurrentIndex(m_pttPort); - ui.astroFont->setValue(m_astroFont); - ui.cbXpol->setChecked(m_xpol); - ui.rbAntennaX->setChecked(m_xpolx); - ui.saveDirEntry->setText(m_saveDir); - ui.azelDirEntry->setText(m_azelDir); - ui.dxccEntry->setText(m_dxccPfx); - ui.timeoutSpinBox->setValue(m_timeout); - ui.dPhiSpinBox->setValue(m_dPhi); - ui.fCalSpinBox->setValue(m_fCal); - ui.faddEntry->setText(QString::number(m_fAdd,'f',3)); - ui.networkRadioButton->setChecked(m_network); - ui.soundCardRadioButton->setChecked(!m_network); - ui.rb96000->setChecked(m_fs96000); - ui.rb95238->setChecked(!m_fs96000); - ui.comboBoxSndIn->setEnabled(!m_network); - ui.comboBoxSndIn->setCurrentIndex(m_nDevIn); - ui.comboBoxSndOut->setCurrentIndex(m_nDevOut); - ui.sbPort->setValue(m_udpPort); - ui.cbIQswap->setChecked(m_IQswap); - ui.cb10db->setChecked(m_10db); - ui.cbInitIQplus->setChecked(m_initIQplus); - ui.mult570SpinBox->setValue(m_mult570); - ui.cal570SpinBox->setValue(m_cal570); - sscanf(m_colors.toAscii(),"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", - &r,&g,&b,&r0,&g0,&b0,&r1,&g1,&b1,&r2,&g2,&b2,&r3,&g3,&b3); - updateColorLabels(); - ui.sbBackgroundRed->setValue(r); - ui.sbBackgroundGreen->setValue(g); - ui.sbBackgroundBlue->setValue(b); - ui.sbRed0->setValue(r0); - ui.sbRed1->setValue(r1); - ui.sbRed2->setValue(r2); - ui.sbRed3->setValue(r3); - ui.sbGreen0->setValue(g0); - ui.sbGreen1->setValue(g1); - ui.sbGreen2->setValue(g2); - ui.sbGreen3->setValue(g3); - ui.sbBlue0->setValue(b0); - ui.sbBlue1->setValue(b1); - ui.sbBlue2->setValue(b2); - ui.sbBlue3->setValue(b3); - - m_paInDevice=m_inDevList[m_nDevIn]; - m_paOutDevice=m_outDevList[m_nDevOut]; - -} - -//------------------------------------------------------- accept() -void DevSetup::accept() -{ - // Called when OK button is clicked. - // Check to see whether SoundInThread must be restarted, - // and save user parameters. - - if(m_network!=ui.networkRadioButton->isChecked() or - m_nDevIn!=ui.comboBoxSndIn->currentIndex() or - m_paInDevice!=m_inDevList[m_nDevIn] or - m_xpol!=ui.cbXpol->isChecked() or - m_udpPort!=ui.sbPort->value()) m_restartSoundIn=true; - - if(m_nDevOut!=ui.comboBoxSndOut->currentIndex() or - m_paOutDevice!=m_outDevList[m_nDevOut]) m_restartSoundOut=true; - - m_myCall=ui.myCallEntry->text(); - m_myGrid=ui.myGridEntry->text(); - m_idInt=ui.idIntSpinBox->value(); - m_pttPort=ui.pttComboBox->currentIndex(); - m_astroFont=ui.astroFont->value(); - m_xpol=ui.cbXpol->isChecked(); - m_xpolx=ui.rbAntennaX->isChecked(); - m_saveDir=ui.saveDirEntry->text(); - m_azelDir=ui.azelDirEntry->text(); - m_dxccPfx=ui.dxccEntry->text(); - m_timeout=ui.timeoutSpinBox->value(); - m_dPhi=ui.dPhiSpinBox->value(); - m_fCal=ui.fCalSpinBox->value(); - m_fAdd=ui.faddEntry->text().toDouble(); - m_network=ui.networkRadioButton->isChecked(); - m_fs96000=ui.rb96000->isChecked(); - m_nDevIn=ui.comboBoxSndIn->currentIndex(); - m_paInDevice=m_inDevList[m_nDevIn]; - m_nDevOut=ui.comboBoxSndOut->currentIndex(); - m_paOutDevice=m_outDevList[m_nDevOut]; - m_udpPort=ui.sbPort->value(); - m_IQswap=ui.cbIQswap->isChecked(); - m_10db=ui.cb10db->isChecked(); - m_initIQplus=ui.cbInitIQplus->isChecked(); - m_mult570=ui.mult570SpinBox->value(); - m_cal570=ui.cal570SpinBox->value(); - - QDialog::accept(); -} - -void DevSetup::on_soundCardRadioButton_toggled(bool checked) -{ - ui.comboBoxSndIn->setEnabled(ui.soundCardRadioButton->isChecked()); - ui.rb96000->setChecked(checked); - ui.rb95238->setEnabled(!checked); - ui.label_InputDev->setEnabled(checked); - ui.label_Port->setEnabled(!checked); - ui.sbPort->setEnabled(!checked); - ui.cbIQswap->setEnabled(checked); - ui.cb10db->setEnabled(checked); -} - -void DevSetup::on_cbXpol_stateChanged(int n) -{ - m_xpol = (n!=0); - ui.rbAntenna->setEnabled(m_xpol); - ui.rbAntennaX->setEnabled(m_xpol); - ui.dPhiSpinBox->setEnabled(m_xpol); - ui.labelDphi->setEnabled(m_xpol); -} - -void DevSetup::on_cal570SpinBox_valueChanged(double ppm) -{ - m_cal570=ppm; -} - -void DevSetup::on_mult570SpinBox_valueChanged(int mult) -{ - m_mult570=mult; -} - -void DevSetup::updateColorLabels() -{ - QString t; - int r=ui.sbBackgroundRed->value(); - int g=ui.sbBackgroundGreen->value(); - int b=ui.sbBackgroundBlue->value(); - int r0=ui.sbRed0->value(); - int r1=ui.sbRed1->value(); - int r2=ui.sbRed2->value(); - int r3=ui.sbRed3->value(); - int g0=ui.sbGreen0->value(); - int g1=ui.sbGreen1->value(); - int g2=ui.sbGreen2->value(); - int g3=ui.sbGreen3->value(); - int b0=ui.sbBlue0->value(); - int b1=ui.sbBlue1->value(); - int b2=ui.sbBlue2->value(); - int b3=ui.sbBlue3->value(); - - t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" - "color: #%2.2x%2.2x%2.2x}",r,g,b,r0,g0,b0); - ui.lab0->setStyleSheet(t); - t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" - "color: #%2.2x%2.2x%2.2x}",r,g,b,r1,g1,b1); - ui.lab1->setStyleSheet(t); - t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" - "color: #%2.2x%2.2x%2.2x}",r,g,b,r2,g2,b2); - ui.lab2->setStyleSheet(t); - t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" - "color: #%2.2x%2.2x%2.2x}",r,g,b,r3,g3,b3); - ui.lab3->setStyleSheet(t); - - m_colors.sprintf("%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x" - "%2.2x%2.2x%2.2x",r,g,b,r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3); -} - -void DevSetup::on_sbBackgroundRed_valueChanged(int r) -{ - updateColorLabels(); -} - -void DevSetup::on_sbBackgroundGreen_valueChanged(int g) -{ - updateColorLabels(); -} - -void DevSetup::on_sbBackgroundBlue_valueChanged(int b) -{ - updateColorLabels(); -} - - -void DevSetup::on_sbRed0_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbGreen0_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbBlue0_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbRed1_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbGreen1_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbBlue1_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbRed2_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbGreen2_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbBlue2_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbRed3_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbGreen3_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_sbBlue3_valueChanged(int arg1) -{ - updateColorLabels(); -} - -void DevSetup::on_pushButton_5_clicked() -{ - QColor color = QColorDialog::getColor(Qt::green, this); - if (color.isValid()) { - } -} +#include "devsetup.h" +#include "mainwindow.h" +#include +#include + +#define MAXDEVICES 100 + +//----------------------------------------------------------- DevSetup() +DevSetup::DevSetup(QWidget *parent) : QDialog(parent) +{ + ui.setupUi(this); //setup the dialog form + m_restartSoundIn=false; + m_restartSoundOut=false; +} + +DevSetup::~DevSetup() +{ +} + +void DevSetup::initDlg() +{ + int k,id; + int valid_devices=0; + int minChan[MAXDEVICES]; + int maxChan[MAXDEVICES]; + int minSpeed[MAXDEVICES]; + int maxSpeed[MAXDEVICES]; + char hostAPI_DeviceName[MAXDEVICES][50]; + char s[60]; + int numDevices=Pa_GetDeviceCount(); + getDev(&numDevices,hostAPI_DeviceName,minChan,maxChan,minSpeed,maxSpeed); + k=0; + for(id=0; id= minSpeed[id] && 96000 <= maxSpeed[id]) { + m_inDevList[k]=id; + k++; + sprintf(s,"%2d %d %-49s",id,maxChan[id],hostAPI_DeviceName[id]); + QString t(s); + ui.comboBoxSndIn->addItem(t); + valid_devices++; + } + } + + const PaDeviceInfo *pdi; + int nchout; + char *p,*p1; + char p2[50]; + char pa_device_name[128]; + char pa_device_hostapi[128]; + + k=0; + for(id=0; idmaxOutputChannels; + if(nchout>=2) { + m_outDevList[k]=id; + k++; + sprintf((char*)(pa_device_name),"%s",pdi->name); + sprintf((char*)(pa_device_hostapi),"%s", + Pa_GetHostApiInfo(pdi->hostApi)->name); + + p1=(char*)""; + p=strstr(pa_device_hostapi,"MME"); + if(p!=NULL) p1=(char*)"MME"; + p=strstr(pa_device_hostapi,"Direct"); + if(p!=NULL) p1=(char*)"DirectX"; + p=strstr(pa_device_hostapi,"WASAPI"); + if(p!=NULL) p1=(char*)"WASAPI"; + p=strstr(pa_device_hostapi,"ASIO"); + if(p!=NULL) p1=(char*)"ASIO"; + p=strstr(pa_device_hostapi,"WDM-KS"); + if(p!=NULL) p1=(char*)"WDM-KS"; + + sprintf(p2,"%2d %-8s %-39s",id,p1,pa_device_name); + QString t(p2); + ui.comboBoxSndOut->addItem(t); + } + } + + ui.myCallEntry->setText(m_myCall); + ui.myGridEntry->setText(m_myGrid); + ui.idIntSpinBox->setValue(m_idInt); + ui.pttComboBox->setCurrentIndex(m_pttPort); + ui.astroFont->setValue(m_astroFont); + ui.cbXpol->setChecked(m_xpol); + ui.rbAntennaX->setChecked(m_xpolx); + ui.saveDirEntry->setText(m_saveDir); + ui.azelDirEntry->setText(m_azelDir); + ui.dxccEntry->setText(m_dxccPfx); + ui.timeoutSpinBox->setValue(m_timeout); + ui.dPhiSpinBox->setValue(m_dPhi); + ui.fCalSpinBox->setValue(m_fCal); + ui.faddEntry->setText(QString::number(m_fAdd,'f',3)); + ui.networkRadioButton->setChecked(m_network); + ui.soundCardRadioButton->setChecked(!m_network); + ui.rb96000->setChecked(m_fs96000); + ui.rb95238->setChecked(!m_fs96000); + ui.comboBoxSndIn->setEnabled(!m_network); + ui.comboBoxSndIn->setCurrentIndex(m_nDevIn); + ui.comboBoxSndOut->setCurrentIndex(m_nDevOut); + ui.sbPort->setValue(m_udpPort); + ui.cbIQswap->setChecked(m_IQswap); + ui.cb10db->setChecked(m_10db); + ui.cbInitIQplus->setChecked(m_initIQplus); + ui.mult570SpinBox->setValue(m_mult570); + ui.cal570SpinBox->setValue(m_cal570); + sscanf(m_colors.toAscii(),"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", + &r,&g,&b,&r0,&g0,&b0,&r1,&g1,&b1,&r2,&g2,&b2,&r3,&g3,&b3); + updateColorLabels(); + ui.sbBackgroundRed->setValue(r); + ui.sbBackgroundGreen->setValue(g); + ui.sbBackgroundBlue->setValue(b); + ui.sbRed0->setValue(r0); + ui.sbRed1->setValue(r1); + ui.sbRed2->setValue(r2); + ui.sbRed3->setValue(r3); + ui.sbGreen0->setValue(g0); + ui.sbGreen1->setValue(g1); + ui.sbGreen2->setValue(g2); + ui.sbGreen3->setValue(g3); + ui.sbBlue0->setValue(b0); + ui.sbBlue1->setValue(b1); + ui.sbBlue2->setValue(b2); + ui.sbBlue3->setValue(b3); + + m_paInDevice=m_inDevList[m_nDevIn]; + m_paOutDevice=m_outDevList[m_nDevOut]; + +} + +//------------------------------------------------------- accept() +void DevSetup::accept() +{ + // Called when OK button is clicked. + // Check to see whether SoundInThread must be restarted, + // and save user parameters. + + if(m_network!=ui.networkRadioButton->isChecked() or + m_nDevIn!=ui.comboBoxSndIn->currentIndex() or + m_paInDevice!=m_inDevList[m_nDevIn] or + m_xpol!=ui.cbXpol->isChecked() or + m_udpPort!=ui.sbPort->value()) m_restartSoundIn=true; + + if(m_nDevOut!=ui.comboBoxSndOut->currentIndex() or + m_paOutDevice!=m_outDevList[m_nDevOut]) m_restartSoundOut=true; + + m_myCall=ui.myCallEntry->text(); + m_myGrid=ui.myGridEntry->text(); + m_idInt=ui.idIntSpinBox->value(); + m_pttPort=ui.pttComboBox->currentIndex(); + m_astroFont=ui.astroFont->value(); + m_xpol=ui.cbXpol->isChecked(); + m_xpolx=ui.rbAntennaX->isChecked(); + m_saveDir=ui.saveDirEntry->text(); + m_azelDir=ui.azelDirEntry->text(); + m_dxccPfx=ui.dxccEntry->text(); + m_timeout=ui.timeoutSpinBox->value(); + m_dPhi=ui.dPhiSpinBox->value(); + m_fCal=ui.fCalSpinBox->value(); + m_fAdd=ui.faddEntry->text().toDouble(); + m_network=ui.networkRadioButton->isChecked(); + m_fs96000=ui.rb96000->isChecked(); + m_nDevIn=ui.comboBoxSndIn->currentIndex(); + m_paInDevice=m_inDevList[m_nDevIn]; + m_nDevOut=ui.comboBoxSndOut->currentIndex(); + m_paOutDevice=m_outDevList[m_nDevOut]; + m_udpPort=ui.sbPort->value(); + m_IQswap=ui.cbIQswap->isChecked(); + m_10db=ui.cb10db->isChecked(); + m_initIQplus=ui.cbInitIQplus->isChecked(); + m_mult570=ui.mult570SpinBox->value(); + m_cal570=ui.cal570SpinBox->value(); + + QDialog::accept(); +} + +void DevSetup::on_soundCardRadioButton_toggled(bool checked) +{ + ui.comboBoxSndIn->setEnabled(ui.soundCardRadioButton->isChecked()); + ui.rb96000->setChecked(checked); + ui.rb95238->setEnabled(!checked); + ui.label_InputDev->setEnabled(checked); + ui.label_Port->setEnabled(!checked); + ui.sbPort->setEnabled(!checked); + ui.cbIQswap->setEnabled(checked); + ui.cb10db->setEnabled(checked); +} + +void DevSetup::on_cbXpol_stateChanged(int n) +{ + m_xpol = (n!=0); + ui.rbAntenna->setEnabled(m_xpol); + ui.rbAntennaX->setEnabled(m_xpol); + ui.dPhiSpinBox->setEnabled(m_xpol); + ui.labelDphi->setEnabled(m_xpol); +} + +void DevSetup::on_cal570SpinBox_valueChanged(double ppm) +{ + m_cal570=ppm; +} + +void DevSetup::on_mult570SpinBox_valueChanged(int mult) +{ + m_mult570=mult; +} + +void DevSetup::updateColorLabels() +{ + QString t; + int r=ui.sbBackgroundRed->value(); + int g=ui.sbBackgroundGreen->value(); + int b=ui.sbBackgroundBlue->value(); + int r0=ui.sbRed0->value(); + int r1=ui.sbRed1->value(); + int r2=ui.sbRed2->value(); + int r3=ui.sbRed3->value(); + int g0=ui.sbGreen0->value(); + int g1=ui.sbGreen1->value(); + int g2=ui.sbGreen2->value(); + int g3=ui.sbGreen3->value(); + int b0=ui.sbBlue0->value(); + int b1=ui.sbBlue1->value(); + int b2=ui.sbBlue2->value(); + int b3=ui.sbBlue3->value(); + + t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" + "color: #%2.2x%2.2x%2.2x}",r,g,b,r0,g0,b0); + ui.lab0->setStyleSheet(t); + t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" + "color: #%2.2x%2.2x%2.2x}",r,g,b,r1,g1,b1); + ui.lab1->setStyleSheet(t); + t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" + "color: #%2.2x%2.2x%2.2x}",r,g,b,r2,g2,b2); + ui.lab2->setStyleSheet(t); + t.sprintf("QLabel{background-color: #%2.2x%2.2x%2.2x;" + "color: #%2.2x%2.2x%2.2x}",r,g,b,r3,g3,b3); + ui.lab3->setStyleSheet(t); + + m_colors.sprintf("%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x" + "%2.2x%2.2x%2.2x",r,g,b,r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3); +} + +void DevSetup::on_sbBackgroundRed_valueChanged(int r) +{ + updateColorLabels(); +} + +void DevSetup::on_sbBackgroundGreen_valueChanged(int g) +{ + updateColorLabels(); +} + +void DevSetup::on_sbBackgroundBlue_valueChanged(int b) +{ + updateColorLabels(); +} + + +void DevSetup::on_sbRed0_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbGreen0_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbBlue0_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbRed1_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbGreen1_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbBlue1_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbRed2_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbGreen2_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbBlue2_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbRed3_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbGreen3_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_sbBlue3_valueChanged(int arg1) +{ + updateColorLabels(); +} + +void DevSetup::on_pushButton_5_clicked() +{ + QColor color = QColorDialog::getColor(Qt::green, this); + if (color.isValid()) { + } +} diff --git a/devsetup.h b/devsetup.h index 56f6bd6ad..1fc34331f 100644 --- a/devsetup.h +++ b/devsetup.h @@ -1,83 +1,83 @@ -#ifndef DEVSETUP_H -#define DEVSETUP_H - -#include -#include "ui_devsetup.h" - -class DevSetup : public QDialog -{ - Q_OBJECT -public: - DevSetup(QWidget *parent=0); - ~DevSetup(); - - void initDlg(); - qint32 m_idInt; - qint32 m_pttPort; - qint32 m_nDevIn; - qint32 m_nDevOut; - qint32 m_inDevList[100]; - qint32 m_outDevList[100]; - qint32 m_paInDevice; - qint32 m_paOutDevice; - qint32 m_timeout; - qint32 m_dPhi; - qint32 m_fCal; - qint32 m_udpPort; - qint32 m_astroFont; - qint32 m_mult570; - - double m_fAdd; - double m_cal570; - - bool m_xpolx; - bool m_network; - bool m_fs96000; - bool m_xpol; - bool m_IQswap; - bool m_restartSoundIn; - bool m_restartSoundOut; - bool m_10db; - bool m_initIQplus; - - QString m_myCall; - QString m_myGrid; - QString m_saveDir; - QString m_azelDir; - QString m_dxccPfx; - QString m_colors; - - QColor m_colorBackground; - -public slots: - void accept(); - -private slots: - void on_soundCardRadioButton_toggled(bool checked); - void on_cbXpol_stateChanged(int arg1); - void on_cal570SpinBox_valueChanged(double ppm); - void on_mult570SpinBox_valueChanged(int mult); - void on_sbBackgroundRed_valueChanged(int arg1); - void on_sbBackgroundGreen_valueChanged(int arg1); - void on_sbBackgroundBlue_valueChanged(int arg1); - void updateColorLabels(void); - void on_sbRed0_valueChanged(int arg1); - void on_sbGreen0_valueChanged(int arg1); - void on_sbBlue0_valueChanged(int arg1); - void on_sbRed1_valueChanged(int arg1); - void on_sbGreen1_valueChanged(int arg1); - void on_sbBlue1_valueChanged(int arg1); - void on_sbRed2_valueChanged(int arg1); - void on_sbGreen2_valueChanged(int arg1); - void on_sbBlue2_valueChanged(int arg1); - void on_sbRed3_valueChanged(int arg1); - void on_sbGreen3_valueChanged(int arg1); - void on_sbBlue3_valueChanged(int arg1); - void on_pushButton_5_clicked(); - -private: - int r,g,b,r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3; - Ui::DialogSndCard ui; -}; - -#endif // DEVSETUP_H +#ifndef DEVSETUP_H +#define DEVSETUP_H + +#include +#include "ui_devsetup.h" + +class DevSetup : public QDialog +{ + Q_OBJECT +public: + DevSetup(QWidget *parent=0); + ~DevSetup(); + + void initDlg(); + qint32 m_idInt; + qint32 m_pttPort; + qint32 m_nDevIn; + qint32 m_nDevOut; + qint32 m_inDevList[100]; + qint32 m_outDevList[100]; + qint32 m_paInDevice; + qint32 m_paOutDevice; + qint32 m_timeout; + qint32 m_dPhi; + qint32 m_fCal; + qint32 m_udpPort; + qint32 m_astroFont; + qint32 m_mult570; + + double m_fAdd; + double m_cal570; + + bool m_xpolx; + bool m_network; + bool m_fs96000; + bool m_xpol; + bool m_IQswap; + bool m_restartSoundIn; + bool m_restartSoundOut; + bool m_10db; + bool m_initIQplus; + + QString m_myCall; + QString m_myGrid; + QString m_saveDir; + QString m_azelDir; + QString m_dxccPfx; + QString m_colors; + + QColor m_colorBackground; + +public slots: + void accept(); + +private slots: + void on_soundCardRadioButton_toggled(bool checked); + void on_cbXpol_stateChanged(int arg1); + void on_cal570SpinBox_valueChanged(double ppm); + void on_mult570SpinBox_valueChanged(int mult); + void on_sbBackgroundRed_valueChanged(int arg1); + void on_sbBackgroundGreen_valueChanged(int arg1); + void on_sbBackgroundBlue_valueChanged(int arg1); + void updateColorLabels(void); + void on_sbRed0_valueChanged(int arg1); + void on_sbGreen0_valueChanged(int arg1); + void on_sbBlue0_valueChanged(int arg1); + void on_sbRed1_valueChanged(int arg1); + void on_sbGreen1_valueChanged(int arg1); + void on_sbBlue1_valueChanged(int arg1); + void on_sbRed2_valueChanged(int arg1); + void on_sbGreen2_valueChanged(int arg1); + void on_sbBlue2_valueChanged(int arg1); + void on_sbRed3_valueChanged(int arg1); + void on_sbGreen3_valueChanged(int arg1); + void on_sbBlue3_valueChanged(int arg1); + void on_pushButton_5_clicked(); + +private: + int r,g,b,r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3; + Ui::DialogSndCard ui; +}; + +#endif // DEVSETUP_H diff --git a/displaytext.cpp b/displaytext.cpp index 4f2ac0b6d..4d7286d3b 100644 --- a/displaytext.cpp +++ b/displaytext.cpp @@ -1,15 +1,15 @@ -#include "displaytext.h" -#include -#include - -DisplayText::DisplayText(QWidget *parent) : - QTextBrowser(parent) -{ -} - -void DisplayText::mouseDoubleClickEvent(QMouseEvent *e) -{ - bool ctrl = (e->modifiers() & 0x4000000); - emit(selectCallsign(ctrl)); - QTextBrowser::mouseDoubleClickEvent(e); -} +#include "displaytext.h" +#include +#include + +DisplayText::DisplayText(QWidget *parent) : + QTextBrowser(parent) +{ +} + +void DisplayText::mouseDoubleClickEvent(QMouseEvent *e) +{ + bool ctrl = (e->modifiers() & 0x4000000); + emit(selectCallsign(ctrl)); + QTextBrowser::mouseDoubleClickEvent(e); +} diff --git a/displaytext.h b/displaytext.h index 7362ad196..4553d53fb 100644 --- a/displaytext.h +++ b/displaytext.h @@ -1,22 +1,22 @@ -#ifndef DISPLAYTEXT_H -#define DISPLAYTEXT_H - -#include - -class DisplayText : public QTextBrowser -{ - Q_OBJECT -public: - explicit DisplayText(QWidget *parent = 0); - -signals: - void selectCallsign(bool ctrl); - -public slots: - -protected: - void mouseDoubleClickEvent(QMouseEvent *e); - -}; - -#endif // DISPLAYTEXT_H +#ifndef DISPLAYTEXT_H +#define DISPLAYTEXT_H + +#include + +class DisplayText : public QTextBrowser +{ + Q_OBJECT +public: + explicit DisplayText(QWidget *parent = 0); + +signals: + void selectCallsign(bool ctrl); + +public slots: + +protected: + void mouseDoubleClickEvent(QMouseEvent *e); + +}; + +#endif // DISPLAYTEXT_H diff --git a/ffft.f b/ffft.f index d475875c1..9c3c091a7 100644 --- a/ffft.f +++ b/ffft.f @@ -1,69 +1,69 @@ - subroutine ffft(d,npts,isign,ireal) - -C Fourier transform of length npts=2**k, performed in place. -C Input data in array d, treated as complex if ireal=0, and as real if ireal=1. -C In either case the transform values are returned in array d, treated as -C complex. The DC term is d(1), and d(npts/2+1) is the term at the Nyquist -C frequency. The basic algorithm is the same as Norm Brenner's FOUR1, and -C uses radix-2 transforms. - -C J. H. Taylor, Princeton University. - - complex d(npts),t,w,wstep,tt,uu - data pi/3.14159265359/ - -C Shuffle the data to bit-reversed order. - - imax=npts/(ireal+1) - irev=1 - do 5 i=1,imax - if(i.ge.irev) go to 2 - t=d(i) - d(i)=d(irev) - d(irev)=t -2 mmax=imax/2 -3 if(irev.le.mmax) go to 5 - irev=irev-mmax - mmax=mmax/2 - if(mmax.ge.1) go to 3 -5 irev=irev+mmax - -C The radix-2 transform begins here. - - api=isign*pi/2. - mmax=1 -6 istep=2*mmax - wstep=cmplx(-2.*sin(api/mmax)**2,sin(2.*api/mmax)) - w=1. - do 9 m=1,mmax - -C This in the inner-most loop -- optimization here is important! - do 8 i=m,imax,istep - t=w*d(i+mmax) - d(i+mmax)=d(i)-t -8 d(i)=d(i)+t - -9 w=w*(1.+wstep) - mmax=istep - if(mmax.lt.imax) go to 6 - - if(ireal.eq.0) return - -C Now complete the last stage of a doubled-up real transform. - - jmax=imax/2 + 1 - wstep=cmplx(-2.*sin(isign*pi/npts)**2,sin(isign*pi/imax)) - w=1.0 - d(imax+1)=d(1) - - do 10 j=1,jmax - uu=cmplx(real(d(j))+real(d(2+imax-j)),aimag(d(j)) - - + aimag(d(2+imax-j))) - tt=w*cmplx(aimag(d(j))+aimag(d(2+imax-j)),-real(d(j)) + - + real(d(2+imax-j))) - d(j)=uu+tt - d(2+imax-j)=conjg(uu-tt) -10 w=w*(1.+wstep) - - return - end + subroutine ffft(d,npts,isign,ireal) + +C Fourier transform of length npts=2**k, performed in place. +C Input data in array d, treated as complex if ireal=0, and as real if ireal=1. +C In either case the transform values are returned in array d, treated as +C complex. The DC term is d(1), and d(npts/2+1) is the term at the Nyquist +C frequency. The basic algorithm is the same as Norm Brenner's FOUR1, and +C uses radix-2 transforms. + +C J. H. Taylor, Princeton University. + + complex d(npts),t,w,wstep,tt,uu + data pi/3.14159265359/ + +C Shuffle the data to bit-reversed order. + + imax=npts/(ireal+1) + irev=1 + do 5 i=1,imax + if(i.ge.irev) go to 2 + t=d(i) + d(i)=d(irev) + d(irev)=t +2 mmax=imax/2 +3 if(irev.le.mmax) go to 5 + irev=irev-mmax + mmax=mmax/2 + if(mmax.ge.1) go to 3 +5 irev=irev+mmax + +C The radix-2 transform begins here. + + api=isign*pi/2. + mmax=1 +6 istep=2*mmax + wstep=cmplx(-2.*sin(api/mmax)**2,sin(2.*api/mmax)) + w=1. + do 9 m=1,mmax + +C This in the inner-most loop -- optimization here is important! + do 8 i=m,imax,istep + t=w*d(i+mmax) + d(i+mmax)=d(i)-t +8 d(i)=d(i)+t + +9 w=w*(1.+wstep) + mmax=istep + if(mmax.lt.imax) go to 6 + + if(ireal.eq.0) return + +C Now complete the last stage of a doubled-up real transform. + + jmax=imax/2 + 1 + wstep=cmplx(-2.*sin(isign*pi/npts)**2,sin(isign*pi/imax)) + w=1.0 + d(imax+1)=d(1) + + do 10 j=1,jmax + uu=cmplx(real(d(j))+real(d(2+imax-j)),aimag(d(j)) - + + aimag(d(2+imax-j))) + tt=w*cmplx(aimag(d(j))+aimag(d(2+imax-j)),-real(d(j)) + + + real(d(2+imax-j))) + d(j)=uu+tt + d(2+imax-j)=conjg(uu-tt) +10 w=w*(1.+wstep) + + return + end diff --git a/fftw3.f b/fftw3.f index 90748b2fd..3410184ca 100644 --- a/fftw3.f +++ b/fftw3.f @@ -1,64 +1,64 @@ - INTEGER FFTW_R2HC - PARAMETER (FFTW_R2HC=0) - INTEGER FFTW_HC2R - PARAMETER (FFTW_HC2R=1) - INTEGER FFTW_DHT - PARAMETER (FFTW_DHT=2) - INTEGER FFTW_REDFT00 - PARAMETER (FFTW_REDFT00=3) - INTEGER FFTW_REDFT01 - PARAMETER (FFTW_REDFT01=4) - INTEGER FFTW_REDFT10 - PARAMETER (FFTW_REDFT10=5) - INTEGER FFTW_REDFT11 - PARAMETER (FFTW_REDFT11=6) - INTEGER FFTW_RODFT00 - PARAMETER (FFTW_RODFT00=7) - INTEGER FFTW_RODFT01 - PARAMETER (FFTW_RODFT01=8) - INTEGER FFTW_RODFT10 - PARAMETER (FFTW_RODFT10=9) - INTEGER FFTW_RODFT11 - PARAMETER (FFTW_RODFT11=10) - INTEGER FFTW_FORWARD - PARAMETER (FFTW_FORWARD=-1) - INTEGER FFTW_BACKWARD - PARAMETER (FFTW_BACKWARD=+1) - INTEGER FFTW_MEASURE - PARAMETER (FFTW_MEASURE=0) - INTEGER FFTW_DESTROY_INPUT - PARAMETER (FFTW_DESTROY_INPUT=1) - INTEGER FFTW_UNALIGNED - PARAMETER (FFTW_UNALIGNED=2) - INTEGER FFTW_CONSERVE_MEMORY - PARAMETER (FFTW_CONSERVE_MEMORY=4) - INTEGER FFTW_EXHAUSTIVE - PARAMETER (FFTW_EXHAUSTIVE=8) - INTEGER FFTW_PRESERVE_INPUT - PARAMETER (FFTW_PRESERVE_INPUT=16) - INTEGER FFTW_PATIENT - PARAMETER (FFTW_PATIENT=32) - INTEGER FFTW_ESTIMATE - PARAMETER (FFTW_ESTIMATE=64) - INTEGER FFTW_ESTIMATE_PATIENT - PARAMETER (FFTW_ESTIMATE_PATIENT=128) - INTEGER FFTW_BELIEVE_PCOST - PARAMETER (FFTW_BELIEVE_PCOST=256) - INTEGER FFTW_DFT_R2HC_ICKY - PARAMETER (FFTW_DFT_R2HC_ICKY=512) - INTEGER FFTW_NONTHREADED_ICKY - PARAMETER (FFTW_NONTHREADED_ICKY=1024) - INTEGER FFTW_NO_BUFFERING - PARAMETER (FFTW_NO_BUFFERING=2048) - INTEGER FFTW_NO_INDIRECT_OP - PARAMETER (FFTW_NO_INDIRECT_OP=4096) - INTEGER FFTW_ALLOW_LARGE_GENERIC - PARAMETER (FFTW_ALLOW_LARGE_GENERIC=8192) - INTEGER FFTW_NO_RANK_SPLITS - PARAMETER (FFTW_NO_RANK_SPLITS=16384) - INTEGER FFTW_NO_VRANK_SPLITS - PARAMETER (FFTW_NO_VRANK_SPLITS=32768) - INTEGER FFTW_NO_VRECURSE - PARAMETER (FFTW_NO_VRECURSE=65536) - INTEGER FFTW_NO_SIMD - PARAMETER (FFTW_NO_SIMD=131072) + INTEGER FFTW_R2HC + PARAMETER (FFTW_R2HC=0) + INTEGER FFTW_HC2R + PARAMETER (FFTW_HC2R=1) + INTEGER FFTW_DHT + PARAMETER (FFTW_DHT=2) + INTEGER FFTW_REDFT00 + PARAMETER (FFTW_REDFT00=3) + INTEGER FFTW_REDFT01 + PARAMETER (FFTW_REDFT01=4) + INTEGER FFTW_REDFT10 + PARAMETER (FFTW_REDFT10=5) + INTEGER FFTW_REDFT11 + PARAMETER (FFTW_REDFT11=6) + INTEGER FFTW_RODFT00 + PARAMETER (FFTW_RODFT00=7) + INTEGER FFTW_RODFT01 + PARAMETER (FFTW_RODFT01=8) + INTEGER FFTW_RODFT10 + PARAMETER (FFTW_RODFT10=9) + INTEGER FFTW_RODFT11 + PARAMETER (FFTW_RODFT11=10) + INTEGER FFTW_FORWARD + PARAMETER (FFTW_FORWARD=-1) + INTEGER FFTW_BACKWARD + PARAMETER (FFTW_BACKWARD=+1) + INTEGER FFTW_MEASURE + PARAMETER (FFTW_MEASURE=0) + INTEGER FFTW_DESTROY_INPUT + PARAMETER (FFTW_DESTROY_INPUT=1) + INTEGER FFTW_UNALIGNED + PARAMETER (FFTW_UNALIGNED=2) + INTEGER FFTW_CONSERVE_MEMORY + PARAMETER (FFTW_CONSERVE_MEMORY=4) + INTEGER FFTW_EXHAUSTIVE + PARAMETER (FFTW_EXHAUSTIVE=8) + INTEGER FFTW_PRESERVE_INPUT + PARAMETER (FFTW_PRESERVE_INPUT=16) + INTEGER FFTW_PATIENT + PARAMETER (FFTW_PATIENT=32) + INTEGER FFTW_ESTIMATE + PARAMETER (FFTW_ESTIMATE=64) + INTEGER FFTW_ESTIMATE_PATIENT + PARAMETER (FFTW_ESTIMATE_PATIENT=128) + INTEGER FFTW_BELIEVE_PCOST + PARAMETER (FFTW_BELIEVE_PCOST=256) + INTEGER FFTW_DFT_R2HC_ICKY + PARAMETER (FFTW_DFT_R2HC_ICKY=512) + INTEGER FFTW_NONTHREADED_ICKY + PARAMETER (FFTW_NONTHREADED_ICKY=1024) + INTEGER FFTW_NO_BUFFERING + PARAMETER (FFTW_NO_BUFFERING=2048) + INTEGER FFTW_NO_INDIRECT_OP + PARAMETER (FFTW_NO_INDIRECT_OP=4096) + INTEGER FFTW_ALLOW_LARGE_GENERIC + PARAMETER (FFTW_ALLOW_LARGE_GENERIC=8192) + INTEGER FFTW_NO_RANK_SPLITS + PARAMETER (FFTW_NO_RANK_SPLITS=16384) + INTEGER FFTW_NO_VRANK_SPLITS + PARAMETER (FFTW_NO_VRANK_SPLITS=32768) + INTEGER FFTW_NO_VRECURSE + PARAMETER (FFTW_NO_VRECURSE=65536) + INTEGER FFTW_NO_SIMD + PARAMETER (FFTW_NO_SIMD=131072) diff --git a/getdev.cpp b/getdev.cpp index 698fd9d60..751c87fe8 100644 --- a/getdev.cpp +++ b/getdev.cpp @@ -1,259 +1,259 @@ -#include -#define MAXDEVICES 100 -#include -#include -#include - -//------------------------------------------------------- pa_get_device_info -int pa_get_device_info (int n, - void *pa_device_name, - void *pa_device_hostapi, - double *pa_device_max_speed, - double *pa_device_min_speed, - int *pa_device_max_bytes, - int *pa_device_min_bytes, - int *pa_device_max_channels, - int *pa_device_min_channels ) -{ - - (void) n ; - (void) pa_device_name; - (void) pa_device_hostapi; - (void) pa_device_max_speed; - (void) pa_device_min_speed; - (void) pa_device_max_bytes; - (void) pa_device_min_bytes; - (void) pa_device_max_channels; - (void) pa_device_min_channels; - const PaDeviceInfo *deviceInfo; - PaError pa_err; - PaStreamParameters inputParameters; - int i,j, speed_warning; - int minBytes, maxBytes; - double maxStandardSampleRate; - double minStandardSampleRate; - int minInputChannels; - int maxInputChannels; - -// negative terminated list - static double standardSampleRates[] = {8000.0, 9600.0, - 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, - 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1}; -// ******************************************************* - - - *pa_device_max_speed=0; - *pa_device_min_speed=0; - *pa_device_max_bytes=0; - *pa_device_min_bytes=0; - *pa_device_max_channels=0; - *pa_device_min_channels=0; - minInputChannels=0; - if(n >= Pa_GetDeviceCount() ) return -1; - deviceInfo = Pa_GetDeviceInfo(n); - if (deviceInfo->maxInputChannels==0) return -1; - sprintf((char*)(pa_device_name),"%s",deviceInfo->name); - sprintf((char*)(pa_device_hostapi),"%s", - Pa_GetHostApiInfo( deviceInfo->hostApi )->name); - speed_warning=0; - -// bypass bug in Juli@ ASIO driver: -// this driver hangs after a Pa_IsFormatSupported call - i = strncmp(deviceInfo->name, "ASIO 2.0 - ESI Juli@", 19); - if (i == 0) { - minStandardSampleRate=44100; - maxStandardSampleRate=192000; - minBytes=1; - maxBytes=4; - maxInputChannels= deviceInfo->maxInputChannels; - minInputChannels= 1; - goto end_pa_get_device_info; - } - -// Investigate device capabilities. -// Check min and max samplerates with 16 bit data. - maxStandardSampleRate=0; - minStandardSampleRate=0; - inputParameters.device = n; - inputParameters.channelCount = deviceInfo->maxInputChannels; - inputParameters.sampleFormat = paInt16; - inputParameters.suggestedLatency = 0; - inputParameters.hostApiSpecificStreamInfo = NULL; - -// ************************************************************************ -//filter for portaudio Windows hostapi's with non experts. -//only allow ASIO or WASAPI or WDM-KS - i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, "ASIO", 4); - if (i==0 ) goto end_filter_hostapi; - i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, - "Windows WASAPI", 14); - if (i==0 ) goto end_filter_hostapi; - i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, - "Windows WDM-KS", 14); - if (i==0 ) goto end_filter_hostapi; - speed_warning=1; -end_filter_hostapi:; - -// ************************************************************************ - i=0; - while(standardSampleRates[i] > 0 && minStandardSampleRate==0) { - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - standardSampleRates[i] ); - if(pa_err == paDeviceUnavailable) return -1; - if(pa_err == paInvalidDevice) return -1; - if(pa_err == paFormatIsSupported ) { - minStandardSampleRate=standardSampleRates[i]; - } - i++; - } - if(minStandardSampleRate == 0) return -1; - j=i; - while(standardSampleRates[i] > 0 ) i++; - i--; - - while(i >= j && maxStandardSampleRate==0) { - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - standardSampleRates[i] ); - if(pa_err == paDeviceUnavailable) return -1; - if(pa_err == paInvalidDevice) return -1; - if( pa_err == paFormatIsSupported ) { - maxStandardSampleRate=standardSampleRates[i]; - } - i--; - } - -// check if min SampleRate = max SampleRate - if(maxStandardSampleRate==0 && (minStandardSampleRate != 0)) { - maxStandardSampleRate= minStandardSampleRate; - } - -// check min and max bytes - minBytes=2; - maxBytes=2; - inputParameters.sampleFormat = paUInt8; - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - maxStandardSampleRate ); - if( pa_err == paFormatIsSupported ) { - minBytes=1; - } - inputParameters.sampleFormat = paInt32; - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - maxStandardSampleRate ); - if( pa_err == paFormatIsSupported ) { - maxBytes=4; - } - -// check min channel count - maxInputChannels= deviceInfo->maxInputChannels; - inputParameters.channelCount = 1; - inputParameters.sampleFormat = paInt16; - pa_err=paFormatIsSupported+32000; - while(pa_err != paFormatIsSupported && - ( inputParameters.channelCount < (maxInputChannels+1)) ) { - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - maxStandardSampleRate ); - inputParameters.channelCount++; - } - if( pa_err == paFormatIsSupported ) { - minInputChannels=inputParameters.channelCount-1; - } else { - return -1; - } - -end_pa_get_device_info:; - - *pa_device_max_speed=maxStandardSampleRate; - *pa_device_min_speed=minStandardSampleRate; - *pa_device_max_bytes=maxBytes; - *pa_device_min_bytes=minBytes; - *pa_device_max_channels= maxInputChannels; - *pa_device_min_channels= minInputChannels; - - return speed_warning; -} - - -void paInputDevice(int id, char* hostAPI_DeviceName, int* minChan, - int* maxChan, int* minSpeed, int* maxSpeed) -{ - int i; - char pa_device_name[128]; - char pa_device_hostapi[128]; - double pa_device_max_speed; - double pa_device_min_speed; - int pa_device_max_bytes; - int pa_device_min_bytes; - int pa_device_max_channels; - int pa_device_min_channels; - char p2[50]; - char *p,*p1; - static int iret, valid_dev_cnt; - - iret=pa_get_device_info (id, - &pa_device_name, - &pa_device_hostapi, - &pa_device_max_speed, - &pa_device_min_speed, - &pa_device_max_bytes, - &pa_device_min_bytes, - &pa_device_max_channels, - &pa_device_min_channels); - - if (iret >= 0 ) { - valid_dev_cnt++; - - p1=(char*)""; - p=strstr(pa_device_hostapi,"MME"); - if(p!=NULL) p1=(char*)"MME"; - p=strstr(pa_device_hostapi,"Direct"); - if(p!=NULL) p1=(char*)"DirectX"; - p=strstr(pa_device_hostapi,"WASAPI"); - if(p!=NULL) p1=(char*)"WASAPI"; - p=strstr(pa_device_hostapi,"ASIO"); - if(p!=NULL) p1=(char*)"ASIO"; - p=strstr(pa_device_hostapi,"WDM-KS"); - if(p!=NULL) p1=(char*)"WDM-KS"; - - sprintf(p2,"%-8s %-39s",p1,pa_device_name); - for(i=0; i<50; i++) { - hostAPI_DeviceName[i]=p2[i]; - if(p2[i]==0) break; - } - *minChan=pa_device_min_channels; - *maxChan=pa_device_max_channels; - *minSpeed=(int)pa_device_min_speed; - *maxSpeed=(int)pa_device_max_speed; - } else { - for(i=0; i<50; i++) { - hostAPI_DeviceName[i]=0; - } - *minChan=0; - *maxChan=0; - *minSpeed=0; - *maxSpeed=0; - } -} - -void getDev(int* numDevices0, char hostAPI_DeviceName[][50], - int minChan[], int maxChan[], - int minSpeed[], int maxSpeed[]) -{ - int i,id,numDevices; - int minch,maxch,minsp,maxsp; - char apidev[256]; - - numDevices=Pa_GetDeviceCount(); - *numDevices0=numDevices; - - for(id=0; id +#define MAXDEVICES 100 +#include +#include +#include + +//------------------------------------------------------- pa_get_device_info +int pa_get_device_info (int n, + void *pa_device_name, + void *pa_device_hostapi, + double *pa_device_max_speed, + double *pa_device_min_speed, + int *pa_device_max_bytes, + int *pa_device_min_bytes, + int *pa_device_max_channels, + int *pa_device_min_channels ) +{ + + (void) n ; + (void) pa_device_name; + (void) pa_device_hostapi; + (void) pa_device_max_speed; + (void) pa_device_min_speed; + (void) pa_device_max_bytes; + (void) pa_device_min_bytes; + (void) pa_device_max_channels; + (void) pa_device_min_channels; + const PaDeviceInfo *deviceInfo; + PaError pa_err; + PaStreamParameters inputParameters; + int i,j, speed_warning; + int minBytes, maxBytes; + double maxStandardSampleRate; + double minStandardSampleRate; + int minInputChannels; + int maxInputChannels; + +// negative terminated list + static double standardSampleRates[] = {8000.0, 9600.0, + 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, + 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1}; +// ******************************************************* + + + *pa_device_max_speed=0; + *pa_device_min_speed=0; + *pa_device_max_bytes=0; + *pa_device_min_bytes=0; + *pa_device_max_channels=0; + *pa_device_min_channels=0; + minInputChannels=0; + if(n >= Pa_GetDeviceCount() ) return -1; + deviceInfo = Pa_GetDeviceInfo(n); + if (deviceInfo->maxInputChannels==0) return -1; + sprintf((char*)(pa_device_name),"%s",deviceInfo->name); + sprintf((char*)(pa_device_hostapi),"%s", + Pa_GetHostApiInfo( deviceInfo->hostApi )->name); + speed_warning=0; + +// bypass bug in Juli@ ASIO driver: +// this driver hangs after a Pa_IsFormatSupported call + i = strncmp(deviceInfo->name, "ASIO 2.0 - ESI Juli@", 19); + if (i == 0) { + minStandardSampleRate=44100; + maxStandardSampleRate=192000; + minBytes=1; + maxBytes=4; + maxInputChannels= deviceInfo->maxInputChannels; + minInputChannels= 1; + goto end_pa_get_device_info; + } + +// Investigate device capabilities. +// Check min and max samplerates with 16 bit data. + maxStandardSampleRate=0; + minStandardSampleRate=0; + inputParameters.device = n; + inputParameters.channelCount = deviceInfo->maxInputChannels; + inputParameters.sampleFormat = paInt16; + inputParameters.suggestedLatency = 0; + inputParameters.hostApiSpecificStreamInfo = NULL; + +// ************************************************************************ +//filter for portaudio Windows hostapi's with non experts. +//only allow ASIO or WASAPI or WDM-KS + i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, "ASIO", 4); + if (i==0 ) goto end_filter_hostapi; + i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, + "Windows WASAPI", 14); + if (i==0 ) goto end_filter_hostapi; + i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, + "Windows WDM-KS", 14); + if (i==0 ) goto end_filter_hostapi; + speed_warning=1; +end_filter_hostapi:; + +// ************************************************************************ + i=0; + while(standardSampleRates[i] > 0 && minStandardSampleRate==0) { + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + standardSampleRates[i] ); + if(pa_err == paDeviceUnavailable) return -1; + if(pa_err == paInvalidDevice) return -1; + if(pa_err == paFormatIsSupported ) { + minStandardSampleRate=standardSampleRates[i]; + } + i++; + } + if(minStandardSampleRate == 0) return -1; + j=i; + while(standardSampleRates[i] > 0 ) i++; + i--; + + while(i >= j && maxStandardSampleRate==0) { + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + standardSampleRates[i] ); + if(pa_err == paDeviceUnavailable) return -1; + if(pa_err == paInvalidDevice) return -1; + if( pa_err == paFormatIsSupported ) { + maxStandardSampleRate=standardSampleRates[i]; + } + i--; + } + +// check if min SampleRate = max SampleRate + if(maxStandardSampleRate==0 && (minStandardSampleRate != 0)) { + maxStandardSampleRate= minStandardSampleRate; + } + +// check min and max bytes + minBytes=2; + maxBytes=2; + inputParameters.sampleFormat = paUInt8; + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + maxStandardSampleRate ); + if( pa_err == paFormatIsSupported ) { + minBytes=1; + } + inputParameters.sampleFormat = paInt32; + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + maxStandardSampleRate ); + if( pa_err == paFormatIsSupported ) { + maxBytes=4; + } + +// check min channel count + maxInputChannels= deviceInfo->maxInputChannels; + inputParameters.channelCount = 1; + inputParameters.sampleFormat = paInt16; + pa_err=paFormatIsSupported+32000; + while(pa_err != paFormatIsSupported && + ( inputParameters.channelCount < (maxInputChannels+1)) ) { + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + maxStandardSampleRate ); + inputParameters.channelCount++; + } + if( pa_err == paFormatIsSupported ) { + minInputChannels=inputParameters.channelCount-1; + } else { + return -1; + } + +end_pa_get_device_info:; + + *pa_device_max_speed=maxStandardSampleRate; + *pa_device_min_speed=minStandardSampleRate; + *pa_device_max_bytes=maxBytes; + *pa_device_min_bytes=minBytes; + *pa_device_max_channels= maxInputChannels; + *pa_device_min_channels= minInputChannels; + + return speed_warning; +} + + +void paInputDevice(int id, char* hostAPI_DeviceName, int* minChan, + int* maxChan, int* minSpeed, int* maxSpeed) +{ + int i; + char pa_device_name[128]; + char pa_device_hostapi[128]; + double pa_device_max_speed; + double pa_device_min_speed; + int pa_device_max_bytes; + int pa_device_min_bytes; + int pa_device_max_channels; + int pa_device_min_channels; + char p2[50]; + char *p,*p1; + static int iret, valid_dev_cnt; + + iret=pa_get_device_info (id, + &pa_device_name, + &pa_device_hostapi, + &pa_device_max_speed, + &pa_device_min_speed, + &pa_device_max_bytes, + &pa_device_min_bytes, + &pa_device_max_channels, + &pa_device_min_channels); + + if (iret >= 0 ) { + valid_dev_cnt++; + + p1=(char*)""; + p=strstr(pa_device_hostapi,"MME"); + if(p!=NULL) p1=(char*)"MME"; + p=strstr(pa_device_hostapi,"Direct"); + if(p!=NULL) p1=(char*)"DirectX"; + p=strstr(pa_device_hostapi,"WASAPI"); + if(p!=NULL) p1=(char*)"WASAPI"; + p=strstr(pa_device_hostapi,"ASIO"); + if(p!=NULL) p1=(char*)"ASIO"; + p=strstr(pa_device_hostapi,"WDM-KS"); + if(p!=NULL) p1=(char*)"WDM-KS"; + + sprintf(p2,"%-8s %-39s",p1,pa_device_name); + for(i=0; i<50; i++) { + hostAPI_DeviceName[i]=p2[i]; + if(p2[i]==0) break; + } + *minChan=pa_device_min_channels; + *maxChan=pa_device_max_channels; + *minSpeed=(int)pa_device_min_speed; + *maxSpeed=(int)pa_device_max_speed; + } else { + for(i=0; i<50; i++) { + hostAPI_DeviceName[i]=0; + } + *minChan=0; + *maxChan=0; + *minSpeed=0; + *maxSpeed=0; + } +} + +void getDev(int* numDevices0, char hostAPI_DeviceName[][50], + int minChan[], int maxChan[], + int minSpeed[], int maxSpeed[]) +{ + int i,id,numDevices; + int minch,maxch,minsp,maxsp; + char apidev[256]; + + numDevices=Pa_GetDeviceCount(); + *numDevices0=numDevices; + + for(id=0; id -#include -#include -#include - -extern qint16 id[4*60*96000]; - -void getfile(QString fname, bool xpol, int dbDgrd) -{ - int npts=2*52*96000; - if(xpol) npts=2*npts; - -// Degrade S/N by dbDgrd dB -- for tests only!! - float dgrd=0.0; - if(dbDgrd<0) dgrd = 23.0*sqrt(pow(10.0,-0.1*(double)dbDgrd) - 1.0); - float fac=23.0/sqrt(dgrd*dgrd + 23.0*23.0); - - memset(id,0,2*npts); - char name[80]; - strcpy(name,fname.toAscii()); - FILE* fp=fopen(name,"rb"); - - if(fp != NULL) { - fread(&datcom_.fcenter,sizeof(datcom_.fcenter),1,fp); - fread(id,2,npts,fp); - int j=0; - - if(dbDgrd<0) { - for(int i=0; i0) datcom_.nutc=100*fname.mid(i0-4,2).toInt() + - fname.mid(i0-2,2).toInt(); - } -} - -void savetf2(QString fname, bool xpol) -{ - int npts=2*52*96000; - if(xpol) npts=2*npts; - - qint16* buf=(qint16*)malloc(2*npts); - char name[80]; - strcpy(name,fname.toAscii()); - FILE* fp=fopen(name,"wb"); - - if(fp != NULL) { - fwrite(&datcom_.fcenter,sizeof(datcom_.fcenter),1,fp); - int j=0; - for(int i=0; i= 1.0 || rsq == 0.0); - fac = sqrt(-2.0*log(rsq)/rsq); - gset = v1*fac; - iset++; - return v2*fac; -} +#include "getfile.h" +#include +#include +#include +#include + +extern qint16 id[4*60*96000]; + +void getfile(QString fname, bool xpol, int dbDgrd) +{ + int npts=2*52*96000; + if(xpol) npts=2*npts; + +// Degrade S/N by dbDgrd dB -- for tests only!! + float dgrd=0.0; + if(dbDgrd<0) dgrd = 23.0*sqrt(pow(10.0,-0.1*(double)dbDgrd) - 1.0); + float fac=23.0/sqrt(dgrd*dgrd + 23.0*23.0); + + memset(id,0,2*npts); + char name[80]; + strcpy(name,fname.toAscii()); + FILE* fp=fopen(name,"rb"); + + if(fp != NULL) { + fread(&datcom_.fcenter,sizeof(datcom_.fcenter),1,fp); + fread(id,2,npts,fp); + int j=0; + + if(dbDgrd<0) { + for(int i=0; i0) datcom_.nutc=100*fname.mid(i0-4,2).toInt() + + fname.mid(i0-2,2).toInt(); + } +} + +void savetf2(QString fname, bool xpol) +{ + int npts=2*52*96000; + if(xpol) npts=2*npts; + + qint16* buf=(qint16*)malloc(2*npts); + char name[80]; + strcpy(name,fname.toAscii()); + FILE* fp=fopen(name,"wb"); + + if(fp != NULL) { + fwrite(&datcom_.fcenter,sizeof(datcom_.fcenter),1,fp); + int j=0; + for(int i=0; i= 1.0 || rsq == 0.0); + fac = sqrt(-2.0*log(rsq)/rsq); + gset = v1*fac; + iset++; + return v2*fac; +} diff --git a/getfile.h b/getfile.h index 11912a019..796c31e5c 100644 --- a/getfile.h +++ b/getfile.h @@ -1,12 +1,12 @@ -#ifndef GETFILE_H -#define GETFILE_H -#include -#include -#include -#include "commons.h" - -void getfile(QString fname, bool xpol, int dbDgrd); -void savetf2(QString fname, bool xpol); -float gran(); - -#endif // GETFILE_H +#ifndef GETFILE_H +#define GETFILE_H +#include +#include +#include +#include "commons.h" + +void getfile(QString fname, bool xpol, int dbDgrd); +void savetf2(QString fname, bool xpol); +float gran(); + +#endif // GETFILE_H diff --git a/killbyname.cpp b/killbyname.cpp index 51e8c80d6..e615f2347 100644 --- a/killbyname.cpp +++ b/killbyname.cpp @@ -1,282 +1,282 @@ -#include -#include -#include - -int killbyname(const char *szToTerminate) -// Created: 6/23/2000 (Ravi Kochhar) -// Last modified: 3/10/2002 (RK) -// Please report any problems or bugs to kochhar@physiology.wisc.edu -// The latest version of this routine can be found at: -// http://www.neurophys.wisc.edu/ravi/software/killproc/ -// Terminate the process "szToTerminate" if it is currently running -// This works for Win/95/98/ME and also Win/NT/2000/XP -// The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE" -// will both work (for szToTerminate) -// Return codes are as follows: -// 0 = Process was successfully terminated -// 602 = Unable to terminate process for some other reason -// 603 = Process was not currently running -// 604 = No permission to terminate process -// 605 = Unable to load PSAPI.DLL -// 606 = Unable to identify system type -// 607 = Unsupported OS -// 632 = Invalid process name -// 700 = Unable to get procedure address from PSAPI.DLL -// 701 = Unable to get process list, EnumProcesses failed -// 702 = Unable to load KERNEL32.DLL -// 703 = Unable to get procedure address from KERNEL32.DLL -// 704 = CreateToolhelp32Snapshot failed - -{ - BOOL bResult,bResultm; - DWORD aiPID[1000],iCb=1000,iNumProc; //,iV2000=0; - DWORD iCbneeded,i,iFound=0; - char szName[MAX_PATH],szToTermUpper[MAX_PATH]; - HANDLE hProc,hSnapShot,hSnapShotm; - OSVERSIONINFO osvi; - HINSTANCE hInstLib; - int iLen,iLenP,indx; - HMODULE hMod; - PROCESSENTRY32 procentry; - MODULEENTRY32 modentry; - - // Transfer Process name into "szToTermUpper" and convert to upper case - iLenP=strlen(szToTerminate); - if(iLenP<1 || iLenP>MAX_PATH) return 632; - for(indx=0;indx +#include +#include + +int killbyname(const char *szToTerminate) +// Created: 6/23/2000 (Ravi Kochhar) +// Last modified: 3/10/2002 (RK) +// Please report any problems or bugs to kochhar@physiology.wisc.edu +// The latest version of this routine can be found at: +// http://www.neurophys.wisc.edu/ravi/software/killproc/ +// Terminate the process "szToTerminate" if it is currently running +// This works for Win/95/98/ME and also Win/NT/2000/XP +// The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE" +// will both work (for szToTerminate) +// Return codes are as follows: +// 0 = Process was successfully terminated +// 602 = Unable to terminate process for some other reason +// 603 = Process was not currently running +// 604 = No permission to terminate process +// 605 = Unable to load PSAPI.DLL +// 606 = Unable to identify system type +// 607 = Unsupported OS +// 632 = Invalid process name +// 700 = Unable to get procedure address from PSAPI.DLL +// 701 = Unable to get process list, EnumProcesses failed +// 702 = Unable to load KERNEL32.DLL +// 703 = Unable to get procedure address from KERNEL32.DLL +// 704 = CreateToolhelp32Snapshot failed + +{ + BOOL bResult,bResultm; + DWORD aiPID[1000],iCb=1000,iNumProc; //,iV2000=0; + DWORD iCbneeded,i,iFound=0; + char szName[MAX_PATH],szToTermUpper[MAX_PATH]; + HANDLE hProc,hSnapShot,hSnapShotm; + OSVERSIONINFO osvi; + HINSTANCE hInstLib; + int iLen,iLenP,indx; + HMODULE hMod; + PROCESSENTRY32 procentry; + MODULEENTRY32 modentry; + + // Transfer Process name into "szToTermUpper" and convert to upper case + iLenP=strlen(szToTerminate); + if(iLenP<1 || iLenP>MAX_PATH) return 632; + for(indx=0;indx -#endif - -#include - -#define NULL ((void *)0) -#define min(a,b) ((a) < (b) ? (a) : (b)) - -#ifdef FIXED -#include "fixed.h" -#elif defined(BIGSYM) -#include "int.h" -#else -#include "char.h" -#endif - -int DECODE_RS( -#ifdef FIXED -DTYPE *data, int *eras_pos, int no_eras,int pad){ -#else -void *p,DTYPE *data, int *eras_pos, int no_eras){ - struct rs *rs = (struct rs *)p; -#endif - int deg_lambda, el, deg_omega; - int i, j, r,k; - DTYPE u,q,tmp,num1,num2,den,discr_r; - DTYPE lambda[NROOTS+1], s[NROOTS]; /* Err+Eras Locator poly - * and syndrome poly */ - DTYPE b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1]; - DTYPE root[NROOTS], reg[NROOTS+1], loc[NROOTS]; - int syn_error, count; - -#ifdef FIXED - /* Check pad parameter for validity */ - if(pad < 0 || pad >= NN) - return -1; -#endif - - /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ - for(i=0;i 0) { - /* Init lambda to be the erasure locator polynomial */ - lambda[1] = ALPHA_TO[MODNN(PRIM*(NN-1-eras_pos[0]))]; - for (i = 1; i < no_eras; i++) { - u = MODNN(PRIM*(NN-1-eras_pos[i])); - for (j = i+1; j > 0; j--) { - tmp = INDEX_OF[lambda[j - 1]]; - if(tmp != A0) - lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; - } - } - -#if DEBUG >= 1 - /* Test code that verifies the erasure locator polynomial just constructed - Needed only for decoder debugging. */ - - /* find roots of the erasure location polynomial */ - for(i=1;i<=no_eras;i++) - reg[i] = INDEX_OF[lambda[i]]; - - count = 0; - for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) { - q = 1; - for (j = 1; j <= no_eras; j++) - if (reg[j] != A0) { - reg[j] = MODNN(reg[j] + j); - q ^= ALPHA_TO[reg[j]]; - } - if (q != 0) - continue; - /* store root and error location number indices */ - root[count] = i; - loc[count] = k; - count++; - } - if (count != no_eras) { - printf("count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras); - count = -1; - goto finish; - } -#if DEBUG >= 2 - printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); - for (i = 0; i < count; i++) - printf("%d ", loc[i]); - printf("\n"); -#endif -#endif - } - for(i=0;i 0; j--){ - if (reg[j] != A0) { - reg[j] = MODNN(reg[j] + j); - q ^= ALPHA_TO[reg[j]]; - } - } - if (q != 0) - continue; /* Not a root */ - /* store root (index-form) and error location number */ -#if DEBUG>=2 - printf("count %d root %d loc %d\n",count,i,k); -#endif - root[count] = i; - loc[count] = k; - /* If we've already found max possible roots, - * abort the search to save time - */ - if(++count == deg_lambda) - break; - } - if (deg_lambda != count) { - /* - * deg(lambda) unequal to number of roots => uncorrectable - * error detected - */ - count = -1; - goto finish; - } - /* - * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo - * x**NROOTS). in index form. Also find deg(omega). - */ - deg_omega = deg_lambda-1; - for (i = 0; i <= deg_omega;i++){ - tmp = 0; - for(j=i;j >= 0; j--){ - if ((s[i - j] != A0) && (lambda[j] != A0)) - tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; - } - omega[i] = INDEX_OF[tmp]; - } - - /* - * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = - * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form - */ - for (j = count-1; j >=0; j--) { - num1 = 0; - for (i = deg_omega; i >= 0; i--) { - if (omega[i] != A0) - num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; - } - num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; - den = 0; - - /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ - for (i = min(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) { - if(lambda[i+1] != A0) - den ^= ALPHA_TO[MODNN(lambda[i+1] + i * root[j])]; - } -#if DEBUG >= 1 - if (den == 0) { - printf("\n ERROR: denominator = 0\n"); - count = -1; - goto finish; - } -#endif - /* Apply error to data */ - if (num1 != 0 && loc[j] >= PAD) { - data[loc[j]-PAD] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; - } - } - finish: - if(eras_pos != NULL){ - for(i=0;i +#endif + +#include + +#define NULL ((void *)0) +#define min(a,b) ((a) < (b) ? (a) : (b)) + +#ifdef FIXED +#include "fixed.h" +#elif defined(BIGSYM) +#include "int.h" +#else +#include "char.h" +#endif + +int DECODE_RS( +#ifdef FIXED +DTYPE *data, int *eras_pos, int no_eras,int pad){ +#else +void *p,DTYPE *data, int *eras_pos, int no_eras){ + struct rs *rs = (struct rs *)p; +#endif + int deg_lambda, el, deg_omega; + int i, j, r,k; + DTYPE u,q,tmp,num1,num2,den,discr_r; + DTYPE lambda[NROOTS+1], s[NROOTS]; /* Err+Eras Locator poly + * and syndrome poly */ + DTYPE b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1]; + DTYPE root[NROOTS], reg[NROOTS+1], loc[NROOTS]; + int syn_error, count; + +#ifdef FIXED + /* Check pad parameter for validity */ + if(pad < 0 || pad >= NN) + return -1; +#endif + + /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ + for(i=0;i 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = ALPHA_TO[MODNN(PRIM*(NN-1-eras_pos[0]))]; + for (i = 1; i < no_eras; i++) { + u = MODNN(PRIM*(NN-1-eras_pos[i])); + for (j = i+1; j > 0; j--) { + tmp = INDEX_OF[lambda[j - 1]]; + if(tmp != A0) + lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; + } + } + +#if DEBUG >= 1 + /* Test code that verifies the erasure locator polynomial just constructed + Needed only for decoder debugging. */ + + /* find roots of the erasure location polynomial */ + for(i=1;i<=no_eras;i++) + reg[i] = INDEX_OF[lambda[i]]; + + count = 0; + for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) { + q = 1; + for (j = 1; j <= no_eras; j++) + if (reg[j] != A0) { + reg[j] = MODNN(reg[j] + j); + q ^= ALPHA_TO[reg[j]]; + } + if (q != 0) + continue; + /* store root and error location number indices */ + root[count] = i; + loc[count] = k; + count++; + } + if (count != no_eras) { + printf("count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras); + count = -1; + goto finish; + } +#if DEBUG >= 2 + printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif +#endif + } + for(i=0;i 0; j--){ + if (reg[j] != A0) { + reg[j] = MODNN(reg[j] + j); + q ^= ALPHA_TO[reg[j]]; + } + } + if (q != 0) + continue; /* Not a root */ + /* store root (index-form) and error location number */ +#if DEBUG>=2 + printf("count %d root %d loc %d\n",count,i,k); +#endif + root[count] = i; + loc[count] = k; + /* If we've already found max possible roots, + * abort the search to save time + */ + if(++count == deg_lambda) + break; + } + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + count = -1; + goto finish; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**NROOTS). in index form. Also find deg(omega). + */ + deg_omega = deg_lambda-1; + for (i = 0; i <= deg_omega;i++){ + tmp = 0; + for(j=i;j >= 0; j--){ + if ((s[i - j] != A0) && (lambda[j] != A0)) + tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; + } + omega[i] = INDEX_OF[tmp]; + } + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count-1; j >=0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; + } + num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) { + if(lambda[i+1] != A0) + den ^= ALPHA_TO[MODNN(lambda[i+1] + i * root[j])]; + } +#if DEBUG >= 1 + if (den == 0) { + printf("\n ERROR: denominator = 0\n"); + count = -1; + goto finish; + } +#endif + /* Apply error to data */ + if (num1 != 0 && loc[j] >= PAD) { + data[loc[j]-PAD] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; + } + } + finish: + if(eras_pos != NULL){ + for(i=0;i0 means compound mycall - j4=index(callsign,'/') ! j4>0 means compound hiscall - callgrid(icall)=callsign(1:j2) - - mz=1 -! Allow MyCall + HisCall + rpt (?) - if(n.eq.1 .and. j3.lt.1 .and. j4.lt.1 .and. & - flip.gt.0.0 .and. callsign(1:6).ne.' ') mz=MAXRPT+1 - do m=1,mz - if(m.gt.1) grid=rpt(m-1) - if(j3.lt.1 .and.j4.lt.1) callgrid(icall)=callsign(1:j2)//' '//grid - message=mycall(1:j1)//' '//callgrid(icall) - k=k+1 - testmsg(k)=message - call encode65(message,ncode(1,k)) - -! Insert CQ message - if(j4.lt.1) callgrid(icall)=callsign(1:j2)//' '//grid - message='CQ '//callgrid(icall) - k=k+1 - testmsg(k)=message - call encode65(message,ncode(1,k)) - enddo -10 continue - enddo - -20 continue - ntot=k - call timer('deep65a ',1) - -30 continue - call timer('deep65b ',0) - ref0=0. - do j=1,63 - ref0=ref0 + s3(mrs(j),j) - enddo - - p1=-1.e30 - p2=-1.e30 - do k=1,ntot - pp(k)=0. -! Test all messages if flip=+1; skip the CQ messages if flip=-1. - if(flip.gt.0.0 .or. testmsg(k)(1:3).ne.'CQ ') then - sum=0. - ref=ref0 - do j=1,63 - i=ncode(j,k)+1 - sum=sum + s3(i,j) - if(i.eq.mrs(j)) ref=ref - s3(i,j) + s3(mrs2(j),j) - enddo - p=sum/ref - pp(k)=p - if(p.gt.p1) then - p1=p - ip1=k - endif - endif - enddo - - do i=1,ntot - if(pp(i).gt.p2 .and. pp(i).ne.p1) p2=pp(i) - enddo - -! ### DO NOT REMOVE ### - rewind 77 - write(77,*) p1,p2 -! ### Works OK without it (in both Windows and Linux) if compiled -! ### without optimization. However, in Windows this is a colossal -! ### pain because of the way F2PY wants to run the compile step. - - if(mode65.eq.1) bias=max(1.12*p2,0.335) - if(mode65.eq.2) bias=max(1.08*p2,0.405) - if(mode65.ge.4) bias=max(1.04*p2,0.505) - - if(p2.eq.p1 .and. p1.ne.-1.e30) stop 'Error in deep65' - qual=100.0*(p1-bias) - - decoded=' ' - c=' ' - - if(qual.gt.1.0) then - if(qual.lt.6.0) c='?' - decoded=testmsg(ip1) - else - qual=0. - endif - decoded(22:22)=c - -! Make sure everything is upper case. - do i=1,22 - if(decoded(i:i).ge.'a' .and. decoded(i:i).le.'z') & - decoded(i:i)=char(ichar(decoded(i:i))-32) - enddo - call timer('deep65b ',1) - - return -end subroutine deep65 +subroutine deep65(s3,mode65,neme,flip,mycall,hiscall,hisgrid,decoded,qual) + + parameter (MAXCALLS=7000,MAXRPT=63) + real s3(64,63) + character callsign*12,grid*4,message*22,hisgrid*6,c*1,ceme*3 + character*12 mycall,hiscall + character*22 decoded + character*22 testmsg(2*MAXCALLS + 2 + MAXRPT) + character*15 callgrid(MAXCALLS) + character*180 line + character*4 rpt(MAXRPT) + integer ncode(63,2*MAXCALLS + 2 + MAXRPT) + real pp(2*MAXCALLS + 2 + MAXRPT) + common/mrscom/ mrs(63),mrs2(63) + common/c3com/ mcall3a + data rpt/'-01','-02','-03','-04','-05', & + '-06','-07','-08','-09','-10', & + '-11','-12','-13','-14','-15', & + '-16','-17','-18','-19','-20', & + '-21','-22','-23','-24','-25', & + '-26','-27','-28','-29','-30', & + 'R-01','R-02','R-03','R-04','R-05', & + 'R-06','R-07','R-08','R-09','R-10', & + 'R-11','R-12','R-13','R-14','R-15', & + 'R-16','R-17','R-18','R-19','R-20', & + 'R-21','R-22','R-23','R-24','R-25', & + 'R-26','R-27','R-28','R-29','R-30', & + 'RO','RRR','73'/ + save + + if(mcall3a.eq.0) go to 30 + + call timer('deep65a ',0) + mcall3a=0 + rewind 23 + k=0 + icall=0 + do n=1,MAXCALLS + if(n.eq.1) then + callsign=hiscall + do i=4,12 + if(ichar(callsign(i:i)).eq.0) callsign(i:i)=' ' + enddo + grid=hisgrid(1:4) + if(ichar(grid(3:3)).eq.0) grid(3:3)=' ' + if(ichar(grid(4:4)).eq.0) grid(4:4)=' ' + else + read(23,1002,end=20) line +1002 format (A80) + if(line(1:4).eq.'ZZZZ') go to 20 + if(line(1:2).eq.'//') go to 10 + i1=index(line,',') + if(i1.lt.4) go to 10 + i2=index(line(i1+1:),',') + if(i2.lt.5) go to 10 + i2=i2+i1 + i3=index(line(i2+1:),',') + if(i3.lt.1) i3=index(line(i2+1:),' ') + i3=i2+i3 + callsign=line(1:i1-1) + grid=line(i1+1:i2-1) + ceme=line(i2+1:i3-1) + if(neme.eq.1 .and. ceme.ne.'EME') go to 10 + endif + + icall=icall+1 + j1=index(mycall,' ') - 1 + if(j1.le.-1) j1=12 + if(j1.lt.3) j1=6 + j2=index(callsign,' ') - 1 + if(j2.le.-1) j2=12 + if(j2.lt.3) j2=6 + j3=index(mycall,'/') ! j3>0 means compound mycall + j4=index(callsign,'/') ! j4>0 means compound hiscall + callgrid(icall)=callsign(1:j2) + + mz=1 +! Allow MyCall + HisCall + rpt (?) + if(n.eq.1 .and. j3.lt.1 .and. j4.lt.1 .and. & + flip.gt.0.0 .and. callsign(1:6).ne.' ') mz=MAXRPT+1 + do m=1,mz + if(m.gt.1) grid=rpt(m-1) + if(j3.lt.1 .and.j4.lt.1) callgrid(icall)=callsign(1:j2)//' '//grid + message=mycall(1:j1)//' '//callgrid(icall) + k=k+1 + testmsg(k)=message + call encode65(message,ncode(1,k)) + +! Insert CQ message + if(j4.lt.1) callgrid(icall)=callsign(1:j2)//' '//grid + message='CQ '//callgrid(icall) + k=k+1 + testmsg(k)=message + call encode65(message,ncode(1,k)) + enddo +10 continue + enddo + +20 continue + ntot=k + call timer('deep65a ',1) + +30 continue + call timer('deep65b ',0) + ref0=0. + do j=1,63 + ref0=ref0 + s3(mrs(j),j) + enddo + + p1=-1.e30 + p2=-1.e30 + do k=1,ntot + pp(k)=0. +! Test all messages if flip=+1; skip the CQ messages if flip=-1. + if(flip.gt.0.0 .or. testmsg(k)(1:3).ne.'CQ ') then + sum=0. + ref=ref0 + do j=1,63 + i=ncode(j,k)+1 + sum=sum + s3(i,j) + if(i.eq.mrs(j)) ref=ref - s3(i,j) + s3(mrs2(j),j) + enddo + p=sum/ref + pp(k)=p + if(p.gt.p1) then + p1=p + ip1=k + endif + endif + enddo + + do i=1,ntot + if(pp(i).gt.p2 .and. pp(i).ne.p1) p2=pp(i) + enddo + +! ### DO NOT REMOVE ### + rewind 77 + write(77,*) p1,p2 +! ### Works OK without it (in both Windows and Linux) if compiled +! ### without optimization. However, in Windows this is a colossal +! ### pain because of the way F2PY wants to run the compile step. + + if(mode65.eq.1) bias=max(1.12*p2,0.335) + if(mode65.eq.2) bias=max(1.08*p2,0.405) + if(mode65.ge.4) bias=max(1.04*p2,0.505) + + if(p2.eq.p1 .and. p1.ne.-1.e30) stop 'Error in deep65' + qual=100.0*(p1-bias) + + decoded=' ' + c=' ' + + if(qual.gt.1.0) then + if(qual.lt.6.0) c='?' + decoded=testmsg(ip1) + else + qual=0. + endif + decoded(22:22)=c + +! Make sure everything is upper case. + do i=1,22 + if(decoded(i:i).ge.'a' .and. decoded(i:i).le.'z') & + decoded(i:i)=char(ichar(decoded(i:i))-32) + enddo + call timer('deep65b ',1) + + return +end subroutine deep65 diff --git a/libm65/deg2grid.f b/libm65/deg2grid.f index 257acf86d..8c64028a8 100644 --- a/libm65/deg2grid.f +++ b/libm65/deg2grid.f @@ -1,30 +1,30 @@ - subroutine deg2grid(dlong0,dlat,grid) - - real dlong !West longitude (deg) - real dlat !Latitude (deg) - character grid*6 - - dlong=dlong0 - if(dlong.lt.-180.0) dlong=dlong+360.0 - if(dlong.gt.180.0) dlong=dlong-360.0 - -C Convert to units of 5 min of longitude, working east from 180 deg. - nlong=60.0*(180.0-dlong)/5.0 - n1=nlong/240 !20-degree field - n2=(nlong-240*n1)/24 !2 degree square - n3=nlong-240*n1-24*n2 !5 minute subsquare - grid(1:1)=char(ichar('A')+n1) - grid(3:3)=char(ichar('0')+n2) - grid(5:5)=char(ichar('a')+n3) - -C Convert to units of 2.5 min of latitude, working north from -90 deg. - nlat=60.0*(dlat+90)/2.5 - n1=nlat/240 !10-degree field - n2=(nlat-240*n1)/24 !1 degree square - n3=nlat-240*n1-24*n2 !2.5 minuts subsquare - grid(2:2)=char(ichar('A')+n1) - grid(4:4)=char(ichar('0')+n2) - grid(6:6)=char(ichar('a')+n3) - - return - end + subroutine deg2grid(dlong0,dlat,grid) + + real dlong !West longitude (deg) + real dlat !Latitude (deg) + character grid*6 + + dlong=dlong0 + if(dlong.lt.-180.0) dlong=dlong+360.0 + if(dlong.gt.180.0) dlong=dlong-360.0 + +C Convert to units of 5 min of longitude, working east from 180 deg. + nlong=60.0*(180.0-dlong)/5.0 + n1=nlong/240 !20-degree field + n2=(nlong-240*n1)/24 !2 degree square + n3=nlong-240*n1-24*n2 !5 minute subsquare + grid(1:1)=char(ichar('A')+n1) + grid(3:3)=char(ichar('0')+n2) + grid(5:5)=char(ichar('a')+n3) + +C Convert to units of 2.5 min of latitude, working north from -90 deg. + nlat=60.0*(dlat+90)/2.5 + n1=nlat/240 !10-degree field + n2=(nlat-240*n1)/24 !1 degree square + n3=nlat-240*n1-24*n2 !2.5 minuts subsquare + grid(2:2)=char(ichar('A')+n1) + grid(4:4)=char(ichar('0')+n2) + grid(6:6)=char(ichar('a')+n3) + + return + end diff --git a/libm65/demod64a.f b/libm65/demod64a.f index b62037c09..b5fbd6087 100644 --- a/libm65/demod64a.f +++ b/libm65/demod64a.f @@ -1,73 +1,73 @@ - subroutine demod64a(s3,nadd,mrsym,mrprob, - + mr2sym,mr2prob,ntest,nlow) - -C Demodulate the 64-bin spectra for each of 63 symbols in a frame. - -C Parameters -C nadd number of spectra already summed -C mrsym most reliable symbol value -C mr2sym second most likely symbol value -C mrprob probability that mrsym was the transmitted value -C mr2prob probability that mr2sym was the transmitted value - - implicit real*8 (a-h,o-z) - real*4 s3(64,63) - real*8 fs(64) - integer mrsym(63),mrprob(63),mr2sym(63),mr2prob(63) - common/mrscom/ mrs(63),mrs2(63) - - afac=1.1 * float(nadd)**0.64 - scale=255.999 - -C Compute average spectral value - sum=0. - do j=1,63 - do i=1,64 - sum=sum+s3(i,j) - enddo - enddo - ave=sum/(64.*63.) - i1=1 !Silence warning - i2=1 - -C Compute probabilities for most reliable symbol values - do j=1,63 - s1=-1.e30 - fsum=0. - do i=1,64 - x=min(afac*s3(i,j)/ave,50.d0) - fs(i)=exp(x) - fsum=fsum+fs(i) - if(s3(i,j).gt.s1) then - s1=s3(i,j) - i1=i !Most reliable - endif - enddo - - s2=-1.e30 - do i=1,64 - if(i.ne.i1 .and. s3(i,j).gt.s2) then - s2=s3(i,j) - i2=i !Second most reliable - endif - enddo - p1=fs(i1)/fsum !Normalized probabilities - p2=fs(i2)/fsum - mrsym(j)=i1-1 - mr2sym(j)=i2-1 - mrprob(j)=scale*p1 - mr2prob(j)=scale*p2 - mrs(j)=i1 - mrs2(j)=i2 - enddo - - sum=0. - nlow=0 - do j=1,63 - sum=sum+mrprob(j) - if(mrprob(j).le.5) nlow=nlow+1 - enddo - ntest=sum/63 - - return - end + subroutine demod64a(s3,nadd,mrsym,mrprob, + + mr2sym,mr2prob,ntest,nlow) + +C Demodulate the 64-bin spectra for each of 63 symbols in a frame. + +C Parameters +C nadd number of spectra already summed +C mrsym most reliable symbol value +C mr2sym second most likely symbol value +C mrprob probability that mrsym was the transmitted value +C mr2prob probability that mr2sym was the transmitted value + + implicit real*8 (a-h,o-z) + real*4 s3(64,63) + real*8 fs(64) + integer mrsym(63),mrprob(63),mr2sym(63),mr2prob(63) + common/mrscom/ mrs(63),mrs2(63) + + afac=1.1 * float(nadd)**0.64 + scale=255.999 + +C Compute average spectral value + sum=0. + do j=1,63 + do i=1,64 + sum=sum+s3(i,j) + enddo + enddo + ave=sum/(64.*63.) + i1=1 !Silence warning + i2=1 + +C Compute probabilities for most reliable symbol values + do j=1,63 + s1=-1.e30 + fsum=0. + do i=1,64 + x=min(afac*s3(i,j)/ave,50.d0) + fs(i)=exp(x) + fsum=fsum+fs(i) + if(s3(i,j).gt.s1) then + s1=s3(i,j) + i1=i !Most reliable + endif + enddo + + s2=-1.e30 + do i=1,64 + if(i.ne.i1 .and. s3(i,j).gt.s2) then + s2=s3(i,j) + i2=i !Second most reliable + endif + enddo + p1=fs(i1)/fsum !Normalized probabilities + p2=fs(i2)/fsum + mrsym(j)=i1-1 + mr2sym(j)=i2-1 + mrprob(j)=scale*p1 + mr2prob(j)=scale*p2 + mrs(j)=i1 + mrs2(j)=i2 + enddo + + sum=0. + nlow=0 + do j=1,63 + sum=sum+mrprob(j) + if(mrprob(j).le.5) nlow=nlow+1 + enddo + ntest=sum/63 + + return + end diff --git a/libm65/display.f90 b/libm65/display.f90 index 6925373aa..22f4a6933 100644 --- a/libm65/display.f90 +++ b/libm65/display.f90 @@ -1,169 +1,169 @@ -subroutine display(nkeep,ftol) - - parameter (MAXLINES=400,MX=400) - integer indx(MAXLINES),indx2(MX) - character*81 line(MAXLINES),line2(MX),line3(MAXLINES) - character out*50,cfreq0*3,cqlive*52 - character*6 callsign,callsign0 - character*12 freqcall(100) - real freqkHz(MAXLINES) - integer utc(MAXLINES),utc2(MX),utcz - real*8 f0 - - rewind 26 - - do i=1,MAXLINES - read(26,1010,end=10) line(i) -1010 format(a80) - read(line(i),1020) f0,ndf,nh,nm -1020 format(f8.3,i5,25x,i3,i2) - utc(i)=60*nh + nm - freqkHz(i)=1000.d0*(f0-144.d0) + 0.001d0*ndf - enddo - -10 nz=i-1 - utcz=utc(nz) - nz=nz-1 - if(nz.lt.1) go to 999 - nquad=max(nkeep/4,3) - do i=1,nz - nage=utcz-utc(i) - if(nage.lt.0) nage=nage+1440 - iage=nage/nquad - write(line(i)(80:81),1021) iage -1021 format(i2) - enddo - - nage=utcz-utc(1) - if(nage.lt.0) nage=nage+1440 - if(nage.gt.nkeep) then - do i=1,nz - nage=utcz-utc(i) - if(nage.lt.0) nage=nage+1440 - if(nage.le.nkeep) go to 20 - enddo -20 i0=i - nz=nz-i0+1 - rewind 26 - if(nz.lt.1) go to 999 - do i=1,nz - j=i+i0-1 - line(i)=line(j) - utc(i)=utc(j) - freqkHz(i)=freqkHz(j) - write(26,1010) line(i) - enddo - endif - - call flush(26) - call indexx(nz,freqkHz,indx) - - nstart=1 - k3=0 - k=1 - m=indx(1) - if(m.lt.1 .or. m.gt.MAXLINES) then - print*,'Error in display.f90: ',nz,m - m=1 - endif - line2(1)=line(m) - utc2(1)=utc(m) - do i=2,nz - j0=indx(i-1) - j=indx(i) - if(freqkHz(j)-freqkHz(j0).gt.2.0*ftol) then - if(nstart.eq.0) then - k=k+1 - line2(k)="" - utc2(k)=-1 - endif - kz=k - if(nstart.eq.1) then - call indexx(kz,utc2,indx2) - k3=0 - do k=1,kz - k3=min(k3+1,400) - line3(k3)=line2(indx2(k)) - enddo - nstart=0 - else - call indexx(kz,utc2,indx2) - do k=1,kz - k3=min(k3+1,400) - line3(k3)=line2(indx2(k)) - enddo - endif - k=0 - endif - if(i.eq.nz) then - k=k+1 - line2(k)="" - utc2(k)=-1 - endif - k=k+1 - line2(k)=line(j) - utc2(k)=utc(j) - j0=j - enddo - kz=k - call indexx(kz,utc2,indx2) - do k=1,kz - k3=min(k3+1,400) - line3(k3)=line2(indx2(k)) - enddo - - rewind 19 - rewind 20 - cfreq0=' ' - nc=0 - callsign0=' ' - do k=1,k3 - out=line3(k)(6:13)//line3(k)(28:31)//line3(k)(39:43)// & - line3(k)(35:38)//line3(k)(44:67)//line3(k)(77:81) - if(out(1:3).ne.' ') then - cfreq0=out(1:3) - if(iw.lt.MAXLINES-1) iw=iw+1 - cqlive=line3(k)(6:13)//line3(k)(28:31)//line3(k)(39:43)// & - line3(k)(23:27)//line3(k)(35:38)//line3(k)(44:67)// & - line3(k)(80:81) - if(index(cqlive,' CQ ').gt.0 .or. index(cqlive,' QRZ ').gt.0 .or. & - index(cqlive,' QRT ').gt.0 .or. index(cqlive,' CQV ').gt.0 .or. & - index(cqlive,' CQH ').gt.0) write(19,1029) cqlive -1029 format(a52) - write(*,1030) out -1030 format('@',a50) - i1=index(out(24:),' ') - callsign=out(i1+24:) - i2=index(callsign,' ') - if(i2.gt.1) callsign(i2:)=' ' - if(callsign.ne.' ' .and. callsign.ne.callsign0) then - len=i2-1 - if(len.lt.0) len=6 - if(len.ge.4) then !Omit short "callsigns" - nc=nc+1 - freqcall(nc)=cfreq0//' '//callsign//line3(k)(80:81) - callsign0=callsign - endif - endif - if(callsign.ne.' ' .and. callsign.eq.callsign0) then - freqcall(nc)=cfreq0//' '//callsign//line3(k)(80:81) - endif - endif - enddo - flush(19) - nc=nc+1 - freqcall(nc)=' ' - nc=nc+1 - freqcall(nc)=' ' - freqcall(nc+1)=' ' - freqcall(nc+2)=' ' - iz=(nc+2)/3 - - do i=1,nc - write(*,1042) freqcall(i) -1042 format('&',a12) - enddo - -999 continue - return -end subroutine display +subroutine display(nkeep,ftol) + + parameter (MAXLINES=400,MX=400) + integer indx(MAXLINES),indx2(MX) + character*81 line(MAXLINES),line2(MX),line3(MAXLINES) + character out*50,cfreq0*3,cqlive*52 + character*6 callsign,callsign0 + character*12 freqcall(100) + real freqkHz(MAXLINES) + integer utc(MAXLINES),utc2(MX),utcz + real*8 f0 + + rewind 26 + + do i=1,MAXLINES + read(26,1010,end=10) line(i) +1010 format(a80) + read(line(i),1020) f0,ndf,nh,nm +1020 format(f8.3,i5,25x,i3,i2) + utc(i)=60*nh + nm + freqkHz(i)=1000.d0*(f0-144.d0) + 0.001d0*ndf + enddo + +10 nz=i-1 + utcz=utc(nz) + nz=nz-1 + if(nz.lt.1) go to 999 + nquad=max(nkeep/4,3) + do i=1,nz + nage=utcz-utc(i) + if(nage.lt.0) nage=nage+1440 + iage=nage/nquad + write(line(i)(80:81),1021) iage +1021 format(i2) + enddo + + nage=utcz-utc(1) + if(nage.lt.0) nage=nage+1440 + if(nage.gt.nkeep) then + do i=1,nz + nage=utcz-utc(i) + if(nage.lt.0) nage=nage+1440 + if(nage.le.nkeep) go to 20 + enddo +20 i0=i + nz=nz-i0+1 + rewind 26 + if(nz.lt.1) go to 999 + do i=1,nz + j=i+i0-1 + line(i)=line(j) + utc(i)=utc(j) + freqkHz(i)=freqkHz(j) + write(26,1010) line(i) + enddo + endif + + call flush(26) + call indexx(nz,freqkHz,indx) + + nstart=1 + k3=0 + k=1 + m=indx(1) + if(m.lt.1 .or. m.gt.MAXLINES) then + print*,'Error in display.f90: ',nz,m + m=1 + endif + line2(1)=line(m) + utc2(1)=utc(m) + do i=2,nz + j0=indx(i-1) + j=indx(i) + if(freqkHz(j)-freqkHz(j0).gt.2.0*ftol) then + if(nstart.eq.0) then + k=k+1 + line2(k)="" + utc2(k)=-1 + endif + kz=k + if(nstart.eq.1) then + call indexx(kz,utc2,indx2) + k3=0 + do k=1,kz + k3=min(k3+1,400) + line3(k3)=line2(indx2(k)) + enddo + nstart=0 + else + call indexx(kz,utc2,indx2) + do k=1,kz + k3=min(k3+1,400) + line3(k3)=line2(indx2(k)) + enddo + endif + k=0 + endif + if(i.eq.nz) then + k=k+1 + line2(k)="" + utc2(k)=-1 + endif + k=k+1 + line2(k)=line(j) + utc2(k)=utc(j) + j0=j + enddo + kz=k + call indexx(kz,utc2,indx2) + do k=1,kz + k3=min(k3+1,400) + line3(k3)=line2(indx2(k)) + enddo + + rewind 19 + rewind 20 + cfreq0=' ' + nc=0 + callsign0=' ' + do k=1,k3 + out=line3(k)(6:13)//line3(k)(28:31)//line3(k)(39:43)// & + line3(k)(35:38)//line3(k)(44:67)//line3(k)(77:81) + if(out(1:3).ne.' ') then + cfreq0=out(1:3) + if(iw.lt.MAXLINES-1) iw=iw+1 + cqlive=line3(k)(6:13)//line3(k)(28:31)//line3(k)(39:43)// & + line3(k)(23:27)//line3(k)(35:38)//line3(k)(44:67)// & + line3(k)(80:81) + if(index(cqlive,' CQ ').gt.0 .or. index(cqlive,' QRZ ').gt.0 .or. & + index(cqlive,' QRT ').gt.0 .or. index(cqlive,' CQV ').gt.0 .or. & + index(cqlive,' CQH ').gt.0) write(19,1029) cqlive +1029 format(a52) + write(*,1030) out +1030 format('@',a50) + i1=index(out(24:),' ') + callsign=out(i1+24:) + i2=index(callsign,' ') + if(i2.gt.1) callsign(i2:)=' ' + if(callsign.ne.' ' .and. callsign.ne.callsign0) then + len=i2-1 + if(len.lt.0) len=6 + if(len.ge.4) then !Omit short "callsigns" + nc=nc+1 + freqcall(nc)=cfreq0//' '//callsign//line3(k)(80:81) + callsign0=callsign + endif + endif + if(callsign.ne.' ' .and. callsign.eq.callsign0) then + freqcall(nc)=cfreq0//' '//callsign//line3(k)(80:81) + endif + endif + enddo + flush(19) + nc=nc+1 + freqcall(nc)=' ' + nc=nc+1 + freqcall(nc)=' ' + freqcall(nc+1)=' ' + freqcall(nc+2)=' ' + iz=(nc+2)/3 + + do i=1,nc + write(*,1042) freqcall(i) +1042 format('&',a12) + enddo + +999 continue + return +end subroutine display diff --git a/libm65/dot.f b/libm65/dot.f index f4c378820..8e2d826bf 100644 --- a/libm65/dot.f +++ b/libm65/dot.f @@ -1,11 +1,11 @@ - real*8 function dot(x,y) - - real*8 x(3),y(3) - - dot=0.d0 - do i=1,3 - dot=dot+x(i)*y(i) - enddo - - return - end + real*8 function dot(x,y) + + real*8 x(3),y(3) + + dot=0.d0 + do i=1,3 + dot=dot+x(i)*y(i) + enddo + + return + end diff --git a/libm65/dpol.f90 b/libm65/dpol.f90 index 23a55bce5..152d69349 100644 --- a/libm65/dpol.f90 +++ b/libm65/dpol.f90 @@ -1,41 +1,41 @@ -real function dpol(mygrid,hisgrid) - -! Compute spatial polartzation offset in degrees for the present -! time, between two specified grid locators. - - character*6 MyGrid,HisGrid - real lat,lon,LST - character cdate*8,ctime2*10,czone*5,fnamedate*6 - integer it(8) - data rad/57.2957795/ - - call date_and_time(cdate,ctime2,czone,it) - nyear=it(1) - month=it(2) - nday=it(3) - nh=it(5)-it(4)/60 - nm=it(6) - ns=it(7) - uth=nh + nm/60.0 + ns/3600.0 - - call grid2deg(MyGrid,lon,lat) - call MoonDop(nyear,month,nday,uth,-lon,lat,RAMoon,DecMoon, & - LST,HA,AzMoon,ElMoon,vr,dist) - xx=sin(lat/rad)*cos(ElMoon/rad) - cos(lat/rad)* & - cos(AzMoon/rad)*sin(ElMoon/rad) - yy=cos(lat/rad)*sin(AzMoon/rad) - poloffset1=rad*atan2(yy,xx) - - call grid2deg(hisGrid,lon,lat) - call MoonDop(nyear,month,nday,uth,-lon,lat,RAMoon,DecMoon, & - LST,HA,AzMoon,ElMoon,vr,dist) - xx=sin(lat/rad)*cos(ElMoon/rad) - cos(lat/rad)* & - cos(AzMoon/rad)*sin(ElMoon/rad) - yy=cos(lat/rad)*sin(AzMoon/rad) - poloffset2=rad*atan2(yy,xx) - - dpol=mod(poloffset2-poloffset1+720.0,180.0) - if(dpol.gt.90.0) dpol=dpol-180.0 - - return -end function dpol +real function dpol(mygrid,hisgrid) + +! Compute spatial polartzation offset in degrees for the present +! time, between two specified grid locators. + + character*6 MyGrid,HisGrid + real lat,lon,LST + character cdate*8,ctime2*10,czone*5,fnamedate*6 + integer it(8) + data rad/57.2957795/ + + call date_and_time(cdate,ctime2,czone,it) + nyear=it(1) + month=it(2) + nday=it(3) + nh=it(5)-it(4)/60 + nm=it(6) + ns=it(7) + uth=nh + nm/60.0 + ns/3600.0 + + call grid2deg(MyGrid,lon,lat) + call MoonDop(nyear,month,nday,uth,-lon,lat,RAMoon,DecMoon, & + LST,HA,AzMoon,ElMoon,vr,dist) + xx=sin(lat/rad)*cos(ElMoon/rad) - cos(lat/rad)* & + cos(AzMoon/rad)*sin(ElMoon/rad) + yy=cos(lat/rad)*sin(AzMoon/rad) + poloffset1=rad*atan2(yy,xx) + + call grid2deg(hisGrid,lon,lat) + call MoonDop(nyear,month,nday,uth,-lon,lat,RAMoon,DecMoon, & + LST,HA,AzMoon,ElMoon,vr,dist) + xx=sin(lat/rad)*cos(ElMoon/rad) - cos(lat/rad)* & + cos(AzMoon/rad)*sin(ElMoon/rad) + yy=cos(lat/rad)*sin(AzMoon/rad) + poloffset2=rad*atan2(yy,xx) + + dpol=mod(poloffset2-poloffset1+720.0,180.0) + if(dpol.gt.90.0) dpol=dpol-180.0 + + return +end function dpol diff --git a/libm65/encode65.f b/libm65/encode65.f index 1fca85ae4..670c2e583 100644 --- a/libm65/encode65.f +++ b/libm65/encode65.f @@ -1,13 +1,13 @@ - subroutine encode65(message,sent) - - character message*22 - integer dgen(12) - integer sent(63) - - call packmsg(message,dgen) - call rs_encode(dgen,sent) - call interleave63(sent,1) - call graycode(sent,63,1) - - return - end + subroutine encode65(message,sent) + + character message*22 + integer dgen(12) + integer sent(63) + + call packmsg(message,dgen) + call rs_encode(dgen,sent) + call interleave63(sent,1) + call graycode(sent,63,1) + + return + end diff --git a/libm65/encode_rs.c b/libm65/encode_rs.c index acfb798fe..911bc36dd 100644 --- a/libm65/encode_rs.c +++ b/libm65/encode_rs.c @@ -1,52 +1,52 @@ -/* Reed-Solomon encoder - * Copyright 2002, Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#include - -#ifdef FIXED -#include "fixed.h" -#elif defined(BIGSYM) -#include "int.h" -#else -#include "char.h" -#endif - -void ENCODE_RS( -#ifdef FIXED -DTYPE *data, DTYPE *bb,int pad){ -#else -void *p,DTYPE *data, DTYPE *bb){ - struct rs *rs = (struct rs *)p; -#endif - int i, j; - DTYPE feedback; - -#ifdef FIXED - /* Check pad parameter for validity */ - if(pad < 0 || pad >= NN) - return; -#endif - - memset(bb,0,NROOTS*sizeof(DTYPE)); - - for(i=0;i + +#ifdef FIXED +#include "fixed.h" +#elif defined(BIGSYM) +#include "int.h" +#else +#include "char.h" +#endif + +void ENCODE_RS( +#ifdef FIXED +DTYPE *data, DTYPE *bb,int pad){ +#else +void *p,DTYPE *data, DTYPE *bb){ + struct rs *rs = (struct rs *)p; +#endif + int i, j; + DTYPE feedback; + +#ifdef FIXED + /* Check pad parameter for validity */ + if(pad < 0 || pad >= NN) + return; +#endif + + memset(bb,0,NROOTS*sizeof(DTYPE)); + + for(i=0;i dev_null') -#else - iret=system('kvasd -q > dev_null') -#endif -! call timer('kvasd ',1) - if(iret.ne.0) then - if(first) write(*,1000) iret - 1000 format('Error in KV decoder, or no KV decoder present.'/ - + 'Return code:',i8,'. Will use BM algorithm.') - ndec=0 - first=.false. - go to 20 - endif - - read(22,rec=2) nsec2,ncount,dat4 - j=nsec2 !Silence compiler warning - decoded=' ' - ltext=.false. - if(ncount.ge.0) then - call unpackmsg(dat4,decoded) !Unpack the user message - if(iand(dat4(10),8).ne.0) ltext=.true. - do i=2,12 - if(dat4(i).ne.dat4(1)) go to 20 - enddo - write(13,*) 'Bad decode?',nhist,nfail,ipk, - + ' ',dat4,decoded - ncount=-1 !Suppress supposedly bogus decodes - decoded=' ' - endif - endif - 20 if(ndec.eq.0) then - call indexx(63,mrprob,indx) - do i=1,nemax - j=indx(i) - if(mrprob(j).gt.120) then - ne2=i-1 - go to 2 - endif - era(i)=j-1 - enddo - ne2=nemax - 2 decoded=' ' - do nerase=0,ne2,2 - call rs_decode(mrsym,era,nerase,dat4,ncount) - if(ncount.ge.0) then - call unpackmsg(dat4,decoded) - go to 900 - endif - enddo - endif - - 900 return - end + subroutine extract(s3,nadd,ncount,nhist,decoded,ltext) + + real s3(64,63) + real tmp(4032) + character decoded*22 + integer era(51),dat4(12),indx(64) + integer mrsym(63),mr2sym(63),mrprob(63),mr2prob(63) + logical first,ltext + data first/.true./,nsec1/0/ + save + + nfail=0 + 1 continue +! call timer('demod64a',0) + call demod64a(s3,nadd,mrsym,mrprob,mr2sym,mr2prob,ntest,nlow) +! call timer('demod64a',1) + if(ntest.lt.50 .or. nlow.gt.20) then + ncount=-999 !Flag bad data + go to 900 + endif + call chkhist(mrsym,nhist,ipk) + + if(nhist.ge.20) then + nfail=nfail+1 + call pctile(s3,tmp,4032,50,base) ! ### or, use ave from demod64a + do j=1,63 + s3(ipk,j)=base + enddo + if(nfail.gt.30) then + decoded=' ' + ncount=-1 + go to 900 + endif + go to 1 + endif + + call graycode(mrsym,63,-1) + call interleave63(mrsym,-1) + call interleave63(mrprob,-1) + + ndec=1 + nemax=30 !Was 200 (30) + maxe=8 + xlambda=13.0 !Was 12 + + if(ndec.eq.1) then + call graycode(mr2sym,63,-1) + call interleave63(mr2sym,-1) + call interleave63(mr2prob,-1) + + nsec1=nsec1+1 + write(22,rec=1) nsec1,xlambda,maxe,200, + + mrsym,mrprob,mr2sym,mr2prob + call flush(22) +! call timer('kvasd ',0) +#ifdef UNIX + iret=system('./kvasd -q > dev_null') +#else + iret=system('kvasd -q > dev_null') +#endif +! call timer('kvasd ',1) + if(iret.ne.0) then + if(first) write(*,1000) iret + 1000 format('Error in KV decoder, or no KV decoder present.'/ + + 'Return code:',i8,'. Will use BM algorithm.') + ndec=0 + first=.false. + go to 20 + endif + + read(22,rec=2) nsec2,ncount,dat4 + j=nsec2 !Silence compiler warning + decoded=' ' + ltext=.false. + if(ncount.ge.0) then + call unpackmsg(dat4,decoded) !Unpack the user message + if(iand(dat4(10),8).ne.0) ltext=.true. + do i=2,12 + if(dat4(i).ne.dat4(1)) go to 20 + enddo + write(13,*) 'Bad decode?',nhist,nfail,ipk, + + ' ',dat4,decoded + ncount=-1 !Suppress supposedly bogus decodes + decoded=' ' + endif + endif + 20 if(ndec.eq.0) then + call indexx(63,mrprob,indx) + do i=1,nemax + j=indx(i) + if(mrprob(j).gt.120) then + ne2=i-1 + go to 2 + endif + era(i)=j-1 + enddo + ne2=nemax + 2 decoded=' ' + do nerase=0,ne2,2 + call rs_decode(mrsym,era,nerase,dat4,ncount) + if(ncount.ge.0) then + call unpackmsg(dat4,decoded) + go to 900 + endif + enddo + endif + + 900 return + end diff --git a/libm65/fchisq.f b/libm65/fchisq.f index 190112b99..f4c17d79c 100644 --- a/libm65/fchisq.f +++ b/libm65/fchisq.f @@ -1,76 +1,76 @@ - real function fchisq(cx,cy,npts,fsample,nflip,a,ccfmax,dtmax) - - parameter (NMAX=60*96000) !Samples per 60 s - complex cx(npts),cy(npts) - real a(5) - complex w,wstep,za,zb,z - real ss(2600) - complex csx(0:NMAX/64),csy(0:NMAX/64) - data twopi/6.283185307/a1,a2,a3/99.,99.,99./ - save - - call timer('fchisq ',0) - baud=11025.0/4096.0 - if(a(1).ne.a1 .or. a(2).ne.a2 .or. a(3).ne.a3) then - a1=a(1) - a2=a(2) - a3=a(3) - -C Mix and integrate the complex X and Y signals - csx(0)=0. - csy(0)=0. - w=1.0 - x0=0.5*(npts+1) - s=2.0/npts - do i=1,npts - x=s*(i-x0) - if(mod(i,100).eq.1) then - p2=1.5*x*x - 0.5 -! p3=2.5*(x**3) - 1.5*x -! p4=4.375*(x**4) - 3.75*(x**2) + 0.375 - dphi=(a(1) + x*a(2) + p2*a(3)) * (twopi/fsample) - wstep=cmplx(cos(dphi),sin(dphi)) - endif - w=w*wstep - csx(i)=csx(i-1) + w*cx(i) - csy(i)=csy(i-1) + w*cy(i) - enddo - endif - -C Compute 1/2-symbol powers at 1/16-symbol steps. - fac=1.e-4 - pol=a(4)/57.2957795 - aa=cos(pol) - bb=sin(pol) - nsps=nint(fsample/baud) !Samples per symbol - nsph=nsps/2 !Samples per half-symbol - - ndiv=16 !Output ss() steps per symbol - nout=ndiv*npts/nsps - dtstep=1.0/(ndiv*baud) !Time per output step - - do i=1,nout - j=i*nsps/ndiv - k=j-nsph - ss(i)=0. - if(k.ge.1) then - za=csx(j)-csx(k) - zb=csy(j)-csy(k) - z=aa*za + bb*zb - ss(i)=fac*(real(z)**2 + aimag(z)**2) - endif - enddo - - ccfmax=0. - call timer('ccf2 ',0) - call ccf2(ss,nout,nflip,ccf,lagpk) - call timer('ccf2 ',1) - if(ccf.gt.ccfmax) then - ccfmax=ccf - dtmax=lagpk*dtstep - endif - fchisq=-ccfmax - - call timer('fchisq ',1) - return - end + real function fchisq(cx,cy,npts,fsample,nflip,a,ccfmax,dtmax) + + parameter (NMAX=60*96000) !Samples per 60 s + complex cx(npts),cy(npts) + real a(5) + complex w,wstep,za,zb,z + real ss(2600) + complex csx(0:NMAX/64),csy(0:NMAX/64) + data twopi/6.283185307/a1,a2,a3/99.,99.,99./ + save + + call timer('fchisq ',0) + baud=11025.0/4096.0 + if(a(1).ne.a1 .or. a(2).ne.a2 .or. a(3).ne.a3) then + a1=a(1) + a2=a(2) + a3=a(3) + +C Mix and integrate the complex X and Y signals + csx(0)=0. + csy(0)=0. + w=1.0 + x0=0.5*(npts+1) + s=2.0/npts + do i=1,npts + x=s*(i-x0) + if(mod(i,100).eq.1) then + p2=1.5*x*x - 0.5 +! p3=2.5*(x**3) - 1.5*x +! p4=4.375*(x**4) - 3.75*(x**2) + 0.375 + dphi=(a(1) + x*a(2) + p2*a(3)) * (twopi/fsample) + wstep=cmplx(cos(dphi),sin(dphi)) + endif + w=w*wstep + csx(i)=csx(i-1) + w*cx(i) + csy(i)=csy(i-1) + w*cy(i) + enddo + endif + +C Compute 1/2-symbol powers at 1/16-symbol steps. + fac=1.e-4 + pol=a(4)/57.2957795 + aa=cos(pol) + bb=sin(pol) + nsps=nint(fsample/baud) !Samples per symbol + nsph=nsps/2 !Samples per half-symbol + + ndiv=16 !Output ss() steps per symbol + nout=ndiv*npts/nsps + dtstep=1.0/(ndiv*baud) !Time per output step + + do i=1,nout + j=i*nsps/ndiv + k=j-nsph + ss(i)=0. + if(k.ge.1) then + za=csx(j)-csx(k) + zb=csy(j)-csy(k) + z=aa*za + bb*zb + ss(i)=fac*(real(z)**2 + aimag(z)**2) + endif + enddo + + ccfmax=0. + call timer('ccf2 ',0) + call ccf2(ss,nout,nflip,ccf,lagpk) + call timer('ccf2 ',1) + if(ccf.gt.ccfmax) then + ccfmax=ccf + dtmax=lagpk*dtstep + endif + fchisq=-ccfmax + + call timer('fchisq ',1) + return + end diff --git a/libm65/fftw3.f b/libm65/fftw3.f index 90748b2fd..3410184ca 100644 --- a/libm65/fftw3.f +++ b/libm65/fftw3.f @@ -1,64 +1,64 @@ - INTEGER FFTW_R2HC - PARAMETER (FFTW_R2HC=0) - INTEGER FFTW_HC2R - PARAMETER (FFTW_HC2R=1) - INTEGER FFTW_DHT - PARAMETER (FFTW_DHT=2) - INTEGER FFTW_REDFT00 - PARAMETER (FFTW_REDFT00=3) - INTEGER FFTW_REDFT01 - PARAMETER (FFTW_REDFT01=4) - INTEGER FFTW_REDFT10 - PARAMETER (FFTW_REDFT10=5) - INTEGER FFTW_REDFT11 - PARAMETER (FFTW_REDFT11=6) - INTEGER FFTW_RODFT00 - PARAMETER (FFTW_RODFT00=7) - INTEGER FFTW_RODFT01 - PARAMETER (FFTW_RODFT01=8) - INTEGER FFTW_RODFT10 - PARAMETER (FFTW_RODFT10=9) - INTEGER FFTW_RODFT11 - PARAMETER (FFTW_RODFT11=10) - INTEGER FFTW_FORWARD - PARAMETER (FFTW_FORWARD=-1) - INTEGER FFTW_BACKWARD - PARAMETER (FFTW_BACKWARD=+1) - INTEGER FFTW_MEASURE - PARAMETER (FFTW_MEASURE=0) - INTEGER FFTW_DESTROY_INPUT - PARAMETER (FFTW_DESTROY_INPUT=1) - INTEGER FFTW_UNALIGNED - PARAMETER (FFTW_UNALIGNED=2) - INTEGER FFTW_CONSERVE_MEMORY - PARAMETER (FFTW_CONSERVE_MEMORY=4) - INTEGER FFTW_EXHAUSTIVE - PARAMETER (FFTW_EXHAUSTIVE=8) - INTEGER FFTW_PRESERVE_INPUT - PARAMETER (FFTW_PRESERVE_INPUT=16) - INTEGER FFTW_PATIENT - PARAMETER (FFTW_PATIENT=32) - INTEGER FFTW_ESTIMATE - PARAMETER (FFTW_ESTIMATE=64) - INTEGER FFTW_ESTIMATE_PATIENT - PARAMETER (FFTW_ESTIMATE_PATIENT=128) - INTEGER FFTW_BELIEVE_PCOST - PARAMETER (FFTW_BELIEVE_PCOST=256) - INTEGER FFTW_DFT_R2HC_ICKY - PARAMETER (FFTW_DFT_R2HC_ICKY=512) - INTEGER FFTW_NONTHREADED_ICKY - PARAMETER (FFTW_NONTHREADED_ICKY=1024) - INTEGER FFTW_NO_BUFFERING - PARAMETER (FFTW_NO_BUFFERING=2048) - INTEGER FFTW_NO_INDIRECT_OP - PARAMETER (FFTW_NO_INDIRECT_OP=4096) - INTEGER FFTW_ALLOW_LARGE_GENERIC - PARAMETER (FFTW_ALLOW_LARGE_GENERIC=8192) - INTEGER FFTW_NO_RANK_SPLITS - PARAMETER (FFTW_NO_RANK_SPLITS=16384) - INTEGER FFTW_NO_VRANK_SPLITS - PARAMETER (FFTW_NO_VRANK_SPLITS=32768) - INTEGER FFTW_NO_VRECURSE - PARAMETER (FFTW_NO_VRECURSE=65536) - INTEGER FFTW_NO_SIMD - PARAMETER (FFTW_NO_SIMD=131072) + INTEGER FFTW_R2HC + PARAMETER (FFTW_R2HC=0) + INTEGER FFTW_HC2R + PARAMETER (FFTW_HC2R=1) + INTEGER FFTW_DHT + PARAMETER (FFTW_DHT=2) + INTEGER FFTW_REDFT00 + PARAMETER (FFTW_REDFT00=3) + INTEGER FFTW_REDFT01 + PARAMETER (FFTW_REDFT01=4) + INTEGER FFTW_REDFT10 + PARAMETER (FFTW_REDFT10=5) + INTEGER FFTW_REDFT11 + PARAMETER (FFTW_REDFT11=6) + INTEGER FFTW_RODFT00 + PARAMETER (FFTW_RODFT00=7) + INTEGER FFTW_RODFT01 + PARAMETER (FFTW_RODFT01=8) + INTEGER FFTW_RODFT10 + PARAMETER (FFTW_RODFT10=9) + INTEGER FFTW_RODFT11 + PARAMETER (FFTW_RODFT11=10) + INTEGER FFTW_FORWARD + PARAMETER (FFTW_FORWARD=-1) + INTEGER FFTW_BACKWARD + PARAMETER (FFTW_BACKWARD=+1) + INTEGER FFTW_MEASURE + PARAMETER (FFTW_MEASURE=0) + INTEGER FFTW_DESTROY_INPUT + PARAMETER (FFTW_DESTROY_INPUT=1) + INTEGER FFTW_UNALIGNED + PARAMETER (FFTW_UNALIGNED=2) + INTEGER FFTW_CONSERVE_MEMORY + PARAMETER (FFTW_CONSERVE_MEMORY=4) + INTEGER FFTW_EXHAUSTIVE + PARAMETER (FFTW_EXHAUSTIVE=8) + INTEGER FFTW_PRESERVE_INPUT + PARAMETER (FFTW_PRESERVE_INPUT=16) + INTEGER FFTW_PATIENT + PARAMETER (FFTW_PATIENT=32) + INTEGER FFTW_ESTIMATE + PARAMETER (FFTW_ESTIMATE=64) + INTEGER FFTW_ESTIMATE_PATIENT + PARAMETER (FFTW_ESTIMATE_PATIENT=128) + INTEGER FFTW_BELIEVE_PCOST + PARAMETER (FFTW_BELIEVE_PCOST=256) + INTEGER FFTW_DFT_R2HC_ICKY + PARAMETER (FFTW_DFT_R2HC_ICKY=512) + INTEGER FFTW_NONTHREADED_ICKY + PARAMETER (FFTW_NONTHREADED_ICKY=1024) + INTEGER FFTW_NO_BUFFERING + PARAMETER (FFTW_NO_BUFFERING=2048) + INTEGER FFTW_NO_INDIRECT_OP + PARAMETER (FFTW_NO_INDIRECT_OP=4096) + INTEGER FFTW_ALLOW_LARGE_GENERIC + PARAMETER (FFTW_ALLOW_LARGE_GENERIC=8192) + INTEGER FFTW_NO_RANK_SPLITS + PARAMETER (FFTW_NO_RANK_SPLITS=16384) + INTEGER FFTW_NO_VRANK_SPLITS + PARAMETER (FFTW_NO_VRANK_SPLITS=32768) + INTEGER FFTW_NO_VRECURSE + PARAMETER (FFTW_NO_VRECURSE=65536) + INTEGER FFTW_NO_SIMD + PARAMETER (FFTW_NO_SIMD=131072) diff --git a/libm65/fil6521.f b/libm65/fil6521.f index e962203eb..32feb8f44 100644 --- a/libm65/fil6521.f +++ b/libm65/fil6521.f @@ -1,44 +1,44 @@ - subroutine fil6521(c1,n1,c2,n2) - -C FIR lowpass filter designed using ScopeFIR - -C Pass #1 Pass #2 -C----------------------------------------------- -C fsample (Hz) 1378.125 Input sample rate -C Ntaps 21 Number of filter taps -C fc (Hz) 40 Cutoff frequency -C fstop (Hz) 172.266 Lower limit of stopband -C Ripple (dB) 0.1 Ripple in passband -C Stop Atten (dB) 38 Stopband attenuation -C fout (Hz) 344.531 Output sample rate - - parameter (NTAPS=21) - parameter (NH=NTAPS/2) - parameter (NDOWN=4) !Downsample ratio = 1/4 - complex c1(n1) - complex c2(n1/NDOWN) - -C Filter coefficients: - real a(-NH:NH) - data a/ - + -0.011958606980,-0.013888627387,-0.015601306443,-0.010602249570, - + 0.003804023436, 0.028320058273, 0.060903935217, 0.096841904411, - + 0.129639871228, 0.152644580853, 0.160917511283, 0.152644580853, - + 0.129639871228, 0.096841904411, 0.060903935217, 0.028320058273, - + 0.003804023436,-0.010602249570,-0.015601306443,-0.013888627387, - + -0.011958606980/ - - n2=(n1-NTAPS+NDOWN)/NDOWN - k0=NH-NDOWN+1 - -C Loop over all output samples - do i=1,n2 - c2(i)=0. - k=k0 + NDOWN*i - do j=-NH,NH - c2(i)=c2(i) + c1(j+k)*a(j) - enddo - enddo - - return - end + subroutine fil6521(c1,n1,c2,n2) + +C FIR lowpass filter designed using ScopeFIR + +C Pass #1 Pass #2 +C----------------------------------------------- +C fsample (Hz) 1378.125 Input sample rate +C Ntaps 21 Number of filter taps +C fc (Hz) 40 Cutoff frequency +C fstop (Hz) 172.266 Lower limit of stopband +C Ripple (dB) 0.1 Ripple in passband +C Stop Atten (dB) 38 Stopband attenuation +C fout (Hz) 344.531 Output sample rate + + parameter (NTAPS=21) + parameter (NH=NTAPS/2) + parameter (NDOWN=4) !Downsample ratio = 1/4 + complex c1(n1) + complex c2(n1/NDOWN) + +C Filter coefficients: + real a(-NH:NH) + data a/ + + -0.011958606980,-0.013888627387,-0.015601306443,-0.010602249570, + + 0.003804023436, 0.028320058273, 0.060903935217, 0.096841904411, + + 0.129639871228, 0.152644580853, 0.160917511283, 0.152644580853, + + 0.129639871228, 0.096841904411, 0.060903935217, 0.028320058273, + + 0.003804023436,-0.010602249570,-0.015601306443,-0.013888627387, + + -0.011958606980/ + + n2=(n1-NTAPS+NDOWN)/NDOWN + k0=NH-NDOWN+1 + +C Loop over all output samples + do i=1,n2 + c2(i)=0. + k=k0 + NDOWN*i + do j=-NH,NH + c2(i)=c2(i) + c1(j+k)*a(j) + enddo + enddo + + return + end diff --git a/libm65/filbig.f b/libm65/filbig.f index 23c4b1004..60206ddce 100644 --- a/libm65/filbig.f +++ b/libm65/filbig.f @@ -1,134 +1,134 @@ - subroutine filbig(dd,nmax,f0,newdat,nfsample,xpol,c4a,c4b,n4) - -C Filter and downsample complex data stored in array dd(4,nmax). -C Output is downsampled from 96000 Hz to 1375.125 Hz. - - parameter (MAXFFT1=5376000,MAXFFT2=77175) - real*4 dd(4,nmax) !Input data - complex ca(MAXFFT1),cb(MAXFFT1) !FFTs of input - complex c4a(MAXFFT2),c4b(MAXFFT2) !Output data - real*8 df - real halfpulse(8) !Impulse response of filter (one sided) - complex cfilt(MAXFFT2) !Filter (complex; imag = 0) - real rfilt(MAXFFT2) !Filter (real) - integer*8 plan1,plan2,plan3,plan4,plan5 - logical first,xpol - include 'fftw3.f' - equivalence (rfilt,cfilt) - data first/.true./,npatience/1/ - data halfpulse/114.97547150,36.57879257,-20.93789101, - + 5.89886379,1.59355187,-2.49138308,0.60910773,-0.04248129/ - save - - nfft1=MAXFFT1 - nfft2=MAXFFT2 - if(nfsample.eq.95238) then - nfft1=5120000 - nfft2=74088 - endif - if(nmax.lt.0) go to 900 - if(first) then - nflags=FFTW_ESTIMATE - if(npatience.eq.1) nflags=FFTW_ESTIMATE_PATIENT - if(npatience.eq.2) nflags=FFTW_MEASURE - if(npatience.eq.3) nflags=FFTW_PATIENT - if(npatience.eq.4) nflags=FFTW_EXHAUSTIVE -C Plan the FFTs just once - call timer('FFTplans ',0) - call sfftw_plan_dft_1d(plan1,nfft1,ca,ca, - + FFTW_BACKWARD,nflags) - call sfftw_plan_dft_1d(plan2,nfft1,cb,cb, - + FFTW_BACKWARD,nflags) - call sfftw_plan_dft_1d(plan3,nfft2,c4a,c4a, - + FFTW_FORWARD,nflags) - call sfftw_plan_dft_1d(plan4,nfft2,c4b,c4b, - + FFTW_FORWARD,nflags) - call sfftw_plan_dft_1d(plan5,nfft2,cfilt,cfilt, - + FFTW_BACKWARD,nflags) - call timer('FFTplans ',1) - -C Convert impulse response to filter function - do i=1,nfft2 - cfilt(i)=0. - enddo - fac=0.00625/nfft1 - cfilt(1)=fac*halfpulse(1) - do i=2,8 - cfilt(i)=fac*halfpulse(i) - cfilt(nfft2+2-i)=fac*halfpulse(i) - enddo - call timer('FFTfilt ',0) - call sfftw_execute(plan5) - call timer('FFTfilt ',1) - - base=cfilt(nfft2/2+1) - do i=1,nfft2 - rfilt(i)=real(cfilt(i))-base - enddo - - df=96000.d0/nfft1 - if(nfsample.eq.95238) df=95238.1d0/nfft1 - first=.false. - endif - -C When new data comes along, we need to compute a new "big FFT" -C If we just have a new f0, continue with the existing ca and cb. - - if(newdat.ne.0) then - nz=min(nmax,nfft1) - do i=1,nz - ca(i)=cmplx(dd(1,i),dd(2,i)) - if(xpol) cb(i)=cmplx(dd(3,i),dd(4,i)) - enddo - - if(nmax.lt.nfft1) then - do i=nmax+1,nfft1 - ca(i)=0. - if(xpol) cb(i)=0. - enddo - endif - call timer('FFTbig ',0) - call sfftw_execute(plan1) - if(xpol) call sfftw_execute(plan2) - call timer('FFTbig ',1) - newdat=0 - endif - -C NB: f0 is the frequency at which we want our filter centered. -C i0 is the bin number in ca and cb closest to f0. - - i0=nint(f0/df) + 1 - nh=nfft2/2 - do i=1,nh !Copy data into c4a and c4b, - j=i0+i-1 !and apply the filter function - if(j.ge.1 .and. j.le.nfft1) then - c4a(i)=rfilt(i)*ca(j) - if(xpol) c4b(i)=rfilt(i)*cb(j) - else - c4a(i)=0. - if(xpol) c4b(i)=0. - endif - enddo - do i=nh+1,nfft2 - j=i0+i-1-nfft2 - if(j.lt.1) j=j+nfft1 !nfft1 was nfft2 - c4a(i)=rfilt(i)*ca(j) - if(xpol) c4b(i)=rfilt(i)*cb(j) - enddo - -C Do the short reverse transform, to go back to time domain. - call timer('FFTsmall',0) - call sfftw_execute(plan3) - if(xpol) call sfftw_execute(plan4) - call timer('FFTsmall',1) - n4=min(nmax/64,nfft2) - go to 999 - - 900 call sfftw_destroy_plan(plan1) - call sfftw_destroy_plan(plan2) - call sfftw_destroy_plan(plan3) - call sfftw_destroy_plan(plan4) - call sfftw_destroy_plan(plan5) - - 999 return - end + subroutine filbig(dd,nmax,f0,newdat,nfsample,xpol,c4a,c4b,n4) + +C Filter and downsample complex data stored in array dd(4,nmax). +C Output is downsampled from 96000 Hz to 1375.125 Hz. + + parameter (MAXFFT1=5376000,MAXFFT2=77175) + real*4 dd(4,nmax) !Input data + complex ca(MAXFFT1),cb(MAXFFT1) !FFTs of input + complex c4a(MAXFFT2),c4b(MAXFFT2) !Output data + real*8 df + real halfpulse(8) !Impulse response of filter (one sided) + complex cfilt(MAXFFT2) !Filter (complex; imag = 0) + real rfilt(MAXFFT2) !Filter (real) + integer*8 plan1,plan2,plan3,plan4,plan5 + logical first,xpol + include 'fftw3.f' + equivalence (rfilt,cfilt) + data first/.true./,npatience/1/ + data halfpulse/114.97547150,36.57879257,-20.93789101, + + 5.89886379,1.59355187,-2.49138308,0.60910773,-0.04248129/ + save + + nfft1=MAXFFT1 + nfft2=MAXFFT2 + if(nfsample.eq.95238) then + nfft1=5120000 + nfft2=74088 + endif + if(nmax.lt.0) go to 900 + if(first) then + nflags=FFTW_ESTIMATE + if(npatience.eq.1) nflags=FFTW_ESTIMATE_PATIENT + if(npatience.eq.2) nflags=FFTW_MEASURE + if(npatience.eq.3) nflags=FFTW_PATIENT + if(npatience.eq.4) nflags=FFTW_EXHAUSTIVE +C Plan the FFTs just once + call timer('FFTplans ',0) + call sfftw_plan_dft_1d(plan1,nfft1,ca,ca, + + FFTW_BACKWARD,nflags) + call sfftw_plan_dft_1d(plan2,nfft1,cb,cb, + + FFTW_BACKWARD,nflags) + call sfftw_plan_dft_1d(plan3,nfft2,c4a,c4a, + + FFTW_FORWARD,nflags) + call sfftw_plan_dft_1d(plan4,nfft2,c4b,c4b, + + FFTW_FORWARD,nflags) + call sfftw_plan_dft_1d(plan5,nfft2,cfilt,cfilt, + + FFTW_BACKWARD,nflags) + call timer('FFTplans ',1) + +C Convert impulse response to filter function + do i=1,nfft2 + cfilt(i)=0. + enddo + fac=0.00625/nfft1 + cfilt(1)=fac*halfpulse(1) + do i=2,8 + cfilt(i)=fac*halfpulse(i) + cfilt(nfft2+2-i)=fac*halfpulse(i) + enddo + call timer('FFTfilt ',0) + call sfftw_execute(plan5) + call timer('FFTfilt ',1) + + base=cfilt(nfft2/2+1) + do i=1,nfft2 + rfilt(i)=real(cfilt(i))-base + enddo + + df=96000.d0/nfft1 + if(nfsample.eq.95238) df=95238.1d0/nfft1 + first=.false. + endif + +C When new data comes along, we need to compute a new "big FFT" +C If we just have a new f0, continue with the existing ca and cb. + + if(newdat.ne.0) then + nz=min(nmax,nfft1) + do i=1,nz + ca(i)=cmplx(dd(1,i),dd(2,i)) + if(xpol) cb(i)=cmplx(dd(3,i),dd(4,i)) + enddo + + if(nmax.lt.nfft1) then + do i=nmax+1,nfft1 + ca(i)=0. + if(xpol) cb(i)=0. + enddo + endif + call timer('FFTbig ',0) + call sfftw_execute(plan1) + if(xpol) call sfftw_execute(plan2) + call timer('FFTbig ',1) + newdat=0 + endif + +C NB: f0 is the frequency at which we want our filter centered. +C i0 is the bin number in ca and cb closest to f0. + + i0=nint(f0/df) + 1 + nh=nfft2/2 + do i=1,nh !Copy data into c4a and c4b, + j=i0+i-1 !and apply the filter function + if(j.ge.1 .and. j.le.nfft1) then + c4a(i)=rfilt(i)*ca(j) + if(xpol) c4b(i)=rfilt(i)*cb(j) + else + c4a(i)=0. + if(xpol) c4b(i)=0. + endif + enddo + do i=nh+1,nfft2 + j=i0+i-1-nfft2 + if(j.lt.1) j=j+nfft1 !nfft1 was nfft2 + c4a(i)=rfilt(i)*ca(j) + if(xpol) c4b(i)=rfilt(i)*cb(j) + enddo + +C Do the short reverse transform, to go back to time domain. + call timer('FFTsmall',0) + call sfftw_execute(plan3) + if(xpol) call sfftw_execute(plan4) + call timer('FFTsmall',1) + n4=min(nmax/64,nfft2) + go to 999 + + 900 call sfftw_destroy_plan(plan1) + call sfftw_destroy_plan(plan2) + call sfftw_destroy_plan(plan3) + call sfftw_destroy_plan(plan4) + call sfftw_destroy_plan(plan5) + + 999 return + end diff --git a/libm65/four2a.f90 b/libm65/four2a.f90 index a132d7389..01a4605f9 100644 --- a/libm65/four2a.f90 +++ b/libm65/four2a.f90 @@ -1,89 +1,89 @@ -subroutine four2a(a,nfft,ndim,isign,iform) - -! IFORM = 1, 0 or -1, as data is -! complex, real, or the first half of a complex array. Transform -! values are returned in array DATA. They are complex, real, or -! the first half of a complex array, as IFORM = 1, -1 or 0. - -! The transform of a real array (IFORM = 0) dimensioned N(1) by N(2) -! by ... will be returned in the same array, now considered to -! be complex of dimensions N(1)/2+1 by N(2) by .... Note that if -! IFORM = 0 or -1, N(1) must be even, and enough room must be -! reserved. The missing values may be obtained by complex conjugation. - -! The reverse transformation of a half complex array dimensioned -! N(1)/2+1 by N(2) by ..., is accomplished by setting IFORM -! to -1. In the N array, N(1) must be the true N(1), not N(1)/2+1. -! The transform will be real and returned to the input array. - - parameter (NPMAX=100) - parameter (NSMALL=16384) - complex a(nfft) - complex aa(NSMALL) - integer nn(NPMAX),ns(NPMAX),nf(NPMAX),nl(NPMAX) - integer*8 plan(NPMAX) !Actually should be i*8, but no matter - data nplan/0/,npatience/1/ - include 'fftw3.f' - save plan,nplan,nn,ns,nf,nl - - if(nfft.lt.0) go to 999 - - nloc=loc(a) - do i=1,nplan - if(nfft.eq.nn(i) .and. isign.eq.ns(i) .and. & - iform.eq.nf(i) .and. nloc.eq.nl(i)) go to 10 - enddo - if(nplan.ge.NPMAX) stop 'Too many FFTW plans requested.' - nplan=nplan+1 - i=nplan - nn(i)=nfft - ns(i)=isign - nf(i)=iform - nl(i)=nloc - -! Planning: FFTW_ESTIMATE, FFTW_ESTIMATE_PATIENT, FFTW_MEASURE, -! FFTW_PATIENT, FFTW_EXHAUSTIVE - nflags=FFTW_ESTIMATE - if(npatience.eq.1) nflags=FFTW_ESTIMATE_PATIENT - if(npatience.eq.2) nflags=FFTW_MEASURE - if(npatience.eq.3) nflags=FFTW_PATIENT - if(npatience.eq.4) nflags=FFTW_EXHAUSTIVE - - if(nfft.le.NSMALL) then - jz=nfft - if(iform.eq.0) jz=nfft/2 - do j=1,jz - aa(j)=a(j) - enddo - endif - if(isign.eq.-1 .and. iform.eq.1) then - call sfftw_plan_dft_1d(plan(i),nfft,a,a,FFTW_FORWARD,nflags) - else if(isign.eq.1 .and. iform.eq.1) then - call sfftw_plan_dft_1d(plan(i),nfft,a,a,FFTW_BACKWARD,nflags) - else if(isign.eq.-1 .and. iform.eq.0) then - call sfftw_plan_dft_r2c_1d(plan(i),nfft,a,a,nflags) - else if(isign.eq.1 .and. iform.eq.-1) then - call sfftw_plan_dft_c2r_1d(plan(i),nfft,a,a,nflags) - else - stop 'Unsupported request in four2a' - endif - i=nplan - if(nfft.le.NSMALL) then - jz=nfft - if(iform.eq.0) jz=nfft/2 - do j=1,jz - a(j)=aa(j) - enddo - endif - -10 continue - call sfftw_execute(plan(i)) - return - -999 do i=1,nplan -! The test is only to silence a compiler warning: - if(ndim.ne.-999) call sfftw_destroy_plan(plan(i)) - enddo - - return -end subroutine four2a +subroutine four2a(a,nfft,ndim,isign,iform) + +! IFORM = 1, 0 or -1, as data is +! complex, real, or the first half of a complex array. Transform +! values are returned in array DATA. They are complex, real, or +! the first half of a complex array, as IFORM = 1, -1 or 0. + +! The transform of a real array (IFORM = 0) dimensioned N(1) by N(2) +! by ... will be returned in the same array, now considered to +! be complex of dimensions N(1)/2+1 by N(2) by .... Note that if +! IFORM = 0 or -1, N(1) must be even, and enough room must be +! reserved. The missing values may be obtained by complex conjugation. + +! The reverse transformation of a half complex array dimensioned +! N(1)/2+1 by N(2) by ..., is accomplished by setting IFORM +! to -1. In the N array, N(1) must be the true N(1), not N(1)/2+1. +! The transform will be real and returned to the input array. + + parameter (NPMAX=100) + parameter (NSMALL=16384) + complex a(nfft) + complex aa(NSMALL) + integer nn(NPMAX),ns(NPMAX),nf(NPMAX),nl(NPMAX) + integer*8 plan(NPMAX) !Actually should be i*8, but no matter + data nplan/0/,npatience/1/ + include 'fftw3.f' + save plan,nplan,nn,ns,nf,nl + + if(nfft.lt.0) go to 999 + + nloc=loc(a) + do i=1,nplan + if(nfft.eq.nn(i) .and. isign.eq.ns(i) .and. & + iform.eq.nf(i) .and. nloc.eq.nl(i)) go to 10 + enddo + if(nplan.ge.NPMAX) stop 'Too many FFTW plans requested.' + nplan=nplan+1 + i=nplan + nn(i)=nfft + ns(i)=isign + nf(i)=iform + nl(i)=nloc + +! Planning: FFTW_ESTIMATE, FFTW_ESTIMATE_PATIENT, FFTW_MEASURE, +! FFTW_PATIENT, FFTW_EXHAUSTIVE + nflags=FFTW_ESTIMATE + if(npatience.eq.1) nflags=FFTW_ESTIMATE_PATIENT + if(npatience.eq.2) nflags=FFTW_MEASURE + if(npatience.eq.3) nflags=FFTW_PATIENT + if(npatience.eq.4) nflags=FFTW_EXHAUSTIVE + + if(nfft.le.NSMALL) then + jz=nfft + if(iform.eq.0) jz=nfft/2 + do j=1,jz + aa(j)=a(j) + enddo + endif + if(isign.eq.-1 .and. iform.eq.1) then + call sfftw_plan_dft_1d(plan(i),nfft,a,a,FFTW_FORWARD,nflags) + else if(isign.eq.1 .and. iform.eq.1) then + call sfftw_plan_dft_1d(plan(i),nfft,a,a,FFTW_BACKWARD,nflags) + else if(isign.eq.-1 .and. iform.eq.0) then + call sfftw_plan_dft_r2c_1d(plan(i),nfft,a,a,nflags) + else if(isign.eq.1 .and. iform.eq.-1) then + call sfftw_plan_dft_c2r_1d(plan(i),nfft,a,a,nflags) + else + stop 'Unsupported request in four2a' + endif + i=nplan + if(nfft.le.NSMALL) then + jz=nfft + if(iform.eq.0) jz=nfft/2 + do j=1,jz + a(j)=aa(j) + enddo + endif + +10 continue + call sfftw_execute(plan(i)) + return + +999 do i=1,nplan +! The test is only to silence a compiler warning: + if(ndim.ne.-999) call sfftw_destroy_plan(plan(i)) + enddo + + return +end subroutine four2a diff --git a/libm65/ftninit.f90 b/libm65/ftninit.f90 index a94cd866e..9a9a2f950 100644 --- a/libm65/ftninit.f90 +++ b/libm65/ftninit.f90 @@ -1,63 +1,63 @@ -! Fortran logical units used in WSJT6 -! -! 10 binary input data, *.tf2 files -! 11 prefixes.txt -! 12 timer.out -! 13 map65.log -! 14 -! 15 -! 16 -! 17 saved *.tf2 files -! 18 test file to be transmitted (wsjtgen.f90) -! 19 livecq.txt -! 20 -! 21 map65_rx.log -! 22 kvasd.dat -! 23 CALL3.TXT -! 24 -! 25 -! 26 tmp26.txt -! 27 -! 28 fftw_wisdom.dat -!------------------------------------------------ ftn_init -subroutine ftninit(appd) - - character*(*) appd - character cjunk*1,firstline*30 - character addpfx*8 - integer junk(256) - common/pfxcom/addpfx - - addpfx=' ' - call pfxdump(appd//'/prefixes.txt') - open(12,file=appd//'/timer.out',status='unknown',err=920) - open(13,file=appd//'/map65.log',status='unknown') - open(19,file=appd//'/livecq.txt',status='unknown') - open(21,file=appd//'/map65_rx.log',status='unknown',access='append',err=950) - open(22,file=appd//'/kvasd.dat',access='direct',recl=1024,status='unknown') - read(22,rec=2,err=12) junk - go to 18 -12 junk=0 - write(22,rec=1) junk - write(22,rec=2) junk - -18 open(26,file=appd//'/tmp26.txt',status='unknown') - -! Import FFTW wisdom, if available: - open(28,file=appd//'/fftwf_wisdom.dat',status='old',err=30) - read(28,1000,err=30,end=30) firstline -1000 format(a30) - rewind 28 - call import_wisdom_from_file(isuccess,28) - close(28) - if(isuccess.ne.0) write(13,1010) firstline -1010 format('Imported FFTW wisdom: ',a30) - -30 return - -920 write(0,*) '!Error opening timer.out' - stop -950 write(0,*) '!Error opening ALL65.TXT' - stop - -end subroutine ftninit +! Fortran logical units used in WSJT6 +! +! 10 binary input data, *.tf2 files +! 11 prefixes.txt +! 12 timer.out +! 13 map65.log +! 14 +! 15 +! 16 +! 17 saved *.tf2 files +! 18 test file to be transmitted (wsjtgen.f90) +! 19 livecq.txt +! 20 +! 21 map65_rx.log +! 22 kvasd.dat +! 23 CALL3.TXT +! 24 +! 25 +! 26 tmp26.txt +! 27 +! 28 fftw_wisdom.dat +!------------------------------------------------ ftn_init +subroutine ftninit(appd) + + character*(*) appd + character cjunk*1,firstline*30 + character addpfx*8 + integer junk(256) + common/pfxcom/addpfx + + addpfx=' ' + call pfxdump(appd//'/prefixes.txt') + open(12,file=appd//'/timer.out',status='unknown',err=920) + open(13,file=appd//'/map65.log',status='unknown') + open(19,file=appd//'/livecq.txt',status='unknown') + open(21,file=appd//'/map65_rx.log',status='unknown',access='append',err=950) + open(22,file=appd//'/kvasd.dat',access='direct',recl=1024,status='unknown') + read(22,rec=2,err=12) junk + go to 18 +12 junk=0 + write(22,rec=1) junk + write(22,rec=2) junk + +18 open(26,file=appd//'/tmp26.txt',status='unknown') + +! Import FFTW wisdom, if available: + open(28,file=appd//'/fftwf_wisdom.dat',status='old',err=30) + read(28,1000,err=30,end=30) firstline +1000 format(a30) + rewind 28 + call import_wisdom_from_file(isuccess,28) + close(28) + if(isuccess.ne.0) write(13,1010) firstline +1010 format('Imported FFTW wisdom: ',a30) + +30 return + +920 write(0,*) '!Error opening timer.out' + stop +950 write(0,*) '!Error opening ALL65.TXT' + stop + +end subroutine ftninit diff --git a/libm65/ftnquit.f90 b/libm65/ftnquit.f90 index d3a63dcbe..f209d1b4b 100644 --- a/libm65/ftnquit.f90 +++ b/libm65/ftnquit.f90 @@ -1,9 +1,9 @@ -subroutine ftnquit - -! Destroy the FFTW plans - call four2a(a,-1,1,1,1) - call filbig(id,-1,f0,newdat,nfsample,c4a,c4b,n4) - stop - - return -end subroutine ftnquit +subroutine ftnquit + +! Destroy the FFTW plans + call four2a(a,-1,1,1,1) + call filbig(id,-1,f0,newdat,nfsample,c4a,c4b,n4) + stop + + return +end subroutine ftnquit diff --git a/libm65/gen65.f90 b/libm65/gen65.f90 index 56e4c48bc..92c45e7fe 100644 --- a/libm65/gen65.f90 +++ b/libm65/gen65.f90 @@ -1,93 +1,93 @@ -subroutine gen65(message,mode65,samfac,nsendingsh,msgsent,iwave,nwave) - -! Encodes a JT65 message into a wavefile. -! Executes in 17 ms on opti-745. - - parameter (NMAX=60*11025) !Max length of wave file - character*22 message !Message to be generated - character*22 msgsent !Message as it will be received - character*3 cok !' ' or 'OOO' - real*8 dt,phi,f,f0,dfgen,dphi,twopi,samfac - integer*2 iwave(NMAX) !Generated wave file - integer dgen(12) - integer sent(63) - logical first - integer nprc(126) - real pr(126) - data nprc/1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0, & - 0,1,0,1,1,0,0,1,0,0,0,1,1,1,0,0,1,1,1,1, & - 0,1,1,0,1,1,1,1,0,0,0,1,1,0,1,0,1,0,1,1, & - 0,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,1, & - 1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1, & - 0,1,0,1,0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,1, & - 1,1,1,1,1,1/ - data twopi/6.283185307179586476d0/,first/.true./ - save - - if(first) then - do i=1,126 - pr(i)=2*nprc(i)-1 - enddo - first=.false. - endif - - call chkmsg(message,cok,nspecial,flip) - if(nspecial.eq.0) then - call packmsg(message,dgen) !Pack message into 72 bits - nsendingsh=0 - if(iand(dgen(10),8).ne.0) nsendingsh=-1 !Plain text flag - - call rs_encode(dgen,sent) - call interleave63(sent,1) !Apply interleaving - call graycode(sent,63,1) !Apply Gray code - nsym=126 !Symbols per transmission - nsps=4096 - else - nsym=32 - nsps=16384 - nsendingsh=1 !Flag for shorthand message - endif - if(mode65.eq.0) go to 900 - -! Set up necessary constants - dt=1.d0/(samfac*11025.d0) - f0=118*11025.d0/1024 - dfgen=mode65*11025.d0/4096.d0 - phi=0.d0 - i=0 - k=0 - do j=1,nsym - f=f0 - if(nspecial.ne.0 .and. mod(j,2).eq.0) f=f0+10*nspecial*dfgen - if(nspecial.eq.0 .and. flip*pr(j).lt.0.0) then - k=k+1 - f=f0+(sent(k)+2)*dfgen - endif - dphi=twopi*dt*f - do ii=1,nsps - phi=phi+dphi - if(phi.gt.twopi) phi=phi-twopi - xphi=phi - i=i+1 - iwave(i)=32767.0*sin(xphi) - enddo - enddo - - iwave(nsym*nsps+1:)=0 - nwave=nsym*nsps + 5512 - call unpackmsg(dgen,msgsent) - if(flip.lt.0.0) then - do i=22,1,-1 - if(msgsent(i:i).ne.' ') goto 10 - enddo -10 msgsent=msgsent(1:i)//' OOO' - endif - - if(nsendingsh.eq.1) then - if(nspecial.eq.2) msgsent='RO' - if(nspecial.eq.3) msgsent='RRR' - if(nspecial.eq.4) msgsent='73' - endif - -900 return -end subroutine gen65 +subroutine gen65(message,mode65,samfac,nsendingsh,msgsent,iwave,nwave) + +! Encodes a JT65 message into a wavefile. +! Executes in 17 ms on opti-745. + + parameter (NMAX=60*11025) !Max length of wave file + character*22 message !Message to be generated + character*22 msgsent !Message as it will be received + character*3 cok !' ' or 'OOO' + real*8 dt,phi,f,f0,dfgen,dphi,twopi,samfac + integer*2 iwave(NMAX) !Generated wave file + integer dgen(12) + integer sent(63) + logical first + integer nprc(126) + real pr(126) + data nprc/1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0, & + 0,1,0,1,1,0,0,1,0,0,0,1,1,1,0,0,1,1,1,1, & + 0,1,1,0,1,1,1,1,0,0,0,1,1,0,1,0,1,0,1,1, & + 0,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,1, & + 1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1, & + 0,1,0,1,0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,1, & + 1,1,1,1,1,1/ + data twopi/6.283185307179586476d0/,first/.true./ + save + + if(first) then + do i=1,126 + pr(i)=2*nprc(i)-1 + enddo + first=.false. + endif + + call chkmsg(message,cok,nspecial,flip) + if(nspecial.eq.0) then + call packmsg(message,dgen) !Pack message into 72 bits + nsendingsh=0 + if(iand(dgen(10),8).ne.0) nsendingsh=-1 !Plain text flag + + call rs_encode(dgen,sent) + call interleave63(sent,1) !Apply interleaving + call graycode(sent,63,1) !Apply Gray code + nsym=126 !Symbols per transmission + nsps=4096 + else + nsym=32 + nsps=16384 + nsendingsh=1 !Flag for shorthand message + endif + if(mode65.eq.0) go to 900 + +! Set up necessary constants + dt=1.d0/(samfac*11025.d0) + f0=118*11025.d0/1024 + dfgen=mode65*11025.d0/4096.d0 + phi=0.d0 + i=0 + k=0 + do j=1,nsym + f=f0 + if(nspecial.ne.0 .and. mod(j,2).eq.0) f=f0+10*nspecial*dfgen + if(nspecial.eq.0 .and. flip*pr(j).lt.0.0) then + k=k+1 + f=f0+(sent(k)+2)*dfgen + endif + dphi=twopi*dt*f + do ii=1,nsps + phi=phi+dphi + if(phi.gt.twopi) phi=phi-twopi + xphi=phi + i=i+1 + iwave(i)=32767.0*sin(xphi) + enddo + enddo + + iwave(nsym*nsps+1:)=0 + nwave=nsym*nsps + 5512 + call unpackmsg(dgen,msgsent) + if(flip.lt.0.0) then + do i=22,1,-1 + if(msgsent(i:i).ne.' ') goto 10 + enddo +10 msgsent=msgsent(1:i)//' OOO' + endif + + if(nsendingsh.eq.1) then + if(nspecial.eq.2) msgsent='RO' + if(nspecial.eq.3) msgsent='RRR' + if(nspecial.eq.4) msgsent='73' + endif + +900 return +end subroutine gen65 diff --git a/libm65/geocentric.f b/libm65/geocentric.f index 0af575d81..1767f9cf8 100644 --- a/libm65/geocentric.f +++ b/libm65/geocentric.f @@ -1,17 +1,17 @@ - subroutine geocentric(alat,elev,hlt,erad) - - implicit real*8 (a-h,o-z) - -C IAU 1976 flattening f, equatorial radius a - f = 1.d0/298.257d0 - a = 6378140.d0 - c = 1.d0/sqrt(1.d0 + (-2.d0 + f)*f*sin(alat)*sin(alat)) - arcf = (a*c + elev)*cos(alat) - arsf = (a*(1.d0 - f)*(1.d0 - f)*c + elev)*sin(alat) - hlt = datan2(arsf,arcf) - erad = sqrt(arcf*arcf + arsf*arsf) - erad = 0.001d0*erad - - return - end - + subroutine geocentric(alat,elev,hlt,erad) + + implicit real*8 (a-h,o-z) + +C IAU 1976 flattening f, equatorial radius a + f = 1.d0/298.257d0 + a = 6378140.d0 + c = 1.d0/sqrt(1.d0 + (-2.d0 + f)*f*sin(alat)*sin(alat)) + arcf = (a*c + elev)*cos(alat) + arsf = (a*(1.d0 - f)*(1.d0 - f)*c + elev)*sin(alat) + hlt = datan2(arsf,arcf) + erad = sqrt(arcf*arcf + arsf*arsf) + erad = 0.001d0*erad + + return + end + diff --git a/libm65/getdphi.f90 b/libm65/getdphi.f90 index f44c2d06e..e55d7120d 100644 --- a/libm65/getdphi.f90 +++ b/libm65/getdphi.f90 @@ -1,18 +1,18 @@ -subroutine getdphi(qphi) - - real qphi(12) - - s=0. - c=0. - do i=1,12 - th=i*30/57.2957795 - s=s+qphi(i)*sin(th) - c=c+qphi(i)*cos(th) - enddo - - dphi=57.2957795*atan2(s,c) - write(*,1010) nint(dphi) -1010 format('!Best-fit Dphi =',i4,' deg') - - return - end +subroutine getdphi(qphi) + + real qphi(12) + + s=0. + c=0. + do i=1,12 + th=i*30/57.2957795 + s=s+qphi(i)*sin(th) + c=c+qphi(i)*cos(th) + enddo + + dphi=57.2957795*atan2(s,c) + write(*,1010) nint(dphi) +1010 format('!Best-fit Dphi =',i4,' deg') + + return + end diff --git a/libm65/getpfx1.f b/libm65/getpfx1.f index eaa86349e..21489f522 100644 --- a/libm65/getpfx1.f +++ b/libm65/getpfx1.f @@ -1,96 +1,96 @@ - subroutine getpfx1(callsign,k,nv2) - - character*12 callsign0,callsign,lof,rof - character*8 c - character addpfx*8,tpfx*4,tsfx*3 - logical ispfx,issfx,invalid - common/pfxcom/addpfx - include 'pfx.f' - - callsign0=callsign - nv2=0 - iz=index(callsign,' ') - 1 - if(iz.lt.0) iz=12 - islash=index(callsign(1:iz),'/') - k=0 - c=' ' - if(islash.gt.0 .and. islash.le.(iz-4)) then -! Add-on prefix - c=callsign(1:islash-1) - callsign=callsign(islash+1:iz) - do i=1,NZ - if(pfx(i)(1:4).eq.c) then - k=i - go to 10 - endif - enddo - if(addpfx.eq.c) then - k=449 - go to 10 - endif - - else if(islash.eq.(iz-1)) then -! Add-on suffix - c=callsign(islash+1:iz) - callsign=callsign(1:islash-1) - do i=1,NZ2 - if(sfx(i).eq.c(1:1)) then - k=400+i - go to 10 - endif - enddo - endif - - 10 if(islash.ne.0 .and.k.eq.0) then -! Original JT65 would force this compound callsign to be treated as -! plain text. In JT65v2, we will encode the prefix or suffix into nc1. -! The task here is to compute the proper value of k. - lof=callsign0(:islash-1) - rof=callsign0(islash+1:) - llof=len_trim(lof) - lrof=len_trim(rof) - ispfx=(llof.gt.0 .and. llof.le.4) - issfx=(lrof.gt.0 .and. lrof.le.3) - invalid=.not.(ispfx.or.issfx) - if(ispfx.and.issfx) then - if(llof.lt.3) issfx=.false. - if(lrof.lt.3) ispfx=.false. - if(ispfx.and.issfx) then - i=ichar(callsign0(islash-1:islash-1)) - if(i.ge.ichar('0') .and. i.le.ichar('9')) then - issfx=.false. - else - ispfx=.false. - endif - endif - endif - - if(invalid) then - k=-1 - else - if(ispfx) then - tpfx=lof - k=nchar(tpfx(1:1)) - k=37*k + nchar(tpfx(2:2)) - k=37*k + nchar(tpfx(3:3)) - k=37*k + nchar(tpfx(4:4)) - nv2=1 - i=index(callsign0,'/') - callsign=callsign0(:i-1) - callsign=callsign0(i+1:) - endif - if(issfx) then - tsfx=rof - k=nchar(tsfx(1:1)) - k=37*k + nchar(tsfx(2:2)) - k=37*k + nchar(tsfx(3:3)) - nv2=2 - i=index(callsign0,'/') - callsign=callsign0(:i-1) - endif - endif - endif - - return - end - + subroutine getpfx1(callsign,k,nv2) + + character*12 callsign0,callsign,lof,rof + character*8 c + character addpfx*8,tpfx*4,tsfx*3 + logical ispfx,issfx,invalid + common/pfxcom/addpfx + include 'pfx.f' + + callsign0=callsign + nv2=0 + iz=index(callsign,' ') - 1 + if(iz.lt.0) iz=12 + islash=index(callsign(1:iz),'/') + k=0 + c=' ' + if(islash.gt.0 .and. islash.le.(iz-4)) then +! Add-on prefix + c=callsign(1:islash-1) + callsign=callsign(islash+1:iz) + do i=1,NZ + if(pfx(i)(1:4).eq.c) then + k=i + go to 10 + endif + enddo + if(addpfx.eq.c) then + k=449 + go to 10 + endif + + else if(islash.eq.(iz-1)) then +! Add-on suffix + c=callsign(islash+1:iz) + callsign=callsign(1:islash-1) + do i=1,NZ2 + if(sfx(i).eq.c(1:1)) then + k=400+i + go to 10 + endif + enddo + endif + + 10 if(islash.ne.0 .and.k.eq.0) then +! Original JT65 would force this compound callsign to be treated as +! plain text. In JT65v2, we will encode the prefix or suffix into nc1. +! The task here is to compute the proper value of k. + lof=callsign0(:islash-1) + rof=callsign0(islash+1:) + llof=len_trim(lof) + lrof=len_trim(rof) + ispfx=(llof.gt.0 .and. llof.le.4) + issfx=(lrof.gt.0 .and. lrof.le.3) + invalid=.not.(ispfx.or.issfx) + if(ispfx.and.issfx) then + if(llof.lt.3) issfx=.false. + if(lrof.lt.3) ispfx=.false. + if(ispfx.and.issfx) then + i=ichar(callsign0(islash-1:islash-1)) + if(i.ge.ichar('0') .and. i.le.ichar('9')) then + issfx=.false. + else + ispfx=.false. + endif + endif + endif + + if(invalid) then + k=-1 + else + if(ispfx) then + tpfx=lof + k=nchar(tpfx(1:1)) + k=37*k + nchar(tpfx(2:2)) + k=37*k + nchar(tpfx(3:3)) + k=37*k + nchar(tpfx(4:4)) + nv2=1 + i=index(callsign0,'/') + callsign=callsign0(:i-1) + callsign=callsign0(i+1:) + endif + if(issfx) then + tsfx=rof + k=nchar(tsfx(1:1)) + k=37*k + nchar(tsfx(2:2)) + k=37*k + nchar(tsfx(3:3)) + nv2=2 + i=index(callsign0,'/') + callsign=callsign0(:i-1) + endif + endif + endif + + return + end + diff --git a/libm65/getpfx2.f b/libm65/getpfx2.f index ebcdec351..26a46cce5 100644 --- a/libm65/getpfx2.f +++ b/libm65/getpfx2.f @@ -1,24 +1,24 @@ - subroutine getpfx2(k0,callsign) - - character callsign*12 - include 'pfx.f' - character addpfx*8 - common/pfxcom/addpfx - - k=k0 - if(k.gt.450) k=k-450 - if(k.ge.1 .and. k.le.NZ) then - iz=index(pfx(k),' ') - 1 - callsign=pfx(k)(1:iz)//'/'//callsign - else if(k.ge.401 .and. k.le.400+NZ2) then - iz=index(callsign,' ') - 1 - callsign=callsign(1:iz)//'/'//sfx(k-400) - else if(k.eq.449) then - iz=index(addpfx,' ') - 1 - if(iz.lt.1) iz=8 - callsign=addpfx(1:iz)//'/'//callsign - endif - - return - end - + subroutine getpfx2(k0,callsign) + + character callsign*12 + include 'pfx.f' + character addpfx*8 + common/pfxcom/addpfx + + k=k0 + if(k.gt.450) k=k-450 + if(k.ge.1 .and. k.le.NZ) then + iz=index(pfx(k),' ') - 1 + callsign=pfx(k)(1:iz)//'/'//callsign + else if(k.ge.401 .and. k.le.400+NZ2) then + iz=index(callsign,' ') - 1 + callsign=callsign(1:iz)//'/'//sfx(k-400) + else if(k.eq.449) then + iz=index(addpfx,' ') - 1 + if(iz.lt.1) iz=8 + callsign=addpfx(1:iz)//'/'//callsign + endif + + return + end + diff --git a/libm65/graycode.f b/libm65/graycode.f index 0edc2af2d..24c03e943 100644 --- a/libm65/graycode.f +++ b/libm65/graycode.f @@ -1,10 +1,10 @@ - subroutine graycode(dat,n,idir) - - integer dat(n) - do i=1,n - dat(i)=igray(dat(i),idir) - enddo - - return - end - + subroutine graycode(dat,n,idir) + + integer dat(n) + do i=1,n + dat(i)=igray(dat(i),idir) + enddo + + return + end + diff --git a/libm65/grid2deg.f b/libm65/grid2deg.f index 324a15eb7..7947073d8 100644 --- a/libm65/grid2deg.f +++ b/libm65/grid2deg.f @@ -1,38 +1,38 @@ - subroutine grid2deg(grid0,dlong,dlat) - -C Converts Maidenhead grid locator to degrees of West longitude -C and North latitude. - - character*6 grid0,grid - character*1 g1,g2,g3,g4,g5,g6 - - grid=grid0 - i=ichar(grid(5:5)) - if(grid(5:5).eq.' ' .or. i.le.64 .or. i.ge.128) grid(5:6)='mm' - - if(grid(1:1).ge.'a' .and. grid(1:1).le.'z') grid(1:1)= - + char(ichar(grid(1:1))+ichar('A')-ichar('a')) - if(grid(2:2).ge.'a' .and. grid(2:2).le.'z') grid(2:2)= - + char(ichar(grid(2:2))+ichar('A')-ichar('a')) - if(grid(5:5).ge.'A' .and. grid(5:5).le.'Z') grid(5:5)= - + char(ichar(grid(5:5))-ichar('A')+ichar('a')) - if(grid(6:6).ge.'A' .and. grid(6:6).le.'Z') grid(6:6)= - + char(ichar(grid(6:6))-ichar('A')+ichar('a')) - - g1=grid(1:1) - g2=grid(2:2) - g3=grid(3:3) - g4=grid(4:4) - g5=grid(5:5) - g6=grid(6:6) - - nlong = 180 - 20*(ichar(g1)-ichar('A')) - n20d = 2*(ichar(g3)-ichar('0')) - xminlong = 5*(ichar(g5)-ichar('a')+0.5) - dlong = nlong - n20d - xminlong/60.0 - nlat = -90+10*(ichar(g2)-ichar('A')) + ichar(g4)-ichar('0') - xminlat = 2.5*(ichar(g6)-ichar('a')+0.5) - dlat = nlat + xminlat/60.0 - - return - end + subroutine grid2deg(grid0,dlong,dlat) + +C Converts Maidenhead grid locator to degrees of West longitude +C and North latitude. + + character*6 grid0,grid + character*1 g1,g2,g3,g4,g5,g6 + + grid=grid0 + i=ichar(grid(5:5)) + if(grid(5:5).eq.' ' .or. i.le.64 .or. i.ge.128) grid(5:6)='mm' + + if(grid(1:1).ge.'a' .and. grid(1:1).le.'z') grid(1:1)= + + char(ichar(grid(1:1))+ichar('A')-ichar('a')) + if(grid(2:2).ge.'a' .and. grid(2:2).le.'z') grid(2:2)= + + char(ichar(grid(2:2))+ichar('A')-ichar('a')) + if(grid(5:5).ge.'A' .and. grid(5:5).le.'Z') grid(5:5)= + + char(ichar(grid(5:5))-ichar('A')+ichar('a')) + if(grid(6:6).ge.'A' .and. grid(6:6).le.'Z') grid(6:6)= + + char(ichar(grid(6:6))-ichar('A')+ichar('a')) + + g1=grid(1:1) + g2=grid(2:2) + g3=grid(3:3) + g4=grid(4:4) + g5=grid(5:5) + g6=grid(6:6) + + nlong = 180 - 20*(ichar(g1)-ichar('A')) + n20d = 2*(ichar(g3)-ichar('0')) + xminlong = 5*(ichar(g5)-ichar('a')+0.5) + dlong = nlong - n20d - xminlong/60.0 + nlat = -90+10*(ichar(g2)-ichar('A')) + ichar(g4)-ichar('0') + xminlat = 2.5*(ichar(g6)-ichar('a')+0.5) + dlat = nlat + xminlat/60.0 + + return + end diff --git a/libm65/grid2k.f b/libm65/grid2k.f index b79f290ed..1306a95a2 100644 --- a/libm65/grid2k.f +++ b/libm65/grid2k.f @@ -1,12 +1,12 @@ - subroutine grid2k(grid,k) - - character*6 grid - - call grid2deg(grid,xlong,xlat) - nlong=nint(xlong) - nlat=nint(xlat) - k=0 - if(nlat.ge.85) k=5*(nlong+179)/2 + nlat-84 - - return - end + subroutine grid2k(grid,k) + + character*6 grid + + call grid2deg(grid,xlong,xlat) + nlong=nint(xlong) + nlat=nint(xlat) + k=0 + if(nlat.ge.85) k=5*(nlong+179)/2 + nlat-84 + + return + end diff --git a/libm65/igray.c b/libm65/igray.c index b1d9dbaf5..395f79712 100644 --- a/libm65/igray.c +++ b/libm65/igray.c @@ -1,22 +1,22 @@ -#ifdef CVF -extern int __stdcall IGRAY(int *n0, int *idir) -#else -int igray_(int *n0, int *idir) -#endif -{ - int n; - unsigned long sh; - unsigned long nn; - n=*n0; - - if(*idir>0) return (n ^ (n >> 1)); - - sh = 1; - nn = (n >> sh); - while (nn > 0) { - n ^= nn; - sh <<= 1; - nn = (n >> sh); - } - return (n); -} +#ifdef CVF +extern int __stdcall IGRAY(int *n0, int *idir) +#else +int igray_(int *n0, int *idir) +#endif +{ + int n; + unsigned long sh; + unsigned long nn; + n=*n0; + + if(*idir>0) return (n ^ (n >> 1)); + + sh = 1; + nn = (n >> sh); + while (nn > 0) { + n ^= nn; + sh <<= 1; + nn = (n >> sh); + } + return (n); +} diff --git a/libm65/indexx.f b/libm65/indexx.f index 11e0fefd2..df2a5330e 100644 --- a/libm65/indexx.f +++ b/libm65/indexx.f @@ -1,19 +1,19 @@ - subroutine indexx(n,arr,indx) - - parameter (NMAX=3000) - integer indx(n) - real arr(n) - real brr(NMAX) - if(n.gt.NMAX) then - print*,'n=',n,' too big in indexx.' - stop - endif - do i=1,n - brr(i)=arr(i) - indx(i)=i - enddo - call ssort(brr,indx,n,2) - - return - end - + subroutine indexx(n,arr,indx) + + parameter (NMAX=3000) + integer indx(n) + real arr(n) + real brr(NMAX) + if(n.gt.NMAX) then + print*,'n=',n,' too big in indexx.' + stop + endif + do i=1,n + brr(i)=arr(i) + indx(i)=i + enddo + call ssort(brr,indx,n,2) + + return + end + diff --git a/libm65/init_rs.c b/libm65/init_rs.c index c335c8994..7e1e09e5b 100644 --- a/libm65/init_rs.c +++ b/libm65/init_rs.c @@ -1,126 +1,126 @@ -/* Initialize a RS codec - * - * Copyright 2002 Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#include - -#ifdef CCSDS -#include "ccsds.h" -#elif defined(BIGSYM) -#include "int.h" -#else -#include "char.h" -#endif - -#define NULL ((void *)0) - -void FREE_RS(void *p){ - struct rs *rs = (struct rs *)p; - - free(rs->alpha_to); - free(rs->index_of); - free(rs->genpoly); - free(rs); -} - -/* Initialize a Reed-Solomon codec - * symsize = symbol size, bits (1-8) - * gfpoly = Field generator polynomial coefficients - * fcr = first root of RS code generator polynomial, index form - * prim = primitive element to generate polynomial roots - * nroots = RS code generator polynomial degree (number of roots) - * pad = padding bytes at front of shortened block - */ -void *INIT_RS(int symsize,int gfpoly,int fcr,int prim, - int nroots,int pad){ - struct rs *rs; - int i, j, sr,root,iprim; - - /* Check parameter ranges */ - if(symsize < 0 || symsize > 8*sizeof(DTYPE)) - return NULL; /* Need version with ints rather than chars */ - - if(fcr < 0 || fcr >= (1<= (1<= (1<= ((1<mm = symsize; - rs->nn = (1<pad = pad; - - rs->alpha_to = (DTYPE *)malloc(sizeof(DTYPE)*(rs->nn+1)); - if(rs->alpha_to == NULL){ - free(rs); - return NULL; - } - rs->index_of = (DTYPE *)malloc(sizeof(DTYPE)*(rs->nn+1)); - if(rs->index_of == NULL){ - free(rs->alpha_to); - free(rs); - return NULL; - } - - /* Generate Galois field lookup tables */ - rs->index_of[0] = A0; /* log(zero) = -inf */ - rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ - sr = 1; - for(i=0;inn;i++){ - rs->index_of[sr] = i; - rs->alpha_to[i] = sr; - sr <<= 1; - if(sr & (1<nn; - } - if(sr != 1){ - /* field generator polynomial is not primitive! */ - free(rs->alpha_to); - free(rs->index_of); - free(rs); - return NULL; - } - - /* Form RS code generator polynomial from its roots */ - rs->genpoly = (DTYPE *)malloc(sizeof(DTYPE)*(nroots+1)); - if(rs->genpoly == NULL){ - free(rs->alpha_to); - free(rs->index_of); - free(rs); - return NULL; - } - rs->fcr = fcr; - rs->prim = prim; - rs->nroots = nroots; - - /* Find prim-th root of 1, used in decoding */ - for(iprim=1;(iprim % prim) != 0;iprim += rs->nn) - ; - rs->iprim = iprim / prim; - - rs->genpoly[0] = 1; - for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) { - rs->genpoly[i+1] = 1; - - /* Multiply rs->genpoly[] by @**(root + x) */ - for (j = i; j > 0; j--){ - if (rs->genpoly[j] != 0) - rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)]; - else - rs->genpoly[j] = rs->genpoly[j-1]; - } - /* rs->genpoly[0] can never be zero */ - rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)]; - } - /* convert rs->genpoly[] to index form for quicker encoding */ - for (i = 0; i <= nroots; i++) - rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; - - return rs; -} +/* Initialize a RS codec + * + * Copyright 2002 Phil Karn, KA9Q + * May be used under the terms of the GNU General Public License (GPL) + */ +#include + +#ifdef CCSDS +#include "ccsds.h" +#elif defined(BIGSYM) +#include "int.h" +#else +#include "char.h" +#endif + +#define NULL ((void *)0) + +void FREE_RS(void *p){ + struct rs *rs = (struct rs *)p; + + free(rs->alpha_to); + free(rs->index_of); + free(rs->genpoly); + free(rs); +} + +/* Initialize a Reed-Solomon codec + * symsize = symbol size, bits (1-8) + * gfpoly = Field generator polynomial coefficients + * fcr = first root of RS code generator polynomial, index form + * prim = primitive element to generate polynomial roots + * nroots = RS code generator polynomial degree (number of roots) + * pad = padding bytes at front of shortened block + */ +void *INIT_RS(int symsize,int gfpoly,int fcr,int prim, + int nroots,int pad){ + struct rs *rs; + int i, j, sr,root,iprim; + + /* Check parameter ranges */ + if(symsize < 0 || symsize > 8*sizeof(DTYPE)) + return NULL; /* Need version with ints rather than chars */ + + if(fcr < 0 || fcr >= (1<= (1<= (1<= ((1<mm = symsize; + rs->nn = (1<pad = pad; + + rs->alpha_to = (DTYPE *)malloc(sizeof(DTYPE)*(rs->nn+1)); + if(rs->alpha_to == NULL){ + free(rs); + return NULL; + } + rs->index_of = (DTYPE *)malloc(sizeof(DTYPE)*(rs->nn+1)); + if(rs->index_of == NULL){ + free(rs->alpha_to); + free(rs); + return NULL; + } + + /* Generate Galois field lookup tables */ + rs->index_of[0] = A0; /* log(zero) = -inf */ + rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ + sr = 1; + for(i=0;inn;i++){ + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr <<= 1; + if(sr & (1<nn; + } + if(sr != 1){ + /* field generator polynomial is not primitive! */ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + return NULL; + } + + /* Form RS code generator polynomial from its roots */ + rs->genpoly = (DTYPE *)malloc(sizeof(DTYPE)*(nroots+1)); + if(rs->genpoly == NULL){ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + return NULL; + } + rs->fcr = fcr; + rs->prim = prim; + rs->nroots = nroots; + + /* Find prim-th root of 1, used in decoding */ + for(iprim=1;(iprim % prim) != 0;iprim += rs->nn) + ; + rs->iprim = iprim / prim; + + rs->genpoly[0] = 1; + for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) { + rs->genpoly[i+1] = 1; + + /* Multiply rs->genpoly[] by @**(root + x) */ + for (j = i; j > 0; j--){ + if (rs->genpoly[j] != 0) + rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)]; + else + rs->genpoly[j] = rs->genpoly[j-1]; + } + /* rs->genpoly[0] can never be zero */ + rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)]; + } + /* convert rs->genpoly[] to index form for quicker encoding */ + for (i = 0; i <= nroots; i++) + rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; + + return rs; +} diff --git a/libm65/int.h b/libm65/int.h index 0591b1181..056241e12 100644 --- a/libm65/int.h +++ b/libm65/int.h @@ -1,57 +1,57 @@ -/* Include file to configure the RS codec for integer symbols - * - * Copyright 2002, Phil Karn, KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ -#define DTYPE int - -/* Reed-Solomon codec control block */ -struct rs { - int mm; /* Bits per symbol */ - int nn; /* Symbols per block (= (1<= rs->nn) { - x -= rs->nn; - x = (x >> rs->mm) + (x & rs->nn); - } - return x; -} -#define MODNN(x) modnn(rs,x) - -#define MM (rs->mm) -#define NN (rs->nn) -#define ALPHA_TO (rs->alpha_to) -#define INDEX_OF (rs->index_of) -#define GENPOLY (rs->genpoly) -//#define NROOTS (rs->nroots) -#define NROOTS (51) -#define FCR (rs->fcr) -#define PRIM (rs->prim) -#define IPRIM (rs->iprim) -#define PAD (rs->pad) -#define A0 (NN) - -#define ENCODE_RS encode_rs_int -#define DECODE_RS decode_rs_int -#define INIT_RS init_rs_int -#define FREE_RS free_rs_int - -void ENCODE_RS(void *p,DTYPE *data,DTYPE *parity); -int DECODE_RS(void *p,DTYPE *data,int *eras_pos,int no_eras); -void *INIT_RS(int symsize,int gfpoly,int fcr, - int prim,int nroots,int pad); -void FREE_RS(void *p); - - - - +/* Include file to configure the RS codec for integer symbols + * + * Copyright 2002, Phil Karn, KA9Q + * May be used under the terms of the GNU General Public License (GPL) + */ +#define DTYPE int + +/* Reed-Solomon codec control block */ +struct rs { + int mm; /* Bits per symbol */ + int nn; /* Symbols per block (= (1<= rs->nn) { + x -= rs->nn; + x = (x >> rs->mm) + (x & rs->nn); + } + return x; +} +#define MODNN(x) modnn(rs,x) + +#define MM (rs->mm) +#define NN (rs->nn) +#define ALPHA_TO (rs->alpha_to) +#define INDEX_OF (rs->index_of) +#define GENPOLY (rs->genpoly) +//#define NROOTS (rs->nroots) +#define NROOTS (51) +#define FCR (rs->fcr) +#define PRIM (rs->prim) +#define IPRIM (rs->iprim) +#define PAD (rs->pad) +#define A0 (NN) + +#define ENCODE_RS encode_rs_int +#define DECODE_RS decode_rs_int +#define INIT_RS init_rs_int +#define FREE_RS free_rs_int + +void ENCODE_RS(void *p,DTYPE *data,DTYPE *parity); +int DECODE_RS(void *p,DTYPE *data,int *eras_pos,int no_eras); +void *INIT_RS(int symsize,int gfpoly,int fcr, + int prim,int nroots,int pad); +void FREE_RS(void *p); + + + + diff --git a/libm65/interleave63.f b/libm65/interleave63.f index c07dbd4c1..f6793023a 100644 --- a/libm65/interleave63.f +++ b/libm65/interleave63.f @@ -1,25 +1,25 @@ - subroutine interleave63(d1,idir) - -C Interleave (idir=1) or de-interleave (idir=-1) the array d1. - - integer d1(0:6,0:8) - integer d2(0:8,0:6) - - if(idir.ge.0) then - do i=0,6 - do j=0,8 - d2(j,i)=d1(i,j) - enddo - enddo - call move(d2,d1,63) - else - call move(d1,d2,63) - do i=0,6 - do j=0,8 - d1(i,j)=d2(j,i) - enddo - enddo - endif - - return - end + subroutine interleave63(d1,idir) + +C Interleave (idir=1) or de-interleave (idir=-1) the array d1. + + integer d1(0:6,0:8) + integer d2(0:8,0:6) + + if(idir.ge.0) then + do i=0,6 + do j=0,8 + d2(j,i)=d1(i,j) + enddo + enddo + call move(d2,d1,63) + else + call move(d1,d2,63) + do i=0,6 + do j=0,8 + d1(i,j)=d2(j,i) + enddo + enddo + endif + + return + end diff --git a/libm65/ipcomm.cpp b/libm65/ipcomm.cpp index 83e98ebd4..b40a09998 100644 --- a/libm65/ipcomm.cpp +++ b/libm65/ipcomm.cpp @@ -1,34 +1,34 @@ -#include -#include -#include - -QSharedMemory mem_m65("mem_m65"); -QSystemSemaphore sem_m65("sem_m65", 1, QSystemSemaphore::Open); - -extern "C" { - bool attach_m65_(); - bool create_m65_(int nsize); - bool detach_m65_(); - bool lock_m65_(); - bool unlock_m65_(); - char* address_m65_(); - int size_m65_(); - - bool acquire_m65_(); - bool release_m65_(); - - extern struct { - char c[10]; - } m65com_; -} - -bool attach_m65_() {return mem_m65.attach();} -bool create_m65_(int nsize) {return mem_m65.create(nsize);} -bool detach_m65_() {return mem_m65.detach();} -bool lock_m65_() {return mem_m65.lock();} -bool unlock_m65_() {return mem_m65.unlock();} -char* address_m65_() {return (char*)mem_m65.constData();} -int size_m65_() {return (int)mem_m65.size();} - -bool acquire_m65_() {return sem_m65.acquire();} -bool release_m65_() {return sem_m65.release();} +#include +#include +#include + +QSharedMemory mem_m65("mem_m65"); +QSystemSemaphore sem_m65("sem_m65", 1, QSystemSemaphore::Open); + +extern "C" { + bool attach_m65_(); + bool create_m65_(int nsize); + bool detach_m65_(); + bool lock_m65_(); + bool unlock_m65_(); + char* address_m65_(); + int size_m65_(); + + bool acquire_m65_(); + bool release_m65_(); + + extern struct { + char c[10]; + } m65com_; +} + +bool attach_m65_() {return mem_m65.attach();} +bool create_m65_(int nsize) {return mem_m65.create(nsize);} +bool detach_m65_() {return mem_m65.detach();} +bool lock_m65_() {return mem_m65.lock();} +bool unlock_m65_() {return mem_m65.unlock();} +char* address_m65_() {return (char*)mem_m65.constData();} +int size_m65_() {return (int)mem_m65.size();} + +bool acquire_m65_() {return sem_m65.acquire();} +bool release_m65_() {return sem_m65.release();} diff --git a/libm65/iqcal.f90 b/libm65/iqcal.f90 index c7ee7fd95..c0c4fce2d 100644 --- a/libm65/iqcal.f90 +++ b/libm65/iqcal.f90 @@ -1,30 +1,30 @@ -subroutine iqcal(nn,c,nfft,gain,phase,zsum,ipk,reject) - - complex c(0:nfft-1) - complex z,zsum,zave - - if(nn.eq.0) then - zsum=0. - endif - nn=nn+1 - smax=0. - ipk=1 - do i=1,nfft-1 !Find strongest signal - s=real(c(i))**2 + aimag(c(i))**2 - if(s.gt.smax) then - smax=s - ipk=i - endif - enddo - pimage=real(c(nfft-ipk))**2 + aimag(c(nfft-ipk))**2 - p=smax + pimage - z=c(ipk)*c(nfft-ipk)/p !Synchronous detection of image - zsum=zsum+z - zave=zsum/nn - tmp=sqrt(1.0 - (2.0*real(zave))**2) - phase=asin(2.0*aimag(zave)/tmp) !Estimate phase - gain=tmp/(1.0-2.0*real(zave)) !Estimate gain - reject=10.0*log10(pimage/smax) - - return -end subroutine iqcal +subroutine iqcal(nn,c,nfft,gain,phase,zsum,ipk,reject) + + complex c(0:nfft-1) + complex z,zsum,zave + + if(nn.eq.0) then + zsum=0. + endif + nn=nn+1 + smax=0. + ipk=1 + do i=1,nfft-1 !Find strongest signal + s=real(c(i))**2 + aimag(c(i))**2 + if(s.gt.smax) then + smax=s + ipk=i + endif + enddo + pimage=real(c(nfft-ipk))**2 + aimag(c(nfft-ipk))**2 + p=smax + pimage + z=c(ipk)*c(nfft-ipk)/p !Synchronous detection of image + zsum=zsum+z + zave=zsum/nn + tmp=sqrt(1.0 - (2.0*real(zave))**2) + phase=asin(2.0*aimag(zave)/tmp) !Estimate phase + gain=tmp/(1.0-2.0*real(zave)) !Estimate gain + reject=10.0*log10(pimage/smax) + + return +end subroutine iqcal diff --git a/libm65/iqfix.f90 b/libm65/iqfix.f90 index 59ac0a3fe..336f7928a 100644 --- a/libm65/iqfix.f90 +++ b/libm65/iqfix.f90 @@ -1,29 +1,29 @@ -subroutine iqfix(c,nfft,gain,phase) - - complex c(0:nfft-1) - complex z,h,u,v - real*8 sq1,sq2 - - nh=nfft/2 - h=gain*cmplx(cos(phase),sin(phase)) - - do i=1,nh-1 - u=c(i) - v=c(nfft-i) - x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & - (real(u) - real(v))*real(h) - y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & - (real(u) - real(v))*aimag(h) - c(i)=0.5*cmplx(x,y) - z=u - u=v - v=z - x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & - (real(u) - real(v))*real(h) - y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & - (real(u) - real(v))*aimag(h) - c(nfft-i)=0.5*cmplx(x,y) - enddo - - return -end subroutine iqfix +subroutine iqfix(c,nfft,gain,phase) + + complex c(0:nfft-1) + complex z,h,u,v + real*8 sq1,sq2 + + nh=nfft/2 + h=gain*cmplx(cos(phase),sin(phase)) + + do i=1,nh-1 + u=c(i) + v=c(nfft-i) + x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & + (real(u) - real(v))*real(h) + y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & + (real(u) - real(v))*aimag(h) + c(i)=0.5*cmplx(x,y) + z=u + u=v + v=z + x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & + (real(u) - real(v))*real(h) + y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & + (real(u) - real(v))*aimag(h) + c(nfft-i)=0.5*cmplx(x,y) + enddo + + return +end subroutine iqfix diff --git a/libm65/k2grid.f b/libm65/k2grid.f index 5ce4ec691..6fcd7f3e4 100644 --- a/libm65/k2grid.f +++ b/libm65/k2grid.f @@ -1,12 +1,12 @@ - subroutine k2grid(k,grid) - character grid*6 - - nlong=2*mod((k-1)/5,90)-179 - if(k.gt.450) nlong=nlong+180 - nlat=mod(k-1,5)+ 85 - dlat=nlat - dlong=nlong - call deg2grid(dlong,dlat,grid) - - return - end + subroutine k2grid(k,grid) + character grid*6 + + nlong=2*mod((k-1)/5,90)-179 + if(k.gt.450) nlong=nlong+180 + nlat=mod(k-1,5)+ 85 + dlat=nlat + dlong=nlong + call deg2grid(dlong,dlat,grid) + + return + end diff --git a/libm65/m65.f90 b/libm65/m65.f90 index eb35520b8..27d9b373c 100644 --- a/libm65/m65.f90 +++ b/libm65/m65.f90 @@ -1,130 +1,130 @@ -program m65 - -! Decoder for map65. Can run stand-alone, reading data from *.tf2 files; -! or as the back end of map65, with data placed in a shared memory region. - - parameter (NSMAX=60*96000) - parameter (NFFT=32768) - integer*2 i2(4,87) - real*8 hsym - real*4 ssz5a(NFFT) - logical*1 lstrong(0:1023) - common/tracer/limtrace,lu - real*8 fc0,fcenter - character*80 arg,infile - character mycall*12,hiscall*12,mygrid*6,hisgrid*6,datetime*20 - common/datcom/dd(4,5760000),ss(4,322,NFFT),savg(4,NFFT),fc0,nutc0,junk(34) - common/npar/fcenter,nutc,idphi,mousedf,mousefqso,nagain, & - ndepth,ndiskdat,neme,newdat,nfa,nfb,nfcal,nfshift, & - mcall3,nkeep,ntol,nxant,nrxlog,nfsample,nxpol,mode65, & - mycall,mygrid,hiscall,hisgrid,datetime - - nargs=iargc() - if(nargs.lt.1) then - print*,'Usage: m65 [95238] file1 [file2 ...]' - print*,' Reads data from *.tf2 files.' - print*,'' - print*,' m65 -s' - print*,' Gets data from shared memory region.' - go to 999 - endif - call getarg(1,arg) - if(arg(1:2).eq.'-s') then - call m65a - call ftnquit - go to 999 - endif - nfsample=96000 - nxpol=1 - mode65=2 - ifile1=1 - if(arg.eq.'95238') then - nfsample=95238 - call getarg(2,arg) - ifile1=2 - endif - - limtrace=0 - lu=12 - nfa=100 - nfb=162 - nfshift=6 - ndepth=2 - nfcal=344 - idphi=-50 - ntol=500 - nkeep=10 - - call ftninit('.') - - do ifile=ifile1,nargs - call getarg(ifile,infile) - open(10,file=infile,access='stream',status='old',err=998) - i1=index(infile,'.tf2') - read(infile(i1-4:i1-1),*,err=1) nutc0 - go to 2 -1 nutc0=0 -2 hsym=2048.d0*96000.d0/11025.d0 !Samples per half symbol - nhsym0=-999 - k=0 - fcenter=144.125d0 - mousedf=0 - mousefqso=125 - newdat=1 - mycall='K1JT' - - if(ifile.eq.ifile1) call timer('m65 ',0) - do irec=1,9999999 - call timer('read_tf2',0) - read(10) i2 - call timer('read_tf2',1) - - call timer('float ',0) - do i=1,87 - k=k+1 - dd(1,k)=i2(1,i) - dd(2,k)=i2(2,i) - dd(3,k)=i2(3,i) - dd(4,k)=i2(4,i) - enddo - call timer('float ',1) - nhsym=(k-2048)/hsym - if(nhsym.ge.1 .and. nhsym.ne.nhsym0) then - ndiskdat=1 - nb=0 -! Emit signal readyForFFT - call timer('symspec ',0) - fgreen=-13.0 - iqadjust=1 - iqapply=1 - nbslider=100 - gainx=0.9962 - gainy=1.0265 - phasex=0.01426 - phasey=-0.01195 - call symspec(k,nxpol,ndiskdat,nb,nbslider,idphi,nfsample,fgreen, & - iqadjust,iqapply,gainx,gainy,phasex,phasey,rejectx,rejecty, & - pxdb,pydb,ssz5a,nkhz,ihsym,nzap,slimit,lstrong) - call timer('symspec ',1) - nhsym0=nhsym - if(ihsym.ge.278) go to 10 - endif - enddo - -10 continue - if(iqadjust.ne.0) write(*,3002) rejectx,rejecty -3002 format('Image rejection:',2f7.1,' dB') - nutc=nutc0 - nstandalone=1 - call decode0(dd,ss,savg,nstandalone,nfsample) - enddo - - call timer('m65 ',1) - call timer('m65 ',101) - call ftnquit - go to 999 - -998 print*,'Cannot open file:' - print*,infile - -999 end program m65 +program m65 + +! Decoder for map65. Can run stand-alone, reading data from *.tf2 files; +! or as the back end of map65, with data placed in a shared memory region. + + parameter (NSMAX=60*96000) + parameter (NFFT=32768) + integer*2 i2(4,87) + real*8 hsym + real*4 ssz5a(NFFT) + logical*1 lstrong(0:1023) + common/tracer/limtrace,lu + real*8 fc0,fcenter + character*80 arg,infile + character mycall*12,hiscall*12,mygrid*6,hisgrid*6,datetime*20 + common/datcom/dd(4,5760000),ss(4,322,NFFT),savg(4,NFFT),fc0,nutc0,junk(34) + common/npar/fcenter,nutc,idphi,mousedf,mousefqso,nagain, & + ndepth,ndiskdat,neme,newdat,nfa,nfb,nfcal,nfshift, & + mcall3,nkeep,ntol,nxant,nrxlog,nfsample,nxpol,mode65, & + mycall,mygrid,hiscall,hisgrid,datetime + + nargs=iargc() + if(nargs.lt.1) then + print*,'Usage: m65 [95238] file1 [file2 ...]' + print*,' Reads data from *.tf2 files.' + print*,'' + print*,' m65 -s' + print*,' Gets data from shared memory region.' + go to 999 + endif + call getarg(1,arg) + if(arg(1:2).eq.'-s') then + call m65a + call ftnquit + go to 999 + endif + nfsample=96000 + nxpol=1 + mode65=2 + ifile1=1 + if(arg.eq.'95238') then + nfsample=95238 + call getarg(2,arg) + ifile1=2 + endif + + limtrace=0 + lu=12 + nfa=100 + nfb=162 + nfshift=6 + ndepth=2 + nfcal=344 + idphi=-50 + ntol=500 + nkeep=10 + + call ftninit('.') + + do ifile=ifile1,nargs + call getarg(ifile,infile) + open(10,file=infile,access='stream',status='old',err=998) + i1=index(infile,'.tf2') + read(infile(i1-4:i1-1),*,err=1) nutc0 + go to 2 +1 nutc0=0 +2 hsym=2048.d0*96000.d0/11025.d0 !Samples per half symbol + nhsym0=-999 + k=0 + fcenter=144.125d0 + mousedf=0 + mousefqso=125 + newdat=1 + mycall='K1JT' + + if(ifile.eq.ifile1) call timer('m65 ',0) + do irec=1,9999999 + call timer('read_tf2',0) + read(10) i2 + call timer('read_tf2',1) + + call timer('float ',0) + do i=1,87 + k=k+1 + dd(1,k)=i2(1,i) + dd(2,k)=i2(2,i) + dd(3,k)=i2(3,i) + dd(4,k)=i2(4,i) + enddo + call timer('float ',1) + nhsym=(k-2048)/hsym + if(nhsym.ge.1 .and. nhsym.ne.nhsym0) then + ndiskdat=1 + nb=0 +! Emit signal readyForFFT + call timer('symspec ',0) + fgreen=-13.0 + iqadjust=1 + iqapply=1 + nbslider=100 + gainx=0.9962 + gainy=1.0265 + phasex=0.01426 + phasey=-0.01195 + call symspec(k,nxpol,ndiskdat,nb,nbslider,idphi,nfsample,fgreen, & + iqadjust,iqapply,gainx,gainy,phasex,phasey,rejectx,rejecty, & + pxdb,pydb,ssz5a,nkhz,ihsym,nzap,slimit,lstrong) + call timer('symspec ',1) + nhsym0=nhsym + if(ihsym.ge.278) go to 10 + endif + enddo + +10 continue + if(iqadjust.ne.0) write(*,3002) rejectx,rejecty +3002 format('Image rejection:',2f7.1,' dB') + nutc=nutc0 + nstandalone=1 + call decode0(dd,ss,savg,nstandalone,nfsample) + enddo + + call timer('m65 ',1) + call timer('m65 ',101) + call ftnquit + go to 999 + +998 print*,'Cannot open file:' + print*,infile + +999 end program m65 diff --git a/libm65/m65a.F90 b/libm65/m65a.F90 index 2f5db5562..b5fc4b11f 100644 --- a/libm65/m65a.F90 +++ b/libm65/m65a.F90 @@ -1,97 +1,97 @@ -subroutine m65a - -! NB: this interface block is required by g95, but must be omitted -! for gfortran. (????) - -#ifndef UNIX - interface - function address_m65() - end function address_m65 - end interface -#endif - - integer*1 attach_m65,lock_m65,unlock_m65 - integer size_m65 - integer*1, pointer :: address_m65,p_m65 - character*80 cwd - logical fileExists - common/tracer/limtrace,lu - - call getcwd(cwd) - call ftninit(trim(cwd)) - limtrace=0 - lu=12 - i1=attach_m65() - -10 inquire(file=trim(cwd)//'/.lock',exist=fileExists) - if(fileExists) then - call sleep_msec(100) - go to 10 - endif - - inquire(file=trim(cwd)//'/.quit',exist=fileExists) - if(fileExists) then - call ftnquit - i=detach_m65() - go to 999 - endif - - nbytes=size_m65() - if(nbytes.le.0) then - print*,'m65a: Shared memory mem_m65 does not exist.' - print*,'Program m65a should be started automatically from within map65.' - go to 999 - endif - p_m65=>address_m65() - call m65b(p_m65,nbytes) - - write(*,1010) -1010 format('') - flush(6) - -100 inquire(file=trim(cwd)//'/.lock',exist=fileExists) - if(fileExists) go to 10 - call sleep_msec(100) - go to 100 - -999 return -end subroutine m65a - -subroutine m65b(m65com,nbytes) - integer*1 m65com(0:nbytes-1) - kss=4*4*60*96000 - ksavg=kss+4*4*322*32768 - kfcenter=ksavg+4*4*32768 - call m65c(m65com(0),m65com(kss),m65com(ksavg),m65com(kfcenter)) - return -end subroutine m65b - -subroutine m65c(dd,ss,savg,nparams0) - integer*1 detach_m65 - real*4 dd(4,5760000),ss(4,322,32768),savg(4,32768) - real*8 fcenter - integer nparams0(37),nparams(37) - character*12 mycall,hiscall - character*6 mygrid,hisgrid - character*20 datetime - common/npar/fcenter,nutc,idphi,mousedf,mousefqso,nagain, & - ndepth,ndiskdat,neme,newdat,nfa,nfb,nfcal,nfshift, & - mcall3,nkeep,ntol,nxant,nrxlog,nfsample,nxpol,mode65, & - mycall,mygrid,hiscall,hisgrid,datetime - equivalence (nparams,fcenter) - - nparams=nparams0 !Copy parameters into common/npar/ - npatience=1 - if(iand(nrxlog,1).ne.0) then - write(21,1000) datetime(:17) -1000 format(/'UTC Date: 'a17/78('-')) - flush(21) - endif - if(iand(nrxlog,2).ne.0) rewind 21 - if(iand(nrxlog,4).ne.0) rewind 26 - - nstandalone=0 - if(sum(nparams).ne.0) call decode0(dd,ss,savg,nstandalone) - - return -end subroutine m65c +subroutine m65a + +! NB: this interface block is required by g95, but must be omitted +! for gfortran. (????) + +#ifndef UNIX + interface + function address_m65() + end function address_m65 + end interface +#endif + + integer*1 attach_m65,lock_m65,unlock_m65 + integer size_m65 + integer*1, pointer :: address_m65,p_m65 + character*80 cwd + logical fileExists + common/tracer/limtrace,lu + + call getcwd(cwd) + call ftninit(trim(cwd)) + limtrace=0 + lu=12 + i1=attach_m65() + +10 inquire(file=trim(cwd)//'/.lock',exist=fileExists) + if(fileExists) then + call sleep_msec(100) + go to 10 + endif + + inquire(file=trim(cwd)//'/.quit',exist=fileExists) + if(fileExists) then + call ftnquit + i=detach_m65() + go to 999 + endif + + nbytes=size_m65() + if(nbytes.le.0) then + print*,'m65a: Shared memory mem_m65 does not exist.' + print*,'Program m65a should be started automatically from within map65.' + go to 999 + endif + p_m65=>address_m65() + call m65b(p_m65,nbytes) + + write(*,1010) +1010 format('') + flush(6) + +100 inquire(file=trim(cwd)//'/.lock',exist=fileExists) + if(fileExists) go to 10 + call sleep_msec(100) + go to 100 + +999 return +end subroutine m65a + +subroutine m65b(m65com,nbytes) + integer*1 m65com(0:nbytes-1) + kss=4*4*60*96000 + ksavg=kss+4*4*322*32768 + kfcenter=ksavg+4*4*32768 + call m65c(m65com(0),m65com(kss),m65com(ksavg),m65com(kfcenter)) + return +end subroutine m65b + +subroutine m65c(dd,ss,savg,nparams0) + integer*1 detach_m65 + real*4 dd(4,5760000),ss(4,322,32768),savg(4,32768) + real*8 fcenter + integer nparams0(37),nparams(37) + character*12 mycall,hiscall + character*6 mygrid,hisgrid + character*20 datetime + common/npar/fcenter,nutc,idphi,mousedf,mousefqso,nagain, & + ndepth,ndiskdat,neme,newdat,nfa,nfb,nfcal,nfshift, & + mcall3,nkeep,ntol,nxant,nrxlog,nfsample,nxpol,mode65, & + mycall,mygrid,hiscall,hisgrid,datetime + equivalence (nparams,fcenter) + + nparams=nparams0 !Copy parameters into common/npar/ + npatience=1 + if(iand(nrxlog,1).ne.0) then + write(21,1000) datetime(:17) +1000 format(/'UTC Date: 'a17/78('-')) + flush(21) + endif + if(iand(nrxlog,2).ne.0) rewind 21 + if(iand(nrxlog,4).ne.0) rewind 26 + + nstandalone=0 + if(sum(nparams).ne.0) call decode0(dd,ss,savg,nstandalone) + + return +end subroutine m65c diff --git a/libm65/map65a.f90 b/libm65/map65a.f90 index b518bccc3..b9e848271 100644 --- a/libm65/map65a.f90 +++ b/libm65/map65a.f90 @@ -1,438 +1,438 @@ -subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, & - mousedf,mousefqso,nagain,ndecdone,ndiskdat,nfshift,ndphi, & - nfcal,nkeep,mcall3b,nsave,nxant,rmsdd,mycall,mygrid, & - neme,ndepth,hiscall,hisgrid,nhsym,nfsample,nxpol,mode65) - -! Processes timf2 data from Linrad to find and decode JT65 signals. - - parameter (MAXMSG=1000) !Size of decoded message list - parameter (NSMAX=60*96000) - parameter (NFFT=32768) - real dd(4,NSMAX) - real*4 ss(4,322,NFFT),savg(4,NFFT) - real tavg(-50:50) !Temp for finding local base level - real base(4) !Local basel level at 4 pol'ns - real tmp (200) !Temp storage for pctile sorting - real sig(MAXMSG,30) !Parameters of detected signals - real a(5) - real*8 fcenter - character*22 msg(MAXMSG) - character*3 shmsg0(4) - character mycall*12,hiscall*12,mygrid*6,hisgrid*6,grid*6,cp*1 - integer indx(MAXMSG),nsiz(MAXMSG) - logical done(MAXMSG) - logical xpol - character decoded*22,blank*22 - real short(3,NFFT) !SNR dt ipol for potential shorthands - real qphi(12) - common/c3com/ mcall3a - common/testcom/ifreq - - data blank/' '/ - data shmsg0/'ATT','RO ','RRR','73 '/ - data nfile/0/,nutc0/-999/,nid/0/,ip000/1/,ip001/1/,mousefqso0/-999/ - save - - mcall3a=mcall3b - mousefqso0=mousefqso - xpol=(nxpol.ne.0) - if(.not.xpol) ndphi=0 - -!### Should use AppDir! ### -! open(23,file='release/CALL3.TXT',status='unknown') - open(23,file='CALL3.TXT',status='unknown') - - if(nutc.ne.nutc0) nfile=nfile+1 - nutc0=nutc - df=96000.0/NFFT !df = 96000/NFFT = 2.930 Hz - if(nfsample.eq.95238) df=95238.1/NFFT - ftol=0.010 !Frequency tolerance (kHz) - dphi=idphi/57.2957795 - foffset=0.001*(1270 + nfcal) !Offset from sync tone, plus CAL - fqso=mousefqso + foffset - 0.5*(nfa+nfb) + nfshift !fqso at baseband (khz) - iloop=0 - -2 if(ndphi.eq.1) dphi=30*iloop/57.2957795 - - do nqd=1,0,-1 - if(nqd.eq.1) then !Quick decode, at fQSO - fa=1000.0*(fqso+0.001*mousedf) - ntol - fb=1000.0*(fqso+0.001*mousedf) + ntol + 4*53.8330078 - else !Wideband decode at all freqs - fa=-1000*0.5*(nfb-nfa) + 1000*nfshift - fb= 1000*0.5*(nfb-nfa) + 1000*nfshift - endif - ia=nint(fa/df) + 16385 - ib=nint(fb/df) + 16385 - ia=max(51,ia) - ib=min(32768-51,ib) - - km=0 - nkm=1 - nz=n/8 - freq0=-999. - sync10=-999. - fshort0=-999. - syncshort0=-999. - ntry=0 - short=0. !Zero the whole short array - jpz=1 - if(xpol) jpz=4 - - do i=ia,ib !Search over freq range - freq=0.001*(i-16385)*df -! Find the local base level for each polarization; update every 10 bins. - if(mod(i-ia,10).eq.0) then - do jp=1,jpz - do ii=-50,50 - iii=i+ii - if(iii.ge.1 .and. iii.le.32768) then - tavg(ii)=savg(jp,iii) - else - write(13,*) ,'Error in iii:',iii,ia,ib,fa,fb - flush(13) - go to 999 - endif - enddo - call pctile(tavg,tmp,101,50,base(jp)) - enddo - endif - -! Find max signal at this frequency - smax=0. - do jp=1,jpz - if(savg(jp,i)/base(jp).gt.smax) then - smax=savg(jp,i)/base(jp) - jpmax=jp - endif - enddo - - if(smax.gt.1.1) then - -! Look for JT65 sync patterns and shorthand square-wave patterns. - call timer('ccf65 ',0) -! ssmax=4.0*(rmsdd/22.5)**2 - ssmax=savg(jpmax,i) - call ccf65(ss(1,1,i),nhsym,ssmax,sync1,ipol,jpz,dt,flipk, & - syncshort,snr2,ipol2,dt2) - call timer('ccf65 ',1) - -! ########################### Search for Shorthand Messages ################# -! Is there a shorthand tone above threshold? - thresh0=1.0 -! Use lower thresh0 at fQSO - if(nqd.eq.1 .and. ntol.le.100) thresh0=0. - if(syncshort.gt.thresh0) then -! ### Do shorthand AFC here (or maybe after finding a pair?) ### - short(1,i)=syncshort - short(2,i)=dt2 - short(3,i)=ipol2 - -! Check to see if lower tone of shorthand pair was found. - do j=2,4 - i0=i-nint(j*mode65*10.0*(11025.0/4096.0)/df) -! Should this be i0 +/- 1, or just i0? -! Should we also insist that difference in DT be either 1.5 or -1.5 s? - if(short(1,i0).gt.thresh0) then - fshort=0.001*(i0-16385)*df - noffset=0 - if(nqd.eq.1) noffset=nint(1000.0*(fshort-fqso)-mousedf) - if(abs(noffset).le.ntol) then -! Keep only the best candidate within ftol. -!### NB: sync2 was not defined here! -! sync2=syncshort !### try this ??? - if(fshort-fshort0.le.ftol .and. syncshort.gt.syncshort0 & - .and. nkm.eq.2) km=km-1 - if(fshort-fshort0.gt.ftol .or. & - syncshort.gt.syncshort0) then - if(km.lt.MAXMSG) km=km+1 - sig(km,1)=nfile - sig(km,2)=nutc - sig(km,3)=fshort + 0.5*(nfa+nfb) - sig(km,4)=syncshort - sig(km,5)=dt2 - sig(km,6)=45*(ipol2-1)/57.2957795 - sig(km,7)=0 - sig(km,8)=snr2 - sig(km,9)=0 - sig(km,10)=0 -! sig(km,11)=rms0 - sig(km,12)=savg(ipol2,i) - sig(km,13)=0 - sig(km,14)=0 - sig(km,15)=0 - sig(km,16)=0 -! sig(km,17)=0 - sig(km,18)=0 - msg(km)=shmsg0(j) - fshort0=fshort - syncshort0=syncshort - nkm=2 - endif - endif - endif - enddo - endif - -! ########################### Search for Normal Messages ########### -! Is sync1 above threshold? - thresh1=1.0 -! Use lower thresh1 at fQSO - if(nqd.eq.1 .and. ntol.le.100) thresh1=0. - noffset=0 - if(nqd.eq.1) noffset=nint(1000.0*(freq-fqso)-mousedf) - - if(sync1.gt.thresh1 .and. abs(noffset).le.ntol) then -! Keep only the best candidate within ftol. -! (Am I deleting any good decodes by doing this?) - if(freq-freq0.le.ftol .and. sync1.gt.sync10 .and. & - nkm.eq.1) km=km-1 - if(freq-freq0.gt.ftol .or. sync1.gt.sync10) then - nflip=nint(flipk) - f00=(i-1)*df !Freq of detected sync tone (0-96000 Hz) - ntry=ntry+1 - if((nqd.eq.1 .and. ntry.ge.40) .or. & - (nqd.eq.0 .and. ntry.ge.400)) then -! Too many calls to decode1a! - write(*,*) '! Signal too strong? Decoding aborted.' - write(13,*) 'Signal too strong? Decoding aborted.' - call flush(13) - go to 999 - endif - call timer('decode1a',0) - ifreq=i - ikHz=nint(freq+0.5*(nfa+nfb)-foffset)-nfshift - idf=nint(1000.0*(freq+0.5*(nfa+nfb)-foffset-(ikHz+nfshift))) - call decode1a(dd,newdat,f00,nflip,mode65,nfsample,xpol, & - mycall,hiscall,hisgrid,neme,ndepth,nqd,dphi, & - nutc,ikHz,idf,ipol,sync2,a,dt,pol,nkv,nhist,qual,decoded) - dt=dt+0.8 !### empirical tweak - call timer('decode1a',1) - - if(km.lt.MAXMSG) km=km+1 - sig(km,1)=nfile - sig(km,2)=nutc - sig(km,3)=freq + 0.5*(nfa+nfb) - sig(km,4)=sync1 - sig(km,5)=dt - sig(km,6)=pol - sig(km,7)=flipk - sig(km,8)=sync2 - sig(km,9)=nkv - sig(km,10)=qual -! sig(km,11)=idphi - sig(km,12)=savg(ipol,i) - sig(km,13)=a(1) - sig(km,14)=a(2) - sig(km,15)=a(3) - sig(km,16)=a(4) -! sig(km,17)=a(5) - sig(km,18)=nhist - msg(km)=decoded - freq0=freq - sync10=sync1 - nkm=1 - endif - endif - endif -!70 continue - enddo - - if(nqd.eq.1) then - nwrite=0 - do k=1,km - decoded=msg(k) - if(decoded.ne.' ') then - nutc=sig(k,2) - freq=sig(k,3) - sync1=sig(k,4) - dt=sig(k,5) - npol=nint(57.2957795*sig(k,6)) - flip=sig(k,7) - sync2=sig(k,8) - nkv=sig(k,9) - nqual=sig(k,10) -! idphi=nint(sig(k,11)) - if(flip.lt.0.0) then - do i=22,1,-1 - if(decoded(i:i).ne.' ') go to 8 - enddo - stop 'Error in message format' -8 if(i.le.18) decoded(i+2:i+4)='OOO' - endif - nkHz=nint(freq-foffset)-nfshift - mhz=fcenter ! ... +fadd ??? - f0=mhz+0.001*nkHz - ndf=nint(1000.0*(freq-foffset-(nkHz+nfshift))) - nsync1=sync1 - nsync2=nint(10.0*log10(sync2)) - 40 !### empirical ### - if(decoded(1:4).eq.'RO ' .or. decoded(1:4).eq.'RRR ' .or. & - decoded(1:4).eq.'73 ') nsync2=nsync2-6 - nwrite=nwrite+1 - if(nxant.ne.0) then - npol=npol-45 - if(npol.lt.0) npol=npol+180 - endif - -! If Tx station's grid is in decoded message, compute optimum TxPol - i1=index(decoded,' ') - i2=index(decoded(i1+1:),' ') + i1 - grid=' ' - if(i2.ge.8 .and. i2.le.18) grid=decoded(i2+1:i2+4)//'mm' - ntxpol=0 - cp=' ' - if(xpol) then - if(grid(1:1).ge.'A' .and. grid(1:1).le.'R' .and. & - grid(2:2).ge.'A' .and. grid(2:2).le.'R' .and. & - grid(3:3).ge.'0' .and. grid(3:3).le.'9' .and. & - grid(4:4).ge.'0' .and. grid(4:4).le.'9') then - ntxpol=mod(npol-nint(2.0*dpol(mygrid,grid))+720,180) - if(nxant.eq.0) then - cp='H' - if(ntxpol.gt.45 .and. ntxpol.le.135) cp='V' - else - cp='/' - if(ntxpol.ge.90 .and. ntxpol.lt.180) cp='\\' - endif - endif - endif - - if(ndphi.eq.0) then - write(*,1010) nkHz,ndf,npol,nutc,dt,nsync2, & - decoded,nkv,nqual,ntxpol,cp -1010 format('!',i3,i5,i4,i5.4,f5.1,i4,2x,a22,i5,i4,i5,1x,a1) - else - if(iloop.ge.1) qphi(iloop)=sig(k,10) - write(*,1010) nkHz,ndf,npol,nutc,dt,nsync2, & - decoded,nkv,nqual,30*iloop - write(27,1011) 30*iloop,nkHz,ndf,npol,nutc, & - dt,sync2,nkv,nqual,decoded -1011 format(i3,i4,i5,i4,i5.4,f5.1,f7.1,i3,i5,2x,a22) - endif - endif - enddo - - if(nwrite.eq.0) then - write(*,1012) mousefqso,nutc -1012 format('!',i3,9x,i5.4,' ') - endif - - endif - if(ndphi.eq.1 .and.iloop.lt.12) then - iloop=iloop+1 - go to 2 - endif - - if(ndphi.eq.1 .and.iloop.eq.12) call getdphi(qphi) - if(nagain.eq.1) go to 999 - enddo - -! Trim the list and produce a sorted index and sizes of groups. -! (Should trimlist remove all but best SNR for given UTC and message content?) - call trimlist(sig,km,ftol,indx,nsiz,nz) - - do i=1,km - done(i)=.false. - enddo - j=0 - ilatest=-1 - do n=1,nz - ifile0=0 - do m=1,nsiz(n) - i=indx(j+m) - ifile=sig(i,1) - if(ifile.gt.ifile0 .and.msg(i).ne.blank) then - ilatest=i - ifile0=ifile - endif - enddo - i=ilatest - - if(i.ge.1) then - if(.not.done(i)) then - done(i)=.true. - nutc=sig(i,2) - freq=sig(i,3) - sync1=sig(i,4) - dt=sig(i,5) - npol=nint(57.2957795*sig(i,6)) - flip=sig(i,7) - sync2=sig(i,8) - nkv=sig(i,9) - nqual=min(sig(i,10),10.0) -! rms0=sig(i,11) - do k=1,5 - a(k)=sig(i,12+k) - enddo - nhist=sig(i,18) - decoded=msg(i) - - if(flip.lt.0.0) then - do i=22,1,-1 - if(decoded(i:i).ne.' ') go to 10 - enddo - stop 'Error in message format' -10 if(i.le.18) decoded(i+2:i+4)='OOO' - endif - mhz=fcenter !... +fadd ??? - nkHz=nint(freq-foffset)-nfshift - f0=mhz+0.001*nkHz - ndf=nint(1000.0*(freq-foffset-(nkHz+nfshift))) - ndf0=nint(a(1)) - ndf1=nint(a(2)) - ndf2=nint(a(3)) - nsync1=sync1 - nsync2=nint(10.0*log10(sync2)) - 40 !### empirical ### - if(decoded(1:4).eq.'RO ' .or. decoded(1:4).eq.'RRR ' .or. & - decoded(1:4).eq.'73 ') nsync2=nsync2-6 - if(nxant.ne.0) then - npol=npol-45 - if(npol.lt.0) npol=npol+180 - endif - -! If Tx station's grid is in decoded message, compute optimum TxPol - i1=index(decoded,' ') - i2=index(decoded(i1+1:),' ') + i1 - grid=' ' - if(i2.ge.8 .and. i2.le.18) grid=decoded(i2+1:i2+4)//'mm' - ntxpol=0 - cp=' ' - if(xpol) then - if(grid(1:1).ge.'A' .and. grid(1:1).le.'R' .and. & - grid(2:2).ge.'A' .and. grid(2:2).le.'R' .and. & - grid(3:3).ge.'0' .and. grid(3:3).le.'9' .and. & - grid(4:4).ge.'0' .and. grid(4:4).le.'9') then - ntxpol=mod(npol-nint(2.0*dpol(mygrid,grid))+720,180) - if(nxant.eq.0) then - cp='H' - if(ntxpol.gt.45 .and. ntxpol.le.135) cp='V' - else - cp='/' - if(ntxpol.ge.90 .and. ntxpol.lt.180) cp='\\' - endif - endif - endif - write(26,1014) f0,ndf,ndf0,ndf1,ndf2,dt,npol,nsync1, & - nsync2,nutc,decoded,nkv,nqual,nhist,cp - write(21,1014) f0,ndf,ndf0,ndf1,ndf2,dt,npol,nsync1, & - nsync2,nutc,decoded,nkv,nqual,nhist -1014 format(f8.3,i5,3i3,f5.1,i4,i3,i4,i5.4,2x,a22,3i3,1x,a1) - - endif - endif - j=j+nsiz(n) - enddo - write(26,1015) nutc -1015 format(39x,i4.4) - call flush(21) - call flush(26) - call display(nkeep,ftol) - ndecdone=2 - -999 close(23) - ndphi=0 - nagain=0 - mcall3b=mcall3a - - return -end subroutine map65a +subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, & + mousedf,mousefqso,nagain,ndecdone,ndiskdat,nfshift,ndphi, & + nfcal,nkeep,mcall3b,nsave,nxant,rmsdd,mycall,mygrid, & + neme,ndepth,hiscall,hisgrid,nhsym,nfsample,nxpol,mode65) + +! Processes timf2 data from Linrad to find and decode JT65 signals. + + parameter (MAXMSG=1000) !Size of decoded message list + parameter (NSMAX=60*96000) + parameter (NFFT=32768) + real dd(4,NSMAX) + real*4 ss(4,322,NFFT),savg(4,NFFT) + real tavg(-50:50) !Temp for finding local base level + real base(4) !Local basel level at 4 pol'ns + real tmp (200) !Temp storage for pctile sorting + real sig(MAXMSG,30) !Parameters of detected signals + real a(5) + real*8 fcenter + character*22 msg(MAXMSG) + character*3 shmsg0(4) + character mycall*12,hiscall*12,mygrid*6,hisgrid*6,grid*6,cp*1 + integer indx(MAXMSG),nsiz(MAXMSG) + logical done(MAXMSG) + logical xpol + character decoded*22,blank*22 + real short(3,NFFT) !SNR dt ipol for potential shorthands + real qphi(12) + common/c3com/ mcall3a + common/testcom/ifreq + + data blank/' '/ + data shmsg0/'ATT','RO ','RRR','73 '/ + data nfile/0/,nutc0/-999/,nid/0/,ip000/1/,ip001/1/,mousefqso0/-999/ + save + + mcall3a=mcall3b + mousefqso0=mousefqso + xpol=(nxpol.ne.0) + if(.not.xpol) ndphi=0 + +!### Should use AppDir! ### +! open(23,file='release/CALL3.TXT',status='unknown') + open(23,file='CALL3.TXT',status='unknown') + + if(nutc.ne.nutc0) nfile=nfile+1 + nutc0=nutc + df=96000.0/NFFT !df = 96000/NFFT = 2.930 Hz + if(nfsample.eq.95238) df=95238.1/NFFT + ftol=0.010 !Frequency tolerance (kHz) + dphi=idphi/57.2957795 + foffset=0.001*(1270 + nfcal) !Offset from sync tone, plus CAL + fqso=mousefqso + foffset - 0.5*(nfa+nfb) + nfshift !fqso at baseband (khz) + iloop=0 + +2 if(ndphi.eq.1) dphi=30*iloop/57.2957795 + + do nqd=1,0,-1 + if(nqd.eq.1) then !Quick decode, at fQSO + fa=1000.0*(fqso+0.001*mousedf) - ntol + fb=1000.0*(fqso+0.001*mousedf) + ntol + 4*53.8330078 + else !Wideband decode at all freqs + fa=-1000*0.5*(nfb-nfa) + 1000*nfshift + fb= 1000*0.5*(nfb-nfa) + 1000*nfshift + endif + ia=nint(fa/df) + 16385 + ib=nint(fb/df) + 16385 + ia=max(51,ia) + ib=min(32768-51,ib) + + km=0 + nkm=1 + nz=n/8 + freq0=-999. + sync10=-999. + fshort0=-999. + syncshort0=-999. + ntry=0 + short=0. !Zero the whole short array + jpz=1 + if(xpol) jpz=4 + + do i=ia,ib !Search over freq range + freq=0.001*(i-16385)*df +! Find the local base level for each polarization; update every 10 bins. + if(mod(i-ia,10).eq.0) then + do jp=1,jpz + do ii=-50,50 + iii=i+ii + if(iii.ge.1 .and. iii.le.32768) then + tavg(ii)=savg(jp,iii) + else + write(13,*) ,'Error in iii:',iii,ia,ib,fa,fb + flush(13) + go to 999 + endif + enddo + call pctile(tavg,tmp,101,50,base(jp)) + enddo + endif + +! Find max signal at this frequency + smax=0. + do jp=1,jpz + if(savg(jp,i)/base(jp).gt.smax) then + smax=savg(jp,i)/base(jp) + jpmax=jp + endif + enddo + + if(smax.gt.1.1) then + +! Look for JT65 sync patterns and shorthand square-wave patterns. + call timer('ccf65 ',0) +! ssmax=4.0*(rmsdd/22.5)**2 + ssmax=savg(jpmax,i) + call ccf65(ss(1,1,i),nhsym,ssmax,sync1,ipol,jpz,dt,flipk, & + syncshort,snr2,ipol2,dt2) + call timer('ccf65 ',1) + +! ########################### Search for Shorthand Messages ################# +! Is there a shorthand tone above threshold? + thresh0=1.0 +! Use lower thresh0 at fQSO + if(nqd.eq.1 .and. ntol.le.100) thresh0=0. + if(syncshort.gt.thresh0) then +! ### Do shorthand AFC here (or maybe after finding a pair?) ### + short(1,i)=syncshort + short(2,i)=dt2 + short(3,i)=ipol2 + +! Check to see if lower tone of shorthand pair was found. + do j=2,4 + i0=i-nint(j*mode65*10.0*(11025.0/4096.0)/df) +! Should this be i0 +/- 1, or just i0? +! Should we also insist that difference in DT be either 1.5 or -1.5 s? + if(short(1,i0).gt.thresh0) then + fshort=0.001*(i0-16385)*df + noffset=0 + if(nqd.eq.1) noffset=nint(1000.0*(fshort-fqso)-mousedf) + if(abs(noffset).le.ntol) then +! Keep only the best candidate within ftol. +!### NB: sync2 was not defined here! +! sync2=syncshort !### try this ??? + if(fshort-fshort0.le.ftol .and. syncshort.gt.syncshort0 & + .and. nkm.eq.2) km=km-1 + if(fshort-fshort0.gt.ftol .or. & + syncshort.gt.syncshort0) then + if(km.lt.MAXMSG) km=km+1 + sig(km,1)=nfile + sig(km,2)=nutc + sig(km,3)=fshort + 0.5*(nfa+nfb) + sig(km,4)=syncshort + sig(km,5)=dt2 + sig(km,6)=45*(ipol2-1)/57.2957795 + sig(km,7)=0 + sig(km,8)=snr2 + sig(km,9)=0 + sig(km,10)=0 +! sig(km,11)=rms0 + sig(km,12)=savg(ipol2,i) + sig(km,13)=0 + sig(km,14)=0 + sig(km,15)=0 + sig(km,16)=0 +! sig(km,17)=0 + sig(km,18)=0 + msg(km)=shmsg0(j) + fshort0=fshort + syncshort0=syncshort + nkm=2 + endif + endif + endif + enddo + endif + +! ########################### Search for Normal Messages ########### +! Is sync1 above threshold? + thresh1=1.0 +! Use lower thresh1 at fQSO + if(nqd.eq.1 .and. ntol.le.100) thresh1=0. + noffset=0 + if(nqd.eq.1) noffset=nint(1000.0*(freq-fqso)-mousedf) + + if(sync1.gt.thresh1 .and. abs(noffset).le.ntol) then +! Keep only the best candidate within ftol. +! (Am I deleting any good decodes by doing this?) + if(freq-freq0.le.ftol .and. sync1.gt.sync10 .and. & + nkm.eq.1) km=km-1 + if(freq-freq0.gt.ftol .or. sync1.gt.sync10) then + nflip=nint(flipk) + f00=(i-1)*df !Freq of detected sync tone (0-96000 Hz) + ntry=ntry+1 + if((nqd.eq.1 .and. ntry.ge.40) .or. & + (nqd.eq.0 .and. ntry.ge.400)) then +! Too many calls to decode1a! + write(*,*) '! Signal too strong? Decoding aborted.' + write(13,*) 'Signal too strong? Decoding aborted.' + call flush(13) + go to 999 + endif + call timer('decode1a',0) + ifreq=i + ikHz=nint(freq+0.5*(nfa+nfb)-foffset)-nfshift + idf=nint(1000.0*(freq+0.5*(nfa+nfb)-foffset-(ikHz+nfshift))) + call decode1a(dd,newdat,f00,nflip,mode65,nfsample,xpol, & + mycall,hiscall,hisgrid,neme,ndepth,nqd,dphi, & + nutc,ikHz,idf,ipol,sync2,a,dt,pol,nkv,nhist,qual,decoded) + dt=dt+0.8 !### empirical tweak + call timer('decode1a',1) + + if(km.lt.MAXMSG) km=km+1 + sig(km,1)=nfile + sig(km,2)=nutc + sig(km,3)=freq + 0.5*(nfa+nfb) + sig(km,4)=sync1 + sig(km,5)=dt + sig(km,6)=pol + sig(km,7)=flipk + sig(km,8)=sync2 + sig(km,9)=nkv + sig(km,10)=qual +! sig(km,11)=idphi + sig(km,12)=savg(ipol,i) + sig(km,13)=a(1) + sig(km,14)=a(2) + sig(km,15)=a(3) + sig(km,16)=a(4) +! sig(km,17)=a(5) + sig(km,18)=nhist + msg(km)=decoded + freq0=freq + sync10=sync1 + nkm=1 + endif + endif + endif +!70 continue + enddo + + if(nqd.eq.1) then + nwrite=0 + do k=1,km + decoded=msg(k) + if(decoded.ne.' ') then + nutc=sig(k,2) + freq=sig(k,3) + sync1=sig(k,4) + dt=sig(k,5) + npol=nint(57.2957795*sig(k,6)) + flip=sig(k,7) + sync2=sig(k,8) + nkv=sig(k,9) + nqual=sig(k,10) +! idphi=nint(sig(k,11)) + if(flip.lt.0.0) then + do i=22,1,-1 + if(decoded(i:i).ne.' ') go to 8 + enddo + stop 'Error in message format' +8 if(i.le.18) decoded(i+2:i+4)='OOO' + endif + nkHz=nint(freq-foffset)-nfshift + mhz=fcenter ! ... +fadd ??? + f0=mhz+0.001*nkHz + ndf=nint(1000.0*(freq-foffset-(nkHz+nfshift))) + nsync1=sync1 + nsync2=nint(10.0*log10(sync2)) - 40 !### empirical ### + if(decoded(1:4).eq.'RO ' .or. decoded(1:4).eq.'RRR ' .or. & + decoded(1:4).eq.'73 ') nsync2=nsync2-6 + nwrite=nwrite+1 + if(nxant.ne.0) then + npol=npol-45 + if(npol.lt.0) npol=npol+180 + endif + +! If Tx station's grid is in decoded message, compute optimum TxPol + i1=index(decoded,' ') + i2=index(decoded(i1+1:),' ') + i1 + grid=' ' + if(i2.ge.8 .and. i2.le.18) grid=decoded(i2+1:i2+4)//'mm' + ntxpol=0 + cp=' ' + if(xpol) then + if(grid(1:1).ge.'A' .and. grid(1:1).le.'R' .and. & + grid(2:2).ge.'A' .and. grid(2:2).le.'R' .and. & + grid(3:3).ge.'0' .and. grid(3:3).le.'9' .and. & + grid(4:4).ge.'0' .and. grid(4:4).le.'9') then + ntxpol=mod(npol-nint(2.0*dpol(mygrid,grid))+720,180) + if(nxant.eq.0) then + cp='H' + if(ntxpol.gt.45 .and. ntxpol.le.135) cp='V' + else + cp='/' + if(ntxpol.ge.90 .and. ntxpol.lt.180) cp='\\' + endif + endif + endif + + if(ndphi.eq.0) then + write(*,1010) nkHz,ndf,npol,nutc,dt,nsync2, & + decoded,nkv,nqual,ntxpol,cp +1010 format('!',i3,i5,i4,i5.4,f5.1,i4,2x,a22,i5,i4,i5,1x,a1) + else + if(iloop.ge.1) qphi(iloop)=sig(k,10) + write(*,1010) nkHz,ndf,npol,nutc,dt,nsync2, & + decoded,nkv,nqual,30*iloop + write(27,1011) 30*iloop,nkHz,ndf,npol,nutc, & + dt,sync2,nkv,nqual,decoded +1011 format(i3,i4,i5,i4,i5.4,f5.1,f7.1,i3,i5,2x,a22) + endif + endif + enddo + + if(nwrite.eq.0) then + write(*,1012) mousefqso,nutc +1012 format('!',i3,9x,i5.4,' ') + endif + + endif + if(ndphi.eq.1 .and.iloop.lt.12) then + iloop=iloop+1 + go to 2 + endif + + if(ndphi.eq.1 .and.iloop.eq.12) call getdphi(qphi) + if(nagain.eq.1) go to 999 + enddo + +! Trim the list and produce a sorted index and sizes of groups. +! (Should trimlist remove all but best SNR for given UTC and message content?) + call trimlist(sig,km,ftol,indx,nsiz,nz) + + do i=1,km + done(i)=.false. + enddo + j=0 + ilatest=-1 + do n=1,nz + ifile0=0 + do m=1,nsiz(n) + i=indx(j+m) + ifile=sig(i,1) + if(ifile.gt.ifile0 .and.msg(i).ne.blank) then + ilatest=i + ifile0=ifile + endif + enddo + i=ilatest + + if(i.ge.1) then + if(.not.done(i)) then + done(i)=.true. + nutc=sig(i,2) + freq=sig(i,3) + sync1=sig(i,4) + dt=sig(i,5) + npol=nint(57.2957795*sig(i,6)) + flip=sig(i,7) + sync2=sig(i,8) + nkv=sig(i,9) + nqual=min(sig(i,10),10.0) +! rms0=sig(i,11) + do k=1,5 + a(k)=sig(i,12+k) + enddo + nhist=sig(i,18) + decoded=msg(i) + + if(flip.lt.0.0) then + do i=22,1,-1 + if(decoded(i:i).ne.' ') go to 10 + enddo + stop 'Error in message format' +10 if(i.le.18) decoded(i+2:i+4)='OOO' + endif + mhz=fcenter !... +fadd ??? + nkHz=nint(freq-foffset)-nfshift + f0=mhz+0.001*nkHz + ndf=nint(1000.0*(freq-foffset-(nkHz+nfshift))) + ndf0=nint(a(1)) + ndf1=nint(a(2)) + ndf2=nint(a(3)) + nsync1=sync1 + nsync2=nint(10.0*log10(sync2)) - 40 !### empirical ### + if(decoded(1:4).eq.'RO ' .or. decoded(1:4).eq.'RRR ' .or. & + decoded(1:4).eq.'73 ') nsync2=nsync2-6 + if(nxant.ne.0) then + npol=npol-45 + if(npol.lt.0) npol=npol+180 + endif + +! If Tx station's grid is in decoded message, compute optimum TxPol + i1=index(decoded,' ') + i2=index(decoded(i1+1:),' ') + i1 + grid=' ' + if(i2.ge.8 .and. i2.le.18) grid=decoded(i2+1:i2+4)//'mm' + ntxpol=0 + cp=' ' + if(xpol) then + if(grid(1:1).ge.'A' .and. grid(1:1).le.'R' .and. & + grid(2:2).ge.'A' .and. grid(2:2).le.'R' .and. & + grid(3:3).ge.'0' .and. grid(3:3).le.'9' .and. & + grid(4:4).ge.'0' .and. grid(4:4).le.'9') then + ntxpol=mod(npol-nint(2.0*dpol(mygrid,grid))+720,180) + if(nxant.eq.0) then + cp='H' + if(ntxpol.gt.45 .and. ntxpol.le.135) cp='V' + else + cp='/' + if(ntxpol.ge.90 .and. ntxpol.lt.180) cp='\\' + endif + endif + endif + write(26,1014) f0,ndf,ndf0,ndf1,ndf2,dt,npol,nsync1, & + nsync2,nutc,decoded,nkv,nqual,nhist,cp + write(21,1014) f0,ndf,ndf0,ndf1,ndf2,dt,npol,nsync1, & + nsync2,nutc,decoded,nkv,nqual,nhist +1014 format(f8.3,i5,3i3,f5.1,i4,i3,i4,i5.4,2x,a22,3i3,1x,a1) + + endif + endif + j=j+nsiz(n) + enddo + write(26,1015) nutc +1015 format(39x,i4.4) + call flush(21) + call flush(26) + call display(nkeep,ftol) + ndecdone=2 + +999 close(23) + ndphi=0 + nagain=0 + mcall3b=mcall3a + + return +end subroutine map65a diff --git a/libm65/moon2.f b/libm65/moon2.f index c2ab106dc..8144b675f 100644 --- a/libm65/moon2.f +++ b/libm65/moon2.f @@ -1,167 +1,167 @@ - subroutine moon2(y,m,Day,UT,lon,lat,RA,Dec,topRA,topDec, - + LST,HA,Az,El,dist) - - implicit none - - integer y !Year - integer m !Month - integer Day !Day - real*8 UT !UTC in hours - real*8 RA,Dec !RA and Dec of moon - -C NB: Double caps are single caps in the writeup. - - real*8 NN !Longitude of ascending node - real*8 i !Inclination to the ecliptic - real*8 w !Argument of perigee - real*8 a !Semi-major axis - real*8 e !Eccentricity - real*8 MM !Mean anomaly - - real*8 v !True anomaly - real*8 EE !Eccentric anomaly - real*8 ecl !Obliquity of the ecliptic - - real*8 d !Ephemeris time argument in days - real*8 r !Distance to sun, AU - real*8 xv,yv !x and y coords in ecliptic - real*8 lonecl,latecl !Ecliptic long and lat of moon - real*8 xg,yg,zg !Ecliptic rectangular coords - real*8 Ms !Mean anomaly of sun - real*8 ws !Argument of perihelion of sun - real*8 Ls !Mean longitude of sun (Ns=0) - real*8 Lm !Mean longitude of moon - real*8 DD !Mean elongation of moon - real*8 FF !Argument of latitude for moon - real*8 xe,ye,ze !Equatorial geocentric coords of moon - real*8 mpar !Parallax of moon (r_E / d) - real*8 lat,lon !Station coordinates on earth - real*8 gclat !Geocentric latitude - real*8 rho !Earth radius factor - real*8 GMST0,LST,HA - real*8 g - real*8 topRA,topDec !Topocentric coordinates of Moon - real*8 Az,El - real*8 dist - - real*8 rad,twopi,pi,pio2 - data rad/57.2957795131d0/,twopi/6.283185307d0/ - - d=367*y - 7*(y+(m+9)/12)/4 + 275*m/9 + Day - 730530 + UT/24.d0 - ecl = 23.4393d0 - 3.563d-7 * d - -C Orbital elements for Moon: - NN = 125.1228d0 - 0.0529538083d0 * d - i = 5.1454d0 - w = mod(318.0634d0 + 0.1643573223d0 * d + 360000.d0,360.d0) - a = 60.2666d0 - e = 0.054900d0 - MM = mod(115.3654d0 + 13.0649929509d0 * d + 360000.d0,360.d0) - - EE = MM + e*rad*sin(MM/rad) * (1.d0 + e*cos(MM/rad)) - EE = EE - (EE - e*rad*sin(EE/rad)-MM) / (1.d0 - e*cos(EE/rad)) - EE = EE - (EE - e*rad*sin(EE/rad)-MM) / (1.d0 - e*cos(EE/rad)) - - xv = a * (cos(EE/rad) - e) - yv = a * (sqrt(1.d0-e*e) * sin(EE/rad)) - - v = mod(rad*atan2(yv,xv)+720.d0,360.d0) - r = sqrt(xv*xv + yv*yv) - -C Get geocentric position in ecliptic rectangular coordinates: - - xg = r * (cos(NN/rad)*cos((v+w)/rad) - - + sin(NN/rad)*sin((v+w)/rad)*cos(i/rad)) - yg = r * (sin(NN/rad)*cos((v+w)/rad) + - + cos(NN/rad)*sin((v+w)/rad)*cos(i/rad)) - zg = r * (sin((v+w)/rad)*sin(i/rad)) - -C Ecliptic longitude and latitude of moon: - lonecl = mod(rad*atan2(yg/rad,xg/rad)+720.d0,360.d0) - latecl = rad*atan2(zg/rad,sqrt(xg*xg + yg*yg)/rad) - -C Now include orbital perturbations: - Ms = mod(356.0470d0 + 0.9856002585d0 * d + 3600000.d0,360.d0) - ws = 282.9404d0 + 4.70935d-5*d - Ls = mod(Ms + ws + 720.d0,360.d0) - Lm = mod(MM + w + NN+720.d0,360.d0) - DD = mod(Lm - Ls + 360.d0,360.d0) - FF = mod(Lm - NN + 360.d0,360.d0) - - lonecl = lonecl - + -1.274d0 * sin((MM-2.d0*DD)/rad) - + +0.658d0 * sin(2.d0*DD/rad) - + -0.186d0 * sin(Ms/rad) - + -0.059d0 * sin((2.d0*MM-2.d0*DD)/rad) - + -0.057d0 * sin((MM-2.d0*DD+Ms)/rad) - + +0.053d0 * sin((MM+2.d0*DD)/rad) - + +0.046d0 * sin((2.d0*DD-Ms)/rad) - + +0.041d0 * sin((MM-Ms)/rad) - + -0.035d0 * sin(DD/rad) - + -0.031d0 * sin((MM+Ms)/rad) - + -0.015d0 * sin((2.d0*FF-2.d0*DD)/rad) - + +0.011d0 * sin((MM-4.d0*DD)/rad) - - latecl = latecl - + -0.173d0 * sin((FF-2.d0*DD)/rad) - + -0.055d0 * sin((MM-FF-2.d0*DD)/rad) - + -0.046d0 * sin((MM+FF-2.d0*DD)/rad) - + +0.033d0 * sin((FF+2.d0*DD)/rad) - + +0.017d0 * sin((2.d0*MM+FF)/rad) - - r = 60.36298d0 - + - 3.27746d0*cos(MM/rad) - + - 0.57994d0*cos((MM-2.d0*DD)/rad) - + - 0.46357d0*cos(2.d0*DD/rad) - + - 0.08904d0*cos(2.d0*MM/rad) - + + 0.03865d0*cos((2.d0*MM-2.d0*DD)/rad) - + - 0.03237d0*cos((2.d0*DD-Ms)/rad) - + - 0.02688d0*cos((MM+2.d0*DD)/rad) - + - 0.02358d0*cos((MM-2.d0*DD+Ms)/rad) - + - 0.02030d0*cos((MM-Ms)/rad) - + + 0.01719d0*cos(DD/rad) - + + 0.01671d0*cos((MM+Ms)/rad) - - dist=r*6378.140d0 - -C Geocentric coordinates: -C Rectangular ecliptic coordinates of the moon: - - xg = r * cos(lonecl/rad)*cos(latecl/rad) - yg = r * sin(lonecl/rad)*cos(latecl/rad) - zg = r * sin(latecl/rad) - -C Rectangular equatorial coordinates of the moon: - xe = xg - ye = yg*cos(ecl/rad) - zg*sin(ecl/rad) - ze = yg*sin(ecl/rad) + zg*cos(ecl/rad) - -C Right Ascension, Declination: - RA = mod(rad*atan2(ye,xe)+360.d0,360.d0) - Dec = rad*atan2(ze,sqrt(xe*xe + ye*ye)) - -C Now convert to topocentric system: - mpar=rad*asin(1.d0/r) -C alt_topoc = alt_geoc - mpar*cos(alt_geoc) - gclat = lat - 0.1924d0*sin(2.d0*lat/rad) - rho = 0.99883d0 + 0.00167d0*cos(2.d0*lat/rad) - GMST0 = (Ls + 180.d0)/15.d0 - LST = mod(GMST0+UT+lon/15.d0+48.d0,24.d0) !LST in hours - HA = 15.d0*LST - RA !HA in degrees - g = rad*atan(tan(gclat/rad)/cos(HA/rad)) - topRA = RA - mpar*rho*cos(gclat/rad)*sin(HA/rad)/cos(Dec/rad) - topDec = Dec - mpar*rho*sin(gclat/rad)*sin((g-Dec)/rad)/sin(g/rad) - - HA = 15.d0*LST - topRA !HA in degrees - if(HA.gt.180.d0) HA=HA-360.d0 - if(HA.lt.-180.d0) HA=HA+360.d0 - - pi=0.5d0*twopi - pio2=0.5d0*pi - call dcoord(pi,pio2-lat/rad,0.d0,lat/rad,ha*twopi/360, - + topDec/rad,az,el) - Az=az*rad - El=El*rad - - return - end + subroutine moon2(y,m,Day,UT,lon,lat,RA,Dec,topRA,topDec, + + LST,HA,Az,El,dist) + + implicit none + + integer y !Year + integer m !Month + integer Day !Day + real*8 UT !UTC in hours + real*8 RA,Dec !RA and Dec of moon + +C NB: Double caps are single caps in the writeup. + + real*8 NN !Longitude of ascending node + real*8 i !Inclination to the ecliptic + real*8 w !Argument of perigee + real*8 a !Semi-major axis + real*8 e !Eccentricity + real*8 MM !Mean anomaly + + real*8 v !True anomaly + real*8 EE !Eccentric anomaly + real*8 ecl !Obliquity of the ecliptic + + real*8 d !Ephemeris time argument in days + real*8 r !Distance to sun, AU + real*8 xv,yv !x and y coords in ecliptic + real*8 lonecl,latecl !Ecliptic long and lat of moon + real*8 xg,yg,zg !Ecliptic rectangular coords + real*8 Ms !Mean anomaly of sun + real*8 ws !Argument of perihelion of sun + real*8 Ls !Mean longitude of sun (Ns=0) + real*8 Lm !Mean longitude of moon + real*8 DD !Mean elongation of moon + real*8 FF !Argument of latitude for moon + real*8 xe,ye,ze !Equatorial geocentric coords of moon + real*8 mpar !Parallax of moon (r_E / d) + real*8 lat,lon !Station coordinates on earth + real*8 gclat !Geocentric latitude + real*8 rho !Earth radius factor + real*8 GMST0,LST,HA + real*8 g + real*8 topRA,topDec !Topocentric coordinates of Moon + real*8 Az,El + real*8 dist + + real*8 rad,twopi,pi,pio2 + data rad/57.2957795131d0/,twopi/6.283185307d0/ + + d=367*y - 7*(y+(m+9)/12)/4 + 275*m/9 + Day - 730530 + UT/24.d0 + ecl = 23.4393d0 - 3.563d-7 * d + +C Orbital elements for Moon: + NN = 125.1228d0 - 0.0529538083d0 * d + i = 5.1454d0 + w = mod(318.0634d0 + 0.1643573223d0 * d + 360000.d0,360.d0) + a = 60.2666d0 + e = 0.054900d0 + MM = mod(115.3654d0 + 13.0649929509d0 * d + 360000.d0,360.d0) + + EE = MM + e*rad*sin(MM/rad) * (1.d0 + e*cos(MM/rad)) + EE = EE - (EE - e*rad*sin(EE/rad)-MM) / (1.d0 - e*cos(EE/rad)) + EE = EE - (EE - e*rad*sin(EE/rad)-MM) / (1.d0 - e*cos(EE/rad)) + + xv = a * (cos(EE/rad) - e) + yv = a * (sqrt(1.d0-e*e) * sin(EE/rad)) + + v = mod(rad*atan2(yv,xv)+720.d0,360.d0) + r = sqrt(xv*xv + yv*yv) + +C Get geocentric position in ecliptic rectangular coordinates: + + xg = r * (cos(NN/rad)*cos((v+w)/rad) - + + sin(NN/rad)*sin((v+w)/rad)*cos(i/rad)) + yg = r * (sin(NN/rad)*cos((v+w)/rad) + + + cos(NN/rad)*sin((v+w)/rad)*cos(i/rad)) + zg = r * (sin((v+w)/rad)*sin(i/rad)) + +C Ecliptic longitude and latitude of moon: + lonecl = mod(rad*atan2(yg/rad,xg/rad)+720.d0,360.d0) + latecl = rad*atan2(zg/rad,sqrt(xg*xg + yg*yg)/rad) + +C Now include orbital perturbations: + Ms = mod(356.0470d0 + 0.9856002585d0 * d + 3600000.d0,360.d0) + ws = 282.9404d0 + 4.70935d-5*d + Ls = mod(Ms + ws + 720.d0,360.d0) + Lm = mod(MM + w + NN+720.d0,360.d0) + DD = mod(Lm - Ls + 360.d0,360.d0) + FF = mod(Lm - NN + 360.d0,360.d0) + + lonecl = lonecl + + -1.274d0 * sin((MM-2.d0*DD)/rad) + + +0.658d0 * sin(2.d0*DD/rad) + + -0.186d0 * sin(Ms/rad) + + -0.059d0 * sin((2.d0*MM-2.d0*DD)/rad) + + -0.057d0 * sin((MM-2.d0*DD+Ms)/rad) + + +0.053d0 * sin((MM+2.d0*DD)/rad) + + +0.046d0 * sin((2.d0*DD-Ms)/rad) + + +0.041d0 * sin((MM-Ms)/rad) + + -0.035d0 * sin(DD/rad) + + -0.031d0 * sin((MM+Ms)/rad) + + -0.015d0 * sin((2.d0*FF-2.d0*DD)/rad) + + +0.011d0 * sin((MM-4.d0*DD)/rad) + + latecl = latecl + + -0.173d0 * sin((FF-2.d0*DD)/rad) + + -0.055d0 * sin((MM-FF-2.d0*DD)/rad) + + -0.046d0 * sin((MM+FF-2.d0*DD)/rad) + + +0.033d0 * sin((FF+2.d0*DD)/rad) + + +0.017d0 * sin((2.d0*MM+FF)/rad) + + r = 60.36298d0 + + - 3.27746d0*cos(MM/rad) + + - 0.57994d0*cos((MM-2.d0*DD)/rad) + + - 0.46357d0*cos(2.d0*DD/rad) + + - 0.08904d0*cos(2.d0*MM/rad) + + + 0.03865d0*cos((2.d0*MM-2.d0*DD)/rad) + + - 0.03237d0*cos((2.d0*DD-Ms)/rad) + + - 0.02688d0*cos((MM+2.d0*DD)/rad) + + - 0.02358d0*cos((MM-2.d0*DD+Ms)/rad) + + - 0.02030d0*cos((MM-Ms)/rad) + + + 0.01719d0*cos(DD/rad) + + + 0.01671d0*cos((MM+Ms)/rad) + + dist=r*6378.140d0 + +C Geocentric coordinates: +C Rectangular ecliptic coordinates of the moon: + + xg = r * cos(lonecl/rad)*cos(latecl/rad) + yg = r * sin(lonecl/rad)*cos(latecl/rad) + zg = r * sin(latecl/rad) + +C Rectangular equatorial coordinates of the moon: + xe = xg + ye = yg*cos(ecl/rad) - zg*sin(ecl/rad) + ze = yg*sin(ecl/rad) + zg*cos(ecl/rad) + +C Right Ascension, Declination: + RA = mod(rad*atan2(ye,xe)+360.d0,360.d0) + Dec = rad*atan2(ze,sqrt(xe*xe + ye*ye)) + +C Now convert to topocentric system: + mpar=rad*asin(1.d0/r) +C alt_topoc = alt_geoc - mpar*cos(alt_geoc) + gclat = lat - 0.1924d0*sin(2.d0*lat/rad) + rho = 0.99883d0 + 0.00167d0*cos(2.d0*lat/rad) + GMST0 = (Ls + 180.d0)/15.d0 + LST = mod(GMST0+UT+lon/15.d0+48.d0,24.d0) !LST in hours + HA = 15.d0*LST - RA !HA in degrees + g = rad*atan(tan(gclat/rad)/cos(HA/rad)) + topRA = RA - mpar*rho*cos(gclat/rad)*sin(HA/rad)/cos(Dec/rad) + topDec = Dec - mpar*rho*sin(gclat/rad)*sin((g-Dec)/rad)/sin(g/rad) + + HA = 15.d0*LST - topRA !HA in degrees + if(HA.gt.180.d0) HA=HA-360.d0 + if(HA.lt.-180.d0) HA=HA+360.d0 + + pi=0.5d0*twopi + pio2=0.5d0*pi + call dcoord(pi,pio2-lat/rad,0.d0,lat/rad,ha*twopi/360, + + topDec/rad,az,el) + Az=az*rad + El=El*rad + + return + end diff --git a/libm65/moondop.f b/libm65/moondop.f index 787606e8e..ebac631c4 100644 --- a/libm65/moondop.f +++ b/libm65/moondop.f @@ -1,73 +1,73 @@ - subroutine MoonDop(nyear,month,nday,uth4,lon4,lat4,RAMoon4, - + DecMoon4,LST4,HA4,AzMoon4,ElMoon4,vr4,dist4) - - implicit real*8 (a-h,o-z) - real*4 uth4 !UT in hours - real*4 lon4 !West longitude, degrees - real*4 lat4 !Latitude, degrees - real*4 RAMoon4 !Topocentric RA of moon, hours - real*4 DecMoon4 !Topocentric Dec of Moon, degrees - real*4 LST4 !Locat sidereal time, hours - real*4 HA4 !Local Hour angle, degrees - real*4 AzMoon4 !Topocentric Azimuth of moon, degrees - real*4 ElMoon4 !Topocentric Elevation of moon, degrees - real*4 vr4 !Radial velocity of moon wrt obs, km/s - real*4 dist4 !Echo time, seconds - - real*8 LST - real*8 RME(6) !Vector from Earth center to Moon - real*8 RAE(6) !Vector from Earth center to Obs - real*8 RMA(6) !Vector from Obs to Moon - real*8 pvsun(6) - real*8 rme0(6) - logical km,bary - - data rad/57.2957795130823d0/,twopi/6.28310530717959d0/ - - km=.true. - dlat=lat4/rad - dlong1=lon4/rad - elev1=200.d0 - call geocentric(dlat,elev1,dlat1,erad1) - - dt=100.d0 !For numerical derivative, in seconds - UT=uth4 - -C NB: geodetic latitude used here, but geocentric latitude used when -C determining Earth-rotation contribution to Doppler. - - call moon2(nyear,month,nDay,UT-dt/3600.d0,dlong1*rad,dlat*rad, - + RA,Dec,topRA,topDec,LST,HA,Az0,El0,dist) - call toxyz(RA/rad,Dec/rad,dist,rme0) !Convert to rectangular coords - - call moon2(nyear,month,nDay,UT,dlong1*rad,dlat*rad, - + RA,Dec,topRA,topDec,LST,HA,Az,El,dist) - call toxyz(RA/rad,Dec/rad,dist,rme) !Convert to rectangular coords - - phi=LST*twopi/24.d0 - call toxyz(phi,dlat1,erad1,rae) !Gencentric numbers used here! - radps=twopi/(86400.d0/1.002737909d0) - rae(4)=-rae(2)*radps !Vel of Obs wrt Earth center - rae(5)=rae(1)*radps - rae(6)=0.d0 - - do i=1,3 - rme(i+3)=(rme(i)-rme0(i))/dt - rma(i)=rme(i)-rae(i) - rma(i+3)=rme(i+3)-rae(i+3) - enddo - - call fromxyz(rma,alpha1,delta1,dtopo0) !Get topocentric coords - vr=dot(rma(4),rma)/dtopo0 - - RAMoon4=topRA - DecMoon4=topDec - LST4=LST - HA4=HA - AzMoon4=Az - ElMoon4=El - vr4=vr - dist4=dist - - return - end + subroutine MoonDop(nyear,month,nday,uth4,lon4,lat4,RAMoon4, + + DecMoon4,LST4,HA4,AzMoon4,ElMoon4,vr4,dist4) + + implicit real*8 (a-h,o-z) + real*4 uth4 !UT in hours + real*4 lon4 !West longitude, degrees + real*4 lat4 !Latitude, degrees + real*4 RAMoon4 !Topocentric RA of moon, hours + real*4 DecMoon4 !Topocentric Dec of Moon, degrees + real*4 LST4 !Locat sidereal time, hours + real*4 HA4 !Local Hour angle, degrees + real*4 AzMoon4 !Topocentric Azimuth of moon, degrees + real*4 ElMoon4 !Topocentric Elevation of moon, degrees + real*4 vr4 !Radial velocity of moon wrt obs, km/s + real*4 dist4 !Echo time, seconds + + real*8 LST + real*8 RME(6) !Vector from Earth center to Moon + real*8 RAE(6) !Vector from Earth center to Obs + real*8 RMA(6) !Vector from Obs to Moon + real*8 pvsun(6) + real*8 rme0(6) + logical km,bary + + data rad/57.2957795130823d0/,twopi/6.28310530717959d0/ + + km=.true. + dlat=lat4/rad + dlong1=lon4/rad + elev1=200.d0 + call geocentric(dlat,elev1,dlat1,erad1) + + dt=100.d0 !For numerical derivative, in seconds + UT=uth4 + +C NB: geodetic latitude used here, but geocentric latitude used when +C determining Earth-rotation contribution to Doppler. + + call moon2(nyear,month,nDay,UT-dt/3600.d0,dlong1*rad,dlat*rad, + + RA,Dec,topRA,topDec,LST,HA,Az0,El0,dist) + call toxyz(RA/rad,Dec/rad,dist,rme0) !Convert to rectangular coords + + call moon2(nyear,month,nDay,UT,dlong1*rad,dlat*rad, + + RA,Dec,topRA,topDec,LST,HA,Az,El,dist) + call toxyz(RA/rad,Dec/rad,dist,rme) !Convert to rectangular coords + + phi=LST*twopi/24.d0 + call toxyz(phi,dlat1,erad1,rae) !Gencentric numbers used here! + radps=twopi/(86400.d0/1.002737909d0) + rae(4)=-rae(2)*radps !Vel of Obs wrt Earth center + rae(5)=rae(1)*radps + rae(6)=0.d0 + + do i=1,3 + rme(i+3)=(rme(i)-rme0(i))/dt + rma(i)=rme(i)-rae(i) + rma(i+3)=rme(i+3)-rae(i+3) + enddo + + call fromxyz(rma,alpha1,delta1,dtopo0) !Get topocentric coords + vr=dot(rma(4),rma)/dtopo0 + + RAMoon4=topRA + DecMoon4=topDec + LST4=LST + HA4=HA + AzMoon4=Az + ElMoon4=El + vr4=vr + dist4=dist + + return + end diff --git a/libm65/nchar.f b/libm65/nchar.f index 0730e905b..1da9a9813 100644 --- a/libm65/nchar.f +++ b/libm65/nchar.f @@ -1,23 +1,23 @@ - function nchar(c) - -C Convert ascii number, letter, or space to 0-36 for callsign packing. - - character c*1 - - n=0 !Silence compiler warning - if(c.ge.'0' .and. c.le.'9') then - n=ichar(c)-ichar('0') - else if(c.ge.'A' .and. c.le.'Z') then - n=ichar(c)-ichar('A') + 10 - else if(c.ge.'a' .and. c.le.'z') then - n=ichar(c)-ichar('a') + 10 - else if(c.ge.' ') then - n=36 - else - Print*,'Invalid character in callsign ',c,' ',ichar(c) - stop - endif - nchar=n - - return - end + function nchar(c) + +C Convert ascii number, letter, or space to 0-36 for callsign packing. + + character c*1 + + n=0 !Silence compiler warning + if(c.ge.'0' .and. c.le.'9') then + n=ichar(c)-ichar('0') + else if(c.ge.'A' .and. c.le.'Z') then + n=ichar(c)-ichar('A') + 10 + else if(c.ge.'a' .and. c.le.'z') then + n=ichar(c)-ichar('a') + 10 + else if(c.ge.' ') then + n=36 + else + Print*,'Invalid character in callsign ',c,' ',ichar(c) + stop + endif + nchar=n + + return + end diff --git a/libm65/packcall.f b/libm65/packcall.f index c0aa1761c..9e91a0be8 100644 --- a/libm65/packcall.f +++ b/libm65/packcall.f @@ -1,79 +1,79 @@ - subroutine packcall(callsign,ncall,text) - -C Pack a valid callsign into a 28-bit integer. - - parameter (NBASE=37*36*10*27*27*27) - character callsign*6,c*1,tmp*6 - logical text - - text=.false. - -C Work-around for Swaziland prefix: - if(callsign(1:4).eq.'3DA0') callsign='3D0'//callsign(5:6) - - if(callsign(1:3).eq.'CQ ') then - ncall=NBASE + 1 - if(callsign(4:4).ge.'0' .and. callsign(4:4).le.'9' .and. - + callsign(5:5).ge.'0' .and. callsign(5:5).le.'9' .and. - + callsign(6:6).ge.'0' .and. callsign(6:6).le.'9') then - read(callsign(4:6),*) nfreq - ncall=NBASE + 3 + nfreq - endif - return - else if(callsign(1:4).eq.'QRZ ') then - ncall=NBASE + 2 - return - else if(callsign(1:3).eq.'DE ') then - ncall=267796945 - return - endif - - tmp=' ' - if(callsign(3:3).ge.'0' .and. callsign(3:3).le.'9') then - tmp=callsign - else if(callsign(2:2).ge.'0' .and. callsign(2:2).le.'9') then - if(callsign(6:6).ne.' ') then - text=.true. - return - endif - tmp=' '//callsign(:5) - else - text=.true. - return - endif - - do i=1,6 - c=tmp(i:i) - if(c.ge.'a' .and. c.le.'z') - + tmp(i:i)=char(ichar(c)-ichar('a')+ichar('A')) - enddo - - n1=0 - if((tmp(1:1).ge.'A'.and.tmp(1:1).le.'Z').or.tmp(1:1).eq.' ') n1=1 - if(tmp(1:1).ge.'0' .and. tmp(1:1).le.'9') n1=1 - n2=0 - if(tmp(2:2).ge.'A' .and. tmp(2:2).le.'Z') n2=1 - if(tmp(2:2).ge.'0' .and. tmp(2:2).le.'9') n2=1 - n3=0 - if(tmp(3:3).ge.'0' .and. tmp(3:3).le.'9') n3=1 - n4=0 - if((tmp(4:4).ge.'A'.and.tmp(4:4).le.'Z').or.tmp(4:4).eq.' ') n4=1 - n5=0 - if((tmp(5:5).ge.'A'.and.tmp(5:5).le.'Z').or.tmp(5:5).eq.' ') n5=1 - n6=0 - if((tmp(6:6).ge.'A'.and.tmp(6:6).le.'Z').or.tmp(6:6).eq.' ') n6=1 - - if(n1+n2+n3+n4+n5+n6 .ne. 6) then - text=.true. - return - endif - - ncall=nchar(tmp(1:1)) - ncall=36*ncall+nchar(tmp(2:2)) - ncall=10*ncall+nchar(tmp(3:3)) - ncall=27*ncall+nchar(tmp(4:4))-10 - ncall=27*ncall+nchar(tmp(5:5))-10 - ncall=27*ncall+nchar(tmp(6:6))-10 - - return - end + subroutine packcall(callsign,ncall,text) + +C Pack a valid callsign into a 28-bit integer. + + parameter (NBASE=37*36*10*27*27*27) + character callsign*6,c*1,tmp*6 + logical text + + text=.false. + +C Work-around for Swaziland prefix: + if(callsign(1:4).eq.'3DA0') callsign='3D0'//callsign(5:6) + + if(callsign(1:3).eq.'CQ ') then + ncall=NBASE + 1 + if(callsign(4:4).ge.'0' .and. callsign(4:4).le.'9' .and. + + callsign(5:5).ge.'0' .and. callsign(5:5).le.'9' .and. + + callsign(6:6).ge.'0' .and. callsign(6:6).le.'9') then + read(callsign(4:6),*) nfreq + ncall=NBASE + 3 + nfreq + endif + return + else if(callsign(1:4).eq.'QRZ ') then + ncall=NBASE + 2 + return + else if(callsign(1:3).eq.'DE ') then + ncall=267796945 + return + endif + + tmp=' ' + if(callsign(3:3).ge.'0' .and. callsign(3:3).le.'9') then + tmp=callsign + else if(callsign(2:2).ge.'0' .and. callsign(2:2).le.'9') then + if(callsign(6:6).ne.' ') then + text=.true. + return + endif + tmp=' '//callsign(:5) + else + text=.true. + return + endif + + do i=1,6 + c=tmp(i:i) + if(c.ge.'a' .and. c.le.'z') + + tmp(i:i)=char(ichar(c)-ichar('a')+ichar('A')) + enddo + + n1=0 + if((tmp(1:1).ge.'A'.and.tmp(1:1).le.'Z').or.tmp(1:1).eq.' ') n1=1 + if(tmp(1:1).ge.'0' .and. tmp(1:1).le.'9') n1=1 + n2=0 + if(tmp(2:2).ge.'A' .and. tmp(2:2).le.'Z') n2=1 + if(tmp(2:2).ge.'0' .and. tmp(2:2).le.'9') n2=1 + n3=0 + if(tmp(3:3).ge.'0' .and. tmp(3:3).le.'9') n3=1 + n4=0 + if((tmp(4:4).ge.'A'.and.tmp(4:4).le.'Z').or.tmp(4:4).eq.' ') n4=1 + n5=0 + if((tmp(5:5).ge.'A'.and.tmp(5:5).le.'Z').or.tmp(5:5).eq.' ') n5=1 + n6=0 + if((tmp(6:6).ge.'A'.and.tmp(6:6).le.'Z').or.tmp(6:6).eq.' ') n6=1 + + if(n1+n2+n3+n4+n5+n6 .ne. 6) then + text=.true. + return + endif + + ncall=nchar(tmp(1:1)) + ncall=36*ncall+nchar(tmp(2:2)) + ncall=10*ncall+nchar(tmp(3:3)) + ncall=27*ncall+nchar(tmp(4:4))-10 + ncall=27*ncall+nchar(tmp(5:5))-10 + ncall=27*ncall+nchar(tmp(6:6))-10 + + return + end diff --git a/libm65/packdxcc.f b/libm65/packdxcc.f index add5e7be9..ac370ef3f 100644 --- a/libm65/packdxcc.f +++ b/libm65/packdxcc.f @@ -1,64 +1,64 @@ - subroutine packdxcc(c,ng,ldxcc) - - character*3 c - logical ldxcc - - parameter (NZ=303) - character*5 pfx(NZ) - data pfx/ - + '1A ','1S ','3A ','3B6 ','3B8 ','3B9 ','3C ','3C0 ', - + '3D2 ', '3DA ','3V ','3W ','3X ','3Y ', - + '4J ','4L ','4S ','4U1 ', '4W ', - + '4X ','5A ','5B ','5H ','5N ','5R ','5T ','5U ', - + '5V ','5W ','5X ','5Z ','6W ','6Y ','7O ','7P ', - + '7Q ','7X ','8P ','8Q ','8R ','9A ','9G ','9H ', - + '9J ','9K ','9L ','9M2 ','9M6 ','9N ','9Q ','9U ', - + '9V ','9X ','9Y ','A2 ','A3 ','A4 ','A5 ','A6 ', - + 'A7 ','A9 ','AP ','BS7 ','BV ','BV9 ','BY ','C2 ', - + 'C3 ','C5 ','C6 ','C9 ','CE ','CE0 ', - + 'CE9 ','CM ','CN ','CP ','CT ','CT3 ','CU ','CX ', - + 'CY0 ','CY9 ','D2 ','D4 ','D6 ','DL ','DU ','E3 ', - + 'E4 ','EA ','EA6 ','EA8 ','EA9 ','EI ','EK ','EL ', - + 'EP ','ER ','ES ','ET ','EU ','EX ','EY ','EZ ', - + 'F ','FG ','FH ','FJ ','FK ', 'FM ','FO ', - + 'FP ','FR ', - + 'FT5 ', 'FW ','FY ','M ','MD ','MI ', - + 'MJ ','MM ', 'MU ','MW ','H4 ','H40 ','HA ', - + 'HB ','HB0 ','HC ','HC8 ','HH ','HI ','HK ','HK0 ', - + 'HL ','HM ','HP ','HR ','HS ','HV ','HZ ', - + 'I ','IG9 ','IS ','IT9 ','J2 ','J3 ','J5 ','J6 ', - + 'J7 ','J8 ','JA ','JD ', 'JT ','JW ', - + 'JX ','JY ','K ','KG4 ','KH0 ','KH1 ','KH2 ','KH3 ', - + 'KH4 ','KH5 ', 'KH6 ','KH7 ','KH8 ','KH9 ','KL ', - + 'KP1 ','KP2 ','KP4 ','KP5 ','LA ','LU ','LX ','LY ', - + 'LZ ','OA ','OD ','OE ','OH ','OH0 ','OJ0 ','OK ', - + 'OM ','ON ','OX ','OY ','OZ ','P2 ','P4 ','PA ', - + 'PJ2 ','PJ7 ','PY ','PY0 ', 'PZ ','R1F ', - + 'R1M ','S0 ','S2 ','S5 ','S7 ','S9 ','SM ','SP ', - + 'ST ','SU ','SV ', 'SV5 ','SV9 ','T2 ','T30 ', - + 'T31 ','T32 ','T33 ','T5 ','T7 ','T8 ','T9 ','TA ', - + 'TA1 ','TF ','TG ','TI ','TI9 ','TJ ','TK ','TL ', - + 'TN ','TR ','TT ','TU ','TY ','TZ ','UA ','UA2 ', - + 'UA9 ','UK ','UN ','UR ','V2 ','V3 ','V4 ','V5 ', - + 'V6 ','V7 ','V8 ','VE ','VK ','VK0 ', 'VK9 ', - + 'VP2 ', - + 'VP5 ','VP6 ', 'VP8 ', - + 'VP9 ','VQ9 ','VR ','VU ','VU4 ','VU7 ','XE ','XF4 ', - + 'XT ','XU ','XW ','XX9 ','XZ ','YA ','YB ','YI ', - + 'YJ ','YK ','YL ','YN ','YO ','YS ','YU ','YV ', - + 'YV0 ','Z2 ','Z3 ','ZA ','ZB ','ZC4 ','ZD7 ','ZD8 ', - + 'ZD9 ','ZF ','ZK1 ', 'ZK2 ','ZK3 ','ZL ','ZL7 ', - + 'ZL8 ','ZL9 ','ZP ','ZS ','ZS8 '/ - - ldxcc=.false. - ng=0 - do i=1,NZ - if(pfx(i)(1:3).eq.c) go to 10 - enddo - go to 20 - - 10 ng=180*180+61+i - ldxcc=.true. - - 20 return - end + subroutine packdxcc(c,ng,ldxcc) + + character*3 c + logical ldxcc + + parameter (NZ=303) + character*5 pfx(NZ) + data pfx/ + + '1A ','1S ','3A ','3B6 ','3B8 ','3B9 ','3C ','3C0 ', + + '3D2 ', '3DA ','3V ','3W ','3X ','3Y ', + + '4J ','4L ','4S ','4U1 ', '4W ', + + '4X ','5A ','5B ','5H ','5N ','5R ','5T ','5U ', + + '5V ','5W ','5X ','5Z ','6W ','6Y ','7O ','7P ', + + '7Q ','7X ','8P ','8Q ','8R ','9A ','9G ','9H ', + + '9J ','9K ','9L ','9M2 ','9M6 ','9N ','9Q ','9U ', + + '9V ','9X ','9Y ','A2 ','A3 ','A4 ','A5 ','A6 ', + + 'A7 ','A9 ','AP ','BS7 ','BV ','BV9 ','BY ','C2 ', + + 'C3 ','C5 ','C6 ','C9 ','CE ','CE0 ', + + 'CE9 ','CM ','CN ','CP ','CT ','CT3 ','CU ','CX ', + + 'CY0 ','CY9 ','D2 ','D4 ','D6 ','DL ','DU ','E3 ', + + 'E4 ','EA ','EA6 ','EA8 ','EA9 ','EI ','EK ','EL ', + + 'EP ','ER ','ES ','ET ','EU ','EX ','EY ','EZ ', + + 'F ','FG ','FH ','FJ ','FK ', 'FM ','FO ', + + 'FP ','FR ', + + 'FT5 ', 'FW ','FY ','M ','MD ','MI ', + + 'MJ ','MM ', 'MU ','MW ','H4 ','H40 ','HA ', + + 'HB ','HB0 ','HC ','HC8 ','HH ','HI ','HK ','HK0 ', + + 'HL ','HM ','HP ','HR ','HS ','HV ','HZ ', + + 'I ','IG9 ','IS ','IT9 ','J2 ','J3 ','J5 ','J6 ', + + 'J7 ','J8 ','JA ','JD ', 'JT ','JW ', + + 'JX ','JY ','K ','KG4 ','KH0 ','KH1 ','KH2 ','KH3 ', + + 'KH4 ','KH5 ', 'KH6 ','KH7 ','KH8 ','KH9 ','KL ', + + 'KP1 ','KP2 ','KP4 ','KP5 ','LA ','LU ','LX ','LY ', + + 'LZ ','OA ','OD ','OE ','OH ','OH0 ','OJ0 ','OK ', + + 'OM ','ON ','OX ','OY ','OZ ','P2 ','P4 ','PA ', + + 'PJ2 ','PJ7 ','PY ','PY0 ', 'PZ ','R1F ', + + 'R1M ','S0 ','S2 ','S5 ','S7 ','S9 ','SM ','SP ', + + 'ST ','SU ','SV ', 'SV5 ','SV9 ','T2 ','T30 ', + + 'T31 ','T32 ','T33 ','T5 ','T7 ','T8 ','T9 ','TA ', + + 'TA1 ','TF ','TG ','TI ','TI9 ','TJ ','TK ','TL ', + + 'TN ','TR ','TT ','TU ','TY ','TZ ','UA ','UA2 ', + + 'UA9 ','UK ','UN ','UR ','V2 ','V3 ','V4 ','V5 ', + + 'V6 ','V7 ','V8 ','VE ','VK ','VK0 ', 'VK9 ', + + 'VP2 ', + + 'VP5 ','VP6 ', 'VP8 ', + + 'VP9 ','VQ9 ','VR ','VU ','VU4 ','VU7 ','XE ','XF4 ', + + 'XT ','XU ','XW ','XX9 ','XZ ','YA ','YB ','YI ', + + 'YJ ','YK ','YL ','YN ','YO ','YS ','YU ','YV ', + + 'YV0 ','Z2 ','Z3 ','ZA ','ZB ','ZC4 ','ZD7 ','ZD8 ', + + 'ZD9 ','ZF ','ZK1 ', 'ZK2 ','ZK3 ','ZL ','ZL7 ', + + 'ZL8 ','ZL9 ','ZP ','ZS ','ZS8 '/ + + ldxcc=.false. + ng=0 + do i=1,NZ + if(pfx(i)(1:3).eq.c) go to 10 + enddo + go to 20 + + 10 ng=180*180+61+i + ldxcc=.true. + + 20 return + end diff --git a/libm65/packgrid.f b/libm65/packgrid.f index 143e167f3..8f1d00330 100644 --- a/libm65/packgrid.f +++ b/libm65/packgrid.f @@ -1,47 +1,47 @@ - subroutine packgrid(grid,ng,text) - - parameter (NGBASE=180*180) - character*4 grid - logical text - - text=.false. - if(grid.eq.' ') go to 90 !Blank grid is OK - -C Test for numerical signal report, etc. - if(grid(1:1).eq.'-') then - read(grid(2:3),*,err=1,end=1) n - 1 ng=NGBASE+1+n - go to 100 - else if(grid(1:2).eq.'R-') then - read(grid(3:4),*,err=2,end=2) n - 2 if(n.eq.0) go to 90 - ng=NGBASE+31+n - go to 100 - else if(grid(1:2).eq.'RO') then - ng=NGBASE+62 - go to 100 - else if(grid(1:3).eq.'RRR') then - ng=NGBASE+63 - go to 100 - else if(grid(1:2).eq.'73') then - ng=NGBASE+64 - go to 100 - endif - - if(grid(1:1).lt.'A' .or. grid(1:1).gt.'R') text=.true. - if(grid(2:2).lt.'A' .or. grid(2:2).gt.'R') text=.true. - if(grid(3:3).lt.'0' .or. grid(3:3).gt.'9') text=.true. - if(grid(4:4).lt.'0' .or. grid(4:4).gt.'9') text=.true. - if(text) go to 100 - - call grid2deg(grid//'mm',dlong,dlat) - long=dlong - lat=dlat+ 90.0 - ng=((long+180)/2)*180 + lat - go to 100 - - 90 ng=NGBASE + 1 - - 100 return - end - + subroutine packgrid(grid,ng,text) + + parameter (NGBASE=180*180) + character*4 grid + logical text + + text=.false. + if(grid.eq.' ') go to 90 !Blank grid is OK + +C Test for numerical signal report, etc. + if(grid(1:1).eq.'-') then + read(grid(2:3),*,err=1,end=1) n + 1 ng=NGBASE+1+n + go to 100 + else if(grid(1:2).eq.'R-') then + read(grid(3:4),*,err=2,end=2) n + 2 if(n.eq.0) go to 90 + ng=NGBASE+31+n + go to 100 + else if(grid(1:2).eq.'RO') then + ng=NGBASE+62 + go to 100 + else if(grid(1:3).eq.'RRR') then + ng=NGBASE+63 + go to 100 + else if(grid(1:2).eq.'73') then + ng=NGBASE+64 + go to 100 + endif + + if(grid(1:1).lt.'A' .or. grid(1:1).gt.'R') text=.true. + if(grid(2:2).lt.'A' .or. grid(2:2).gt.'R') text=.true. + if(grid(3:3).lt.'0' .or. grid(3:3).gt.'9') text=.true. + if(grid(4:4).lt.'0' .or. grid(4:4).gt.'9') text=.true. + if(text) go to 100 + + call grid2deg(grid//'mm',dlong,dlat) + long=dlong + lat=dlat+ 90.0 + ng=((long+180)/2)*180 + lat + go to 100 + + 90 ng=NGBASE + 1 + + 100 return + end + diff --git a/libm65/packmsg.f b/libm65/packmsg.f index d92652fba..76eb5f845 100644 --- a/libm65/packmsg.f +++ b/libm65/packmsg.f @@ -1,103 +1,103 @@ - subroutine packmsg(msg,dat) - - parameter (NBASE=37*36*10*27*27*27) - parameter (NBASE2=262178562) - character*22 msg - integer dat(12) - character*12 c1,c2,c2z - character*4 c3 - character*6 grid6 -c character*3 dxcc !Where is DXCC implemented? - logical text1,text2,text3 - -C Convert all letters to upper case - do i=1,22 - if(msg(i:i).ge.'a' .and. msg(i:i).le.'z') - + msg(i:i)= char(ichar(msg(i:i))+ichar('A')-ichar('a')) - enddo - -C See if it's a CQ message - if(msg(1:3).eq.'CQ ') then - i=3 -C ... and if so, does it have a reply frequency? - if(msg(4:4).ge.'0' .and. msg(4:4).le.'9' .and. - + msg(5:5).ge.'0' .and. msg(5:5).le.'9' .and. - + msg(6:6).ge.'0' .and. msg(6:6).le.'9') i=7 - go to 1 - endif - - do i=1,22 - if(msg(i:i).eq.' ') go to 1 !Get 1st blank - enddo - go to 10 !Consider msg as plain text - - 1 ia=i - c1=msg(1:ia-1) - do i=ia+1,22 - if(msg(i:i).eq.' ') go to 2 !Get 2nd blank - enddo - go to 10 !Consider msg as plain text - - 2 ib=i - c2=msg(ia+1:ib-1) - - do i=ib+1,22 - if(msg(i:i).eq.' ') go to 3 !Get 3rd blank - enddo - go to 10 !Consider msg as plain text - - 3 ic=i - c3=' ' - if(ic.ge.ib+1) c3=msg(ib+1:ic) - if(c3.eq.'OOO ') c3=' ' !Strip out the OOO flag - call getpfx1(c1,k1,junk) - call packcall(c1,nc1,text1) - c2z=c2 - call getpfx1(c2,k2,nv2) - call packcall(c2,nc2,text2) - if(nv2.eq.0) then - if(k1.lt.0 .or. k2.lt.0 .or. k1*k2.ne.0) go to 10 - if(k2.gt.0) k2=k2+450 - k=max(k1,k2) - if(k.gt.0) then - call k2grid(k,grid6) - c3=grid6(:4) - endif - endif - call packgrid(c3,ng,text3) - if(nv2.eq.0 .and. (.not.text1) .and. (.not.text2) .and. - + (.not.text3)) go to 20 - if(nv2.gt.0) then - if(nv2.eq.1) then - if(c1(1:3).eq.'CQ ') nc1=262178563 + k2 - if(c1(1:4).eq.'QRZ ') nc1=264002072 + k2 - if(c1(1:3).eq.'DE ') nc1=265825581 + k2 - endif - if(nv2.eq.2) then - if(c1(1:3).eq.'CQ ') nc1=267649090 + k2 - if(c1(1:4).eq.'QRZ ') nc1=267698375 + k2 - if(c1(1:3).eq.'DE ') nc1=267747660 + k2 - endif - go to 20 - endif - -C The message will be treated as plain text. - 10 call packtext(msg,nc1,nc2,ng) - ng=ng+32768 - -C Encode data into 6-bit words - 20 dat(1)=iand(ishft(nc1,-22),63) !6 bits - dat(2)=iand(ishft(nc1,-16),63) !6 bits - dat(3)=iand(ishft(nc1,-10),63) !6 bits - dat(4)=iand(ishft(nc1, -4),63) !6 bits - dat(5)=4*iand(nc1,15)+iand(ishft(nc2,-26),3) !4+2 bits - dat(6)=iand(ishft(nc2,-20),63) !6 bits - dat(7)=iand(ishft(nc2,-14),63) !6 bits - dat(8)=iand(ishft(nc2, -8),63) !6 bits - dat(9)=iand(ishft(nc2, -2),63) !6 bits - dat(10)=16*iand(nc2,3)+iand(ishft(ng,-12),15) !2+4 bits - dat(11)=iand(ishft(ng,-6),63) - dat(12)=iand(ng,63) - - return - end + subroutine packmsg(msg,dat) + + parameter (NBASE=37*36*10*27*27*27) + parameter (NBASE2=262178562) + character*22 msg + integer dat(12) + character*12 c1,c2,c2z + character*4 c3 + character*6 grid6 +c character*3 dxcc !Where is DXCC implemented? + logical text1,text2,text3 + +C Convert all letters to upper case + do i=1,22 + if(msg(i:i).ge.'a' .and. msg(i:i).le.'z') + + msg(i:i)= char(ichar(msg(i:i))+ichar('A')-ichar('a')) + enddo + +C See if it's a CQ message + if(msg(1:3).eq.'CQ ') then + i=3 +C ... and if so, does it have a reply frequency? + if(msg(4:4).ge.'0' .and. msg(4:4).le.'9' .and. + + msg(5:5).ge.'0' .and. msg(5:5).le.'9' .and. + + msg(6:6).ge.'0' .and. msg(6:6).le.'9') i=7 + go to 1 + endif + + do i=1,22 + if(msg(i:i).eq.' ') go to 1 !Get 1st blank + enddo + go to 10 !Consider msg as plain text + + 1 ia=i + c1=msg(1:ia-1) + do i=ia+1,22 + if(msg(i:i).eq.' ') go to 2 !Get 2nd blank + enddo + go to 10 !Consider msg as plain text + + 2 ib=i + c2=msg(ia+1:ib-1) + + do i=ib+1,22 + if(msg(i:i).eq.' ') go to 3 !Get 3rd blank + enddo + go to 10 !Consider msg as plain text + + 3 ic=i + c3=' ' + if(ic.ge.ib+1) c3=msg(ib+1:ic) + if(c3.eq.'OOO ') c3=' ' !Strip out the OOO flag + call getpfx1(c1,k1,junk) + call packcall(c1,nc1,text1) + c2z=c2 + call getpfx1(c2,k2,nv2) + call packcall(c2,nc2,text2) + if(nv2.eq.0) then + if(k1.lt.0 .or. k2.lt.0 .or. k1*k2.ne.0) go to 10 + if(k2.gt.0) k2=k2+450 + k=max(k1,k2) + if(k.gt.0) then + call k2grid(k,grid6) + c3=grid6(:4) + endif + endif + call packgrid(c3,ng,text3) + if(nv2.eq.0 .and. (.not.text1) .and. (.not.text2) .and. + + (.not.text3)) go to 20 + if(nv2.gt.0) then + if(nv2.eq.1) then + if(c1(1:3).eq.'CQ ') nc1=262178563 + k2 + if(c1(1:4).eq.'QRZ ') nc1=264002072 + k2 + if(c1(1:3).eq.'DE ') nc1=265825581 + k2 + endif + if(nv2.eq.2) then + if(c1(1:3).eq.'CQ ') nc1=267649090 + k2 + if(c1(1:4).eq.'QRZ ') nc1=267698375 + k2 + if(c1(1:3).eq.'DE ') nc1=267747660 + k2 + endif + go to 20 + endif + +C The message will be treated as plain text. + 10 call packtext(msg,nc1,nc2,ng) + ng=ng+32768 + +C Encode data into 6-bit words + 20 dat(1)=iand(ishft(nc1,-22),63) !6 bits + dat(2)=iand(ishft(nc1,-16),63) !6 bits + dat(3)=iand(ishft(nc1,-10),63) !6 bits + dat(4)=iand(ishft(nc1, -4),63) !6 bits + dat(5)=4*iand(nc1,15)+iand(ishft(nc2,-26),3) !4+2 bits + dat(6)=iand(ishft(nc2,-20),63) !6 bits + dat(7)=iand(ishft(nc2,-14),63) !6 bits + dat(8)=iand(ishft(nc2, -8),63) !6 bits + dat(9)=iand(ishft(nc2, -2),63) !6 bits + dat(10)=16*iand(nc2,3)+iand(ishft(ng,-12),15) !2+4 bits + dat(11)=iand(ishft(ng,-6),63) + dat(12)=iand(ng,63) + + return + end diff --git a/libm65/packtext.f b/libm65/packtext.f index 52d299dd1..c06581a0a 100644 --- a/libm65/packtext.f +++ b/libm65/packtext.f @@ -1,47 +1,47 @@ - subroutine packtext(msg,nc1,nc2,nc3) - - parameter (MASK28=2**28 - 1) - character*13 msg - character*44 c - data c/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ +-./?'/ - - nc1=0 - nc2=0 - nc3=0 - - do i=1,5 !First 5 characters in nc1 - do j=1,44 !Get character code - if(msg(i:i).eq.c(j:j)) go to 10 - enddo - j=37 - 10 j=j-1 !Codes should start at zero - nc1=42*nc1 + j - enddo - - do i=6,10 !Characters 6-10 in nc2 - do j=1,44 !Get character code - if(msg(i:i).eq.c(j:j)) go to 20 - enddo - j=37 - 20 j=j-1 !Codes should start at zero - nc2=42*nc2 + j - enddo - - do i=11,13 !Characters 11-13 in nc3 - do j=1,44 !Get character code - if(msg(i:i).eq.c(j:j)) go to 30 - enddo - j=37 - 30 j=j-1 !Codes should start at zero - nc3=42*nc3 + j - enddo - -C We now have used 17 bits in nc3. Must move one each to nc1 and nc2. - nc1=nc1+nc1 - if(iand(nc3,32768).ne.0) nc1=nc1+1 - nc2=nc2+nc2 - if(iand(nc3,65536).ne.0) nc2=nc2+1 - nc3=iand(nc3,32767) - - return - end + subroutine packtext(msg,nc1,nc2,nc3) + + parameter (MASK28=2**28 - 1) + character*13 msg + character*44 c + data c/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ +-./?'/ + + nc1=0 + nc2=0 + nc3=0 + + do i=1,5 !First 5 characters in nc1 + do j=1,44 !Get character code + if(msg(i:i).eq.c(j:j)) go to 10 + enddo + j=37 + 10 j=j-1 !Codes should start at zero + nc1=42*nc1 + j + enddo + + do i=6,10 !Characters 6-10 in nc2 + do j=1,44 !Get character code + if(msg(i:i).eq.c(j:j)) go to 20 + enddo + j=37 + 20 j=j-1 !Codes should start at zero + nc2=42*nc2 + j + enddo + + do i=11,13 !Characters 11-13 in nc3 + do j=1,44 !Get character code + if(msg(i:i).eq.c(j:j)) go to 30 + enddo + j=37 + 30 j=j-1 !Codes should start at zero + nc3=42*nc3 + j + enddo + +C We now have used 17 bits in nc3. Must move one each to nc1 and nc2. + nc1=nc1+nc1 + if(iand(nc3,32768).ne.0) nc1=nc1+1 + nc2=nc2+nc2 + if(iand(nc3,65536).ne.0) nc2=nc2+1 + nc3=iand(nc3,32767) + + return + end diff --git a/libm65/pctile.f b/libm65/pctile.f index 096e222ed..8cfedc154 100644 --- a/libm65/pctile.f +++ b/libm65/pctile.f @@ -1,13 +1,13 @@ - subroutine pctile(x,tmp,nmax,npct,xpct) - real x(nmax),tmp(nmax) - - do i=1,nmax - tmp(i)=x(i) - enddo - call sort(nmax,tmp) - j=nint(nmax*0.01*npct) - if(j.lt.1) j=1 - xpct=tmp(j) - - return - end + subroutine pctile(x,tmp,nmax,npct,xpct) + real x(nmax),tmp(nmax) + + do i=1,nmax + tmp(i)=x(i) + enddo + call sort(nmax,tmp) + j=nint(nmax*0.01*npct) + if(j.lt.1) j=1 + xpct=tmp(j) + + return + end diff --git a/libm65/pfx.f b/libm65/pfx.f index 62d9ca7de..685b3420e 100644 --- a/libm65/pfx.f +++ b/libm65/pfx.f @@ -1,50 +1,50 @@ - parameter (NZ=339) !Total number of prefixes - parameter (NZ2=12) !Total number of suffixes - character*1 sfx(NZ2) - character*5 pfx(NZ) - - data sfx/'P','0','1','2','3','4','5','6','7','8','9','A'/ - data pfx/ - + '1A ','1S ','3A ','3B6 ','3B8 ','3B9 ','3C ','3C0 ', - + '3D2 ','3D2C ','3D2R ','3DA ','3V ','3W ','3X ','3Y ', - + '3YB ','3YP ','4J ','4L ','4S ','4U1I ','4U1U ','4W ', - + '4X ','5A ','5B ','5H ','5N ','5R ','5T ','5U ', - + '5V ','5W ','5X ','5Z ','6W ','6Y ','7O ','7P ', - + '7Q ','7X ','8P ','8Q ','8R ','9A ','9G ','9H ', - + '9J ','9K ','9L ','9M2 ','9M6 ','9N ','9Q ','9U ', - + '9V ','9X ','9Y ','A2 ','A3 ','A4 ','A5 ','A6 ', - + 'A7 ','A9 ','AP ','BS7 ','BV ','BV9 ','BY ','C2 ', - + 'C3 ','C5 ','C6 ','C9 ','CE ','CE0X ','CE0Y ','CE0Z ', - + 'CE9 ','CM ','CN ','CP ','CT ','CT3 ','CU ','CX ', - + 'CY0 ','CY9 ','D2 ','D4 ','D6 ','DL ','DU ','E3 ', - + 'E4 ','EA ','EA6 ','EA8 ','EA9 ','EI ','EK ','EL ', - + 'EP ','ER ','ES ','ET ','EU ','EX ','EY ','EZ ', - + 'F ','FG ','FH ','FJ ','FK ','FKC ','FM ','FO ', - + 'FOA ','FOC ','FOM ','FP ','FR ','FRG ','FRJ ','FRT ', - + 'FT5W ','FT5X ','FT5Z ','FW ','FY ','M ','MD ','MI ', - + 'MJ ','MM ', 'MU ','MW ','H4 ','H40 ','HA ', - + 'HB ','HB0 ','HC ','HC8 ','HH ','HI ','HK ','HK0A ', - + 'HK0M ','HL ','HM ','HP ','HR ','HS ','HV ','HZ ', - + 'I ','IS ','IS0 ', 'J2 ','J3 ','J5 ','J6 ', - + 'J7 ','J8 ','JA ','JDM ','JDO ','JT ','JW ', - + 'JX ','JY ','K ','KG4 ','KH0 ','KH1 ','KH2 ','KH3 ', - + 'KH4 ','KH5 ','KH5K ','KH6 ','KH7 ','KH8 ','KH9 ','KL ', - + 'KP1 ','KP2 ','KP4 ','KP5 ','LA ','LU ','LX ','LY ', - + 'LZ ','OA ','OD ','OE ','OH ','OH0 ','OJ0 ','OK ', - + 'OM ','ON ','OX ','OY ','OZ ','P2 ','P4 ','PA ', - + 'PJ2 ','PJ7 ','PY ','PY0F ','PT0S ','PY0T ','PZ ','R1F ', - + 'R1M ','S0 ','S2 ','S5 ','S7 ','S9 ','SM ','SP ', - + 'ST ','SU ','SV ','SVA ','SV5 ','SV9 ','T2 ','T30 ', - + 'T31 ','T32 ','T33 ','T5 ','T7 ','T8 ','T9 ','TA ', - + 'TF ','TG ','TI ','TI9 ','TJ ','TK ','TL ', - + 'TN ','TR ','TT ','TU ','TY ','TZ ','UA ','UA2 ', - + 'UA9 ','UK ','UN ','UR ','V2 ','V3 ','V4 ','V5 ', - + 'V6 ','V7 ','V8 ','VE ','VK ','VK0H ','VK0M ','VK9C ', - + 'VK9L ','VK9M ','VK9N ','VK9W ','VK9X ','VP2E ','VP2M ','VP2V ', - + 'VP5 ','VP6 ','VP6D ','VP8 ','VP8G ','VP8H ','VP8O ','VP8S ', - + 'VP9 ','VQ9 ','VR ','VU ','VU4 ','VU7 ','XE ','XF4 ', - + 'XT ','XU ','XW ','XX9 ','XZ ','YA ','YB ','YI ', - + 'YJ ','YK ','YL ','YN ','YO ','YS ','YU ','YV ', - + 'YV0 ','Z2 ','Z3 ','ZA ','ZB ','ZC4 ','ZD7 ','ZD8 ', - + 'ZD9 ','ZF ','ZK1N ','ZK1S ','ZK2 ','ZK3 ','ZL ','ZL7 ', - + 'ZL8 ','ZL9 ','ZP ','ZS ','ZS8 ','KC4 ','E5 '/ + parameter (NZ=339) !Total number of prefixes + parameter (NZ2=12) !Total number of suffixes + character*1 sfx(NZ2) + character*5 pfx(NZ) + + data sfx/'P','0','1','2','3','4','5','6','7','8','9','A'/ + data pfx/ + + '1A ','1S ','3A ','3B6 ','3B8 ','3B9 ','3C ','3C0 ', + + '3D2 ','3D2C ','3D2R ','3DA ','3V ','3W ','3X ','3Y ', + + '3YB ','3YP ','4J ','4L ','4S ','4U1I ','4U1U ','4W ', + + '4X ','5A ','5B ','5H ','5N ','5R ','5T ','5U ', + + '5V ','5W ','5X ','5Z ','6W ','6Y ','7O ','7P ', + + '7Q ','7X ','8P ','8Q ','8R ','9A ','9G ','9H ', + + '9J ','9K ','9L ','9M2 ','9M6 ','9N ','9Q ','9U ', + + '9V ','9X ','9Y ','A2 ','A3 ','A4 ','A5 ','A6 ', + + 'A7 ','A9 ','AP ','BS7 ','BV ','BV9 ','BY ','C2 ', + + 'C3 ','C5 ','C6 ','C9 ','CE ','CE0X ','CE0Y ','CE0Z ', + + 'CE9 ','CM ','CN ','CP ','CT ','CT3 ','CU ','CX ', + + 'CY0 ','CY9 ','D2 ','D4 ','D6 ','DL ','DU ','E3 ', + + 'E4 ','EA ','EA6 ','EA8 ','EA9 ','EI ','EK ','EL ', + + 'EP ','ER ','ES ','ET ','EU ','EX ','EY ','EZ ', + + 'F ','FG ','FH ','FJ ','FK ','FKC ','FM ','FO ', + + 'FOA ','FOC ','FOM ','FP ','FR ','FRG ','FRJ ','FRT ', + + 'FT5W ','FT5X ','FT5Z ','FW ','FY ','M ','MD ','MI ', + + 'MJ ','MM ', 'MU ','MW ','H4 ','H40 ','HA ', + + 'HB ','HB0 ','HC ','HC8 ','HH ','HI ','HK ','HK0A ', + + 'HK0M ','HL ','HM ','HP ','HR ','HS ','HV ','HZ ', + + 'I ','IS ','IS0 ', 'J2 ','J3 ','J5 ','J6 ', + + 'J7 ','J8 ','JA ','JDM ','JDO ','JT ','JW ', + + 'JX ','JY ','K ','KG4 ','KH0 ','KH1 ','KH2 ','KH3 ', + + 'KH4 ','KH5 ','KH5K ','KH6 ','KH7 ','KH8 ','KH9 ','KL ', + + 'KP1 ','KP2 ','KP4 ','KP5 ','LA ','LU ','LX ','LY ', + + 'LZ ','OA ','OD ','OE ','OH ','OH0 ','OJ0 ','OK ', + + 'OM ','ON ','OX ','OY ','OZ ','P2 ','P4 ','PA ', + + 'PJ2 ','PJ7 ','PY ','PY0F ','PT0S ','PY0T ','PZ ','R1F ', + + 'R1M ','S0 ','S2 ','S5 ','S7 ','S9 ','SM ','SP ', + + 'ST ','SU ','SV ','SVA ','SV5 ','SV9 ','T2 ','T30 ', + + 'T31 ','T32 ','T33 ','T5 ','T7 ','T8 ','T9 ','TA ', + + 'TF ','TG ','TI ','TI9 ','TJ ','TK ','TL ', + + 'TN ','TR ','TT ','TU ','TY ','TZ ','UA ','UA2 ', + + 'UA9 ','UK ','UN ','UR ','V2 ','V3 ','V4 ','V5 ', + + 'V6 ','V7 ','V8 ','VE ','VK ','VK0H ','VK0M ','VK9C ', + + 'VK9L ','VK9M ','VK9N ','VK9W ','VK9X ','VP2E ','VP2M ','VP2V ', + + 'VP5 ','VP6 ','VP6D ','VP8 ','VP8G ','VP8H ','VP8O ','VP8S ', + + 'VP9 ','VQ9 ','VR ','VU ','VU4 ','VU7 ','XE ','XF4 ', + + 'XT ','XU ','XW ','XX9 ','XZ ','YA ','YB ','YI ', + + 'YJ ','YK ','YL ','YN ','YO ','YS ','YU ','YV ', + + 'YV0 ','Z2 ','Z3 ','ZA ','ZB ','ZC4 ','ZD7 ','ZD8 ', + + 'ZD9 ','ZF ','ZK1N ','ZK1S ','ZK2 ','ZK3 ','ZL ','ZL7 ', + + 'ZL8 ','ZL9 ','ZP ','ZS ','ZS8 ','KC4 ','E5 '/ diff --git a/libm65/pfxdump.f b/libm65/pfxdump.f index 17ae83c67..1fbddc392 100644 --- a/libm65/pfxdump.f +++ b/libm65/pfxdump.f @@ -1,13 +1,13 @@ - subroutine pfxdump(fname) - character*(*) fname - include 'pfx.f' - - open(11,file=fname,status='unknown') - write(11,1001) sfx - 1001 format('Supported Suffixes:'/(11('/',a1,2x))) - write(11,1002) pfx - 1002 format(/'Supported Add-On DXCC Prefixes:'/(15(a5,1x))) - close(11) - - return - end + subroutine pfxdump(fname) + character*(*) fname + include 'pfx.f' + + open(11,file=fname,status='unknown') + write(11,1001) sfx + 1001 format('Supported Suffixes:'/(11('/',a1,2x))) + write(11,1002) pfx + 1002 format(/'Supported Add-On DXCC Prefixes:'/(15(a5,1x))) + close(11) + + return + end diff --git a/libm65/ptt_unix.c b/libm65/ptt_unix.c index 647762f57..1c8c85606 100644 --- a/libm65/ptt_unix.c +++ b/libm65/ptt_unix.c @@ -1,391 +1,391 @@ -/* - * WSJT is Copyright (c) 2001-2006 by Joseph H. Taylor, Jr., K1JT, - * and is licensed under the GNU General Public License (GPL). - * - * Code used from cwdaemon for parallel port ptt only. - * - * cwdaemon - morse sounding daemon for the parallel or serial port - * Copyright (C) 2002 -2005 Joop Stakenborg - * and many authors, see the AUTHORS file. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -# if HAVE_STDIO_H -# include -#endif -#if STDC_HEADERS -# include -# include -#else -# if HAVE_STDLIB_H -# include -# endif -#endif -#if HAVE_UNISTD_H -# include -#endif -#if HAVE_SYS_IOCTL_H -# include -#endif -#if HAVE_FCNTL_H -# include -#endif - -#ifdef HAVE_LINUX_PPDEV_H -# include -# include -#endif -#ifdef HAVE_DEV_PPBUS_PPI_H -# include -# include -#endif - -int lp_reset (int fd); -int lp_ptt (int fd, int onoff); - -#ifdef HAVE_SYS_STAT_H -# include -#endif -#if (defined(__unix__) || defined(unix)) && !defined(USG) -# include -#endif - -#include -/* parport functions */ - -int dev_is_parport(int fd); -int ptt_parallel(int fd, int *ntx, int *iptt); -int ptt_serial(int fd, int *ntx, int *iptt); - -int fd=-1; /* Used for both serial and parallel */ - -/* - * ptt_ - * - * generic unix PTT routine called from Fortran - * - * Inputs - * unused Unused, to satisfy old windows calling convention - * ptt_port device name serial or parallel - * ntx pointer to fortran command on or off - * iptt pointer to fortran command status on or off - * Returns - non 0 if error -*/ - -/* Tiny state machine */ -#define STATE_PORT_CLOSED 0 -#define STATE_PORT_OPEN_PARALLEL 1 -#define STATE_PORT_OPEN_SERIAL 2 - -//int ptt_(int *unused, char *ptt_port, int *ntx, int *iptt) -int ptt_(int *unused, int *ntx, int *iptt) -{ - static int state=0; - char *p; - -// ### Temporary: - char* ptt_port; - if(*unused != -99) { - *iptt=*ntx; - return 0; - } -// ### - - /* In the very unlikely event of a NULL pointer, just return. - * Yes, I realise this should not be possible in WSJT. - */ - if (ptt_port == NULL) { - *iptt = *ntx; - return (0); - } - - switch (state) { - case STATE_PORT_CLOSED: - - /* Remove trailing ' ' */ - if ((p = strchr(ptt_port, ' ')) != NULL) - *p = '\0'; - - /* If all that is left is a '\0' then also just return */ - if (*ptt_port == '\0') { - *iptt = *ntx; - return(0); - } - - if ((fd = open(ptt_port, O_RDWR|O_NONBLOCK)) < 0) { - fprintf(stderr, "Can't open %s.\n", ptt_port); - return (1); - } - - if (dev_is_parport(fd)) { - state = STATE_PORT_OPEN_PARALLEL; - lp_reset(fd); - ptt_parallel(fd, ntx, iptt); - } else { - state = STATE_PORT_OPEN_SERIAL; - ptt_serial(fd, ntx, iptt); - } - break; - - case STATE_PORT_OPEN_PARALLEL: - ptt_parallel(fd, ntx, iptt); - break; - - case STATE_PORT_OPEN_SERIAL: - ptt_serial(fd, ntx, iptt); - break; - - default: - close(fd); - fd = -1; - state = STATE_PORT_CLOSED; - break; - } - return(0); -} - -/* - * ptt_serial - * - * generic serial unix PTT routine called indirectly from Fortran - * - * fd - already opened file descriptor - * ntx - pointer to fortran command on or off - * iptt - pointer to fortran command status on or off - */ - -int -ptt_serial(int fd, int *ntx, int *iptt) -{ - int control = TIOCM_RTS | TIOCM_DTR; - - if(*ntx) { - ioctl(fd, TIOCMBIS, &control); /* Set DTR and RTS */ - *iptt = 1; - } else { - ioctl(fd, TIOCMBIC, &control); - *iptt = 0; - } - return(0); -} - - -/* parport functions */ - -/* - * dev_is_parport(fd): - * - * inputs - Already open fd - * output - 1 if parallel port, 0 if not - * side effects - Unfortunately, this is platform specific. - */ - -#if defined(HAVE_LINUX_PPDEV_H) /* Linux (ppdev) */ - -int -dev_is_parport(int fd) -{ - struct stat st; - int m; - - if ((fstat(fd, &st) == -1) || - ((st.st_mode & S_IFMT) != S_IFCHR) || - (ioctl(fd, PPGETMODE, &m) == -1)) - return(0); - - return(1); -} - -#elif defined(HAVE_DEV_PPBUS_PPI_H) /* FreeBSD (ppbus/ppi) */ - -int -dev_is_parport(int fd) -{ - struct stat st; - unsigned char c; - - if ((fstat(fd, &st) == -1) || - ((st.st_mode & S_IFMT) != S_IFCHR) || - (ioctl(fd, PPISSTATUS, &c) == -1)) - return(0); - - return(1); -} - -#else /* Fallback (nothing) */ - -int -dev_is_parport(int fd) -{ - return(0); -} - -#endif -/* Linux wrapper around PPFCONTROL */ -#ifdef HAVE_LINUX_PPDEV_H -static void -parport_control (int fd, unsigned char controlbits, int values) -{ - struct ppdev_frob_struct frob; - frob.mask = controlbits; - frob.val = values; - - if (ioctl (fd, PPFCONTROL, &frob) == -1) - { - fprintf(stderr, "Parallel port PPFCONTROL"); - exit (1); - } -} -#endif - -/* FreeBSD wrapper around PPISCTRL */ -#ifdef HAVE_DEV_PPBUS_PPI_H -static void -parport_control (int fd, unsigned char controlbits, int values) -{ - unsigned char val; - - if (ioctl (fd, PPIGCTRL, &val) == -1) - { - fprintf(stderr, "Parallel port PPIGCTRL"); - exit (1); - } - - val &= ~controlbits; - val |= values; - - if (ioctl (fd, PPISCTRL, &val) == -1) - { - fprintf(stderr, "Parallel port PPISCTRL"); - exit (1); - } -} -#endif - -/* Initialise a parallel port, given open fd */ -int -lp_init (int fd) -{ -#ifdef HAVE_LINUX_PPDEV_H - int mode; -#endif - -#ifdef HAVE_LINUX_PPDEV_H - mode = PARPORT_MODE_PCSPP; - - if (ioctl (fd, PPSETMODE, &mode) == -1) - { - fprintf(stderr, "Setting parallel port mode"); - close (fd); - return(-1); - } - - if (ioctl (fd, PPEXCL, NULL) == -1) - { - fprintf(stderr, "Parallel port is already in use.\n"); - close (fd); - return(-1); - } - if (ioctl (fd, PPCLAIM, NULL) == -1) - { - fprintf(stderr, "Claiming parallel port.\n"); - fprintf(stderr, "HINT: did you unload the lp kernel module?"); - close (fd); - return(-1); - } - - /* Enable CW & PTT - /STROBE bit (pin 1) */ - parport_control (fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); -#endif -#ifdef HAVE_DEV_PPBUS_PPI_H - parport_control (fd, STROBE, STROBE); -#endif - lp_reset (fd); - return(0); -} - -/* release ppdev and close port */ -int -lp_free (int fd) -{ -#ifdef HAVE_LINUX_PPDEV_H - lp_reset (fd); - - /* Disable CW & PTT - /STROBE bit (pin 1) */ - parport_control (fd, PARPORT_CONTROL_STROBE, 0); - - ioctl (fd, PPRELEASE); -#endif -#ifdef HAVE_DEV_PPBUS_PPI_H - /* Disable CW & PTT - /STROBE bit (pin 1) */ - parport_control (fd, STROBE, 0); -#endif - close (fd); - return(0); -} - -/* set to a known state */ -int -lp_reset (int fd) -{ -#if defined (HAVE_LINUX_PPDEV_H) || defined (HAVE_DEV_PPBUS_PPI_H) - lp_ptt (fd, 0); -#endif - return(0); -} - -/* SSB PTT keying - /INIT bit (pin 16) (inverted) */ -int -lp_ptt (int fd, int onoff) -{ -#ifdef HAVE_LINUX_PPDEV_H - if (onoff == 1) - parport_control (fd, PARPORT_CONTROL_INIT, - PARPORT_CONTROL_INIT); - else - parport_control (fd, PARPORT_CONTROL_INIT, 0); -#endif -#ifdef HAVE_DEV_PPBUS_PPI_H - if (onoff == 1) - parport_control (fd, nINIT, - nINIT); - else - parport_control (fd, nINIT, 0); -#endif - return(0); -} - -/* - * ptt_parallel - * - * generic parallel unix PTT routine called indirectly from Fortran - * - * fd - already opened file descriptor - * ntx - pointer to fortran command on or off - * iptt - pointer to fortran command status on or off - */ - -int -ptt_parallel(int fd, int *ntx, int *iptt) -{ - if(*ntx) { - lp_ptt(fd, 1); - *iptt=1; - } else { - lp_ptt(fd, 0); - *iptt=0; - } - return(0); -} +/* + * WSJT is Copyright (c) 2001-2006 by Joseph H. Taylor, Jr., K1JT, + * and is licensed under the GNU General Public License (GPL). + * + * Code used from cwdaemon for parallel port ptt only. + * + * cwdaemon - morse sounding daemon for the parallel or serial port + * Copyright (C) 2002 -2005 Joop Stakenborg + * and many authors, see the AUTHORS file. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +# if HAVE_STDIO_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif +#if HAVE_SYS_IOCTL_H +# include +#endif +#if HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_LINUX_PPDEV_H +# include +# include +#endif +#ifdef HAVE_DEV_PPBUS_PPI_H +# include +# include +#endif + +int lp_reset (int fd); +int lp_ptt (int fd, int onoff); + +#ifdef HAVE_SYS_STAT_H +# include +#endif +#if (defined(__unix__) || defined(unix)) && !defined(USG) +# include +#endif + +#include +/* parport functions */ + +int dev_is_parport(int fd); +int ptt_parallel(int fd, int *ntx, int *iptt); +int ptt_serial(int fd, int *ntx, int *iptt); + +int fd=-1; /* Used for both serial and parallel */ + +/* + * ptt_ + * + * generic unix PTT routine called from Fortran + * + * Inputs + * unused Unused, to satisfy old windows calling convention + * ptt_port device name serial or parallel + * ntx pointer to fortran command on or off + * iptt pointer to fortran command status on or off + * Returns - non 0 if error +*/ + +/* Tiny state machine */ +#define STATE_PORT_CLOSED 0 +#define STATE_PORT_OPEN_PARALLEL 1 +#define STATE_PORT_OPEN_SERIAL 2 + +//int ptt_(int *unused, char *ptt_port, int *ntx, int *iptt) +int ptt_(int *unused, int *ntx, int *iptt) +{ + static int state=0; + char *p; + +// ### Temporary: + char* ptt_port; + if(*unused != -99) { + *iptt=*ntx; + return 0; + } +// ### + + /* In the very unlikely event of a NULL pointer, just return. + * Yes, I realise this should not be possible in WSJT. + */ + if (ptt_port == NULL) { + *iptt = *ntx; + return (0); + } + + switch (state) { + case STATE_PORT_CLOSED: + + /* Remove trailing ' ' */ + if ((p = strchr(ptt_port, ' ')) != NULL) + *p = '\0'; + + /* If all that is left is a '\0' then also just return */ + if (*ptt_port == '\0') { + *iptt = *ntx; + return(0); + } + + if ((fd = open(ptt_port, O_RDWR|O_NONBLOCK)) < 0) { + fprintf(stderr, "Can't open %s.\n", ptt_port); + return (1); + } + + if (dev_is_parport(fd)) { + state = STATE_PORT_OPEN_PARALLEL; + lp_reset(fd); + ptt_parallel(fd, ntx, iptt); + } else { + state = STATE_PORT_OPEN_SERIAL; + ptt_serial(fd, ntx, iptt); + } + break; + + case STATE_PORT_OPEN_PARALLEL: + ptt_parallel(fd, ntx, iptt); + break; + + case STATE_PORT_OPEN_SERIAL: + ptt_serial(fd, ntx, iptt); + break; + + default: + close(fd); + fd = -1; + state = STATE_PORT_CLOSED; + break; + } + return(0); +} + +/* + * ptt_serial + * + * generic serial unix PTT routine called indirectly from Fortran + * + * fd - already opened file descriptor + * ntx - pointer to fortran command on or off + * iptt - pointer to fortran command status on or off + */ + +int +ptt_serial(int fd, int *ntx, int *iptt) +{ + int control = TIOCM_RTS | TIOCM_DTR; + + if(*ntx) { + ioctl(fd, TIOCMBIS, &control); /* Set DTR and RTS */ + *iptt = 1; + } else { + ioctl(fd, TIOCMBIC, &control); + *iptt = 0; + } + return(0); +} + + +/* parport functions */ + +/* + * dev_is_parport(fd): + * + * inputs - Already open fd + * output - 1 if parallel port, 0 if not + * side effects - Unfortunately, this is platform specific. + */ + +#if defined(HAVE_LINUX_PPDEV_H) /* Linux (ppdev) */ + +int +dev_is_parport(int fd) +{ + struct stat st; + int m; + + if ((fstat(fd, &st) == -1) || + ((st.st_mode & S_IFMT) != S_IFCHR) || + (ioctl(fd, PPGETMODE, &m) == -1)) + return(0); + + return(1); +} + +#elif defined(HAVE_DEV_PPBUS_PPI_H) /* FreeBSD (ppbus/ppi) */ + +int +dev_is_parport(int fd) +{ + struct stat st; + unsigned char c; + + if ((fstat(fd, &st) == -1) || + ((st.st_mode & S_IFMT) != S_IFCHR) || + (ioctl(fd, PPISSTATUS, &c) == -1)) + return(0); + + return(1); +} + +#else /* Fallback (nothing) */ + +int +dev_is_parport(int fd) +{ + return(0); +} + +#endif +/* Linux wrapper around PPFCONTROL */ +#ifdef HAVE_LINUX_PPDEV_H +static void +parport_control (int fd, unsigned char controlbits, int values) +{ + struct ppdev_frob_struct frob; + frob.mask = controlbits; + frob.val = values; + + if (ioctl (fd, PPFCONTROL, &frob) == -1) + { + fprintf(stderr, "Parallel port PPFCONTROL"); + exit (1); + } +} +#endif + +/* FreeBSD wrapper around PPISCTRL */ +#ifdef HAVE_DEV_PPBUS_PPI_H +static void +parport_control (int fd, unsigned char controlbits, int values) +{ + unsigned char val; + + if (ioctl (fd, PPIGCTRL, &val) == -1) + { + fprintf(stderr, "Parallel port PPIGCTRL"); + exit (1); + } + + val &= ~controlbits; + val |= values; + + if (ioctl (fd, PPISCTRL, &val) == -1) + { + fprintf(stderr, "Parallel port PPISCTRL"); + exit (1); + } +} +#endif + +/* Initialise a parallel port, given open fd */ +int +lp_init (int fd) +{ +#ifdef HAVE_LINUX_PPDEV_H + int mode; +#endif + +#ifdef HAVE_LINUX_PPDEV_H + mode = PARPORT_MODE_PCSPP; + + if (ioctl (fd, PPSETMODE, &mode) == -1) + { + fprintf(stderr, "Setting parallel port mode"); + close (fd); + return(-1); + } + + if (ioctl (fd, PPEXCL, NULL) == -1) + { + fprintf(stderr, "Parallel port is already in use.\n"); + close (fd); + return(-1); + } + if (ioctl (fd, PPCLAIM, NULL) == -1) + { + fprintf(stderr, "Claiming parallel port.\n"); + fprintf(stderr, "HINT: did you unload the lp kernel module?"); + close (fd); + return(-1); + } + + /* Enable CW & PTT - /STROBE bit (pin 1) */ + parport_control (fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); +#endif +#ifdef HAVE_DEV_PPBUS_PPI_H + parport_control (fd, STROBE, STROBE); +#endif + lp_reset (fd); + return(0); +} + +/* release ppdev and close port */ +int +lp_free (int fd) +{ +#ifdef HAVE_LINUX_PPDEV_H + lp_reset (fd); + + /* Disable CW & PTT - /STROBE bit (pin 1) */ + parport_control (fd, PARPORT_CONTROL_STROBE, 0); + + ioctl (fd, PPRELEASE); +#endif +#ifdef HAVE_DEV_PPBUS_PPI_H + /* Disable CW & PTT - /STROBE bit (pin 1) */ + parport_control (fd, STROBE, 0); +#endif + close (fd); + return(0); +} + +/* set to a known state */ +int +lp_reset (int fd) +{ +#if defined (HAVE_LINUX_PPDEV_H) || defined (HAVE_DEV_PPBUS_PPI_H) + lp_ptt (fd, 0); +#endif + return(0); +} + +/* SSB PTT keying - /INIT bit (pin 16) (inverted) */ +int +lp_ptt (int fd, int onoff) +{ +#ifdef HAVE_LINUX_PPDEV_H + if (onoff == 1) + parport_control (fd, PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + else + parport_control (fd, PARPORT_CONTROL_INIT, 0); +#endif +#ifdef HAVE_DEV_PPBUS_PPI_H + if (onoff == 1) + parport_control (fd, nINIT, + nINIT); + else + parport_control (fd, nINIT, 0); +#endif + return(0); +} + +/* + * ptt_parallel + * + * generic parallel unix PTT routine called indirectly from Fortran + * + * fd - already opened file descriptor + * ntx - pointer to fortran command on or off + * iptt - pointer to fortran command status on or off + */ + +int +ptt_parallel(int fd, int *ntx, int *iptt) +{ + if(*ntx) { + lp_ptt(fd, 1); + *iptt=1; + } else { + lp_ptt(fd, 0); + *iptt=0; + } + return(0); +} diff --git a/libm65/recvpkt.f90 b/libm65/recvpkt.f90 index 300139611..f55288d88 100644 --- a/libm65/recvpkt.f90 +++ b/libm65/recvpkt.f90 @@ -1,70 +1,70 @@ -subroutine recvpkt(nsam,nblock2,userx_no,k,buf4,buf8,buf16) - -! Reformat timf2 data from Linrad and stuff data into r*4 array dd(). - - parameter (NSMAX=60*96000) !Total sample intervals per minute - parameter (NFFT=32768) - integer*1 userx_no - real*4 d4,buf4(*) !(348) - real*8 d8,buf8(*) !(174) - complex*16 c16,buf16(*) !(87) - integer*2 jd(4),kd(2),nblock2 - real*4 xd(4),yd(2) - real*8 fcenter - common/datcom/dd(4,5760000),ss(4,322,NFFT),savg(4,NFFT),fcenter,nutc,junk(34) - equivalence (kd,d4) - equivalence (jd,d8,yd) - equivalence (xd,c16) - - if(nsam.eq.-1) then -! Move data from the UDP packet buffer into array dd(). - if(userx_no.eq.-1) then - do i=1,174 !One RF channel, r*4 data - k=k+1 - d8=buf8(i) - dd(1,k)=yd(1) - dd(2,k)=yd(2) - enddo - else if(userx_no.eq.1) then - do i=1,348 !One RF channel, i*2 data - k=k+1 - d4=buf4(i) - dd(1,k)=kd(1) - dd(2,k)=kd(2) - enddo - else if(userx_no.eq.-2) then - do i=1,87 !Two RF channels, r*4 data - k=k+1 - c16=buf16(i) - dd(1,k)=xd(1) - dd(2,k)=xd(2) - dd(3,k)=xd(3) - dd(4,k)=xd(4) - enddo - else if(userx_no.eq.2) then - do i=1,174 !Two RF channels, i*2 data - k=k+1 - d8=buf8(i) - dd(1,k)=jd(1) - dd(2,k)=jd(2) - dd(3,k)=jd(3) - dd(4,k)=jd(4) - enddo - endif - else - if(userx_no.eq.1) then - do i=1,nsam !One RF channel, r*4 data - k=k+1 - d4=buf4(i) - dd(1,k)=kd(1) - dd(2,k)=kd(2) - - k=k+1 - dd(1,k)=kd(1) - dd(2,k)=kd(2) - enddo - endif - endif - - return -end subroutine recvpkt +subroutine recvpkt(nsam,nblock2,userx_no,k,buf4,buf8,buf16) + +! Reformat timf2 data from Linrad and stuff data into r*4 array dd(). + + parameter (NSMAX=60*96000) !Total sample intervals per minute + parameter (NFFT=32768) + integer*1 userx_no + real*4 d4,buf4(*) !(348) + real*8 d8,buf8(*) !(174) + complex*16 c16,buf16(*) !(87) + integer*2 jd(4),kd(2),nblock2 + real*4 xd(4),yd(2) + real*8 fcenter + common/datcom/dd(4,5760000),ss(4,322,NFFT),savg(4,NFFT),fcenter,nutc,junk(34) + equivalence (kd,d4) + equivalence (jd,d8,yd) + equivalence (xd,c16) + + if(nsam.eq.-1) then +! Move data from the UDP packet buffer into array dd(). + if(userx_no.eq.-1) then + do i=1,174 !One RF channel, r*4 data + k=k+1 + d8=buf8(i) + dd(1,k)=yd(1) + dd(2,k)=yd(2) + enddo + else if(userx_no.eq.1) then + do i=1,348 !One RF channel, i*2 data + k=k+1 + d4=buf4(i) + dd(1,k)=kd(1) + dd(2,k)=kd(2) + enddo + else if(userx_no.eq.-2) then + do i=1,87 !Two RF channels, r*4 data + k=k+1 + c16=buf16(i) + dd(1,k)=xd(1) + dd(2,k)=xd(2) + dd(3,k)=xd(3) + dd(4,k)=xd(4) + enddo + else if(userx_no.eq.2) then + do i=1,174 !Two RF channels, i*2 data + k=k+1 + d8=buf8(i) + dd(1,k)=jd(1) + dd(2,k)=jd(2) + dd(3,k)=jd(3) + dd(4,k)=jd(4) + enddo + endif + else + if(userx_no.eq.1) then + do i=1,nsam !One RF channel, r*4 data + k=k+1 + d4=buf4(i) + dd(1,k)=kd(1) + dd(2,k)=kd(2) + + k=k+1 + dd(1,k)=kd(1) + dd(2,k)=kd(2) + enddo + endif + endif + + return +end subroutine recvpkt diff --git a/libm65/rfile3a.f90 b/libm65/rfile3a.f90 index db12e4df1..7e2266513 100644 --- a/libm65/rfile3a.f90 +++ b/libm65/rfile3a.f90 @@ -1,14 +1,14 @@ -subroutine rfile3a(infile,ibuf,n,fcenter,ierr) - - character*(*) infile - integer*8 ibuf(n) - real*8 fcenter - - open(10,file=infile,access='stream',status='old',err=998) - read(10,end=998) (ibuf(i),i=1,n/8),fcenter - ierr=0 - go to 999 -998 ierr=1002 -999 close(10) - return -end subroutine rfile3a +subroutine rfile3a(infile,ibuf,n,fcenter,ierr) + + character*(*) infile + integer*8 ibuf(n) + real*8 fcenter + + open(10,file=infile,access='stream',status='old',err=998) + read(10,end=998) (ibuf(i),i=1,n/8),fcenter + ierr=0 + go to 999 +998 ierr=1002 +999 close(10) + return +end subroutine rfile3a diff --git a/libm65/rs.h b/libm65/rs.h index 6f1531467..06cbe344f 100644 --- a/libm65/rs.h +++ b/libm65/rs.h @@ -1,35 +1,35 @@ -/* User include file for the Reed-Solomon codec - * Copyright 2002, Phil Karn KA9Q - * May be used under the terms of the GNU General Public License (GPL) - */ - -/* General purpose RS codec, 8-bit symbols */ -void encode_rs_char(void *rs,unsigned char *data,unsigned char *parity); -int decode_rs_char(void *rs,unsigned char *data,int *eras_pos, - int no_eras); -void *init_rs_char(int symsize,int gfpoly, - int fcr,int prim,int nroots, - int pad); -void free_rs_char(void *rs); - -/* General purpose RS codec, integer symbols */ -void encode_rs_int(void *rs,int *data,int *parity); -int decode_rs_int(void *rs,int *data,int *eras_pos,int no_eras); -void *init_rs_int(int symsize,int gfpoly,int fcr, - int prim,int nroots,int pad); -void free_rs_int(void *rs); - -/* CCSDS standard (255,223) RS codec with conventional (*not* dual-basis) - * symbol representation - */ -void encode_rs_8(unsigned char *data,unsigned char *parity,int pad); -int decode_rs_8(unsigned char *data,int *eras_pos,int no_eras,int pad); - -/* CCSDS standard (255,223) RS codec with dual-basis symbol representation */ -void encode_rs_ccsds(unsigned char *data,unsigned char *parity,int pad); -int decode_rs_ccsds(unsigned char *data,int *eras_pos,int no_eras,int pad); - -/* Tables to map from conventional->dual (Taltab) and - * dual->conventional (Tal1tab) bases - */ -extern unsigned char Taltab[],Tal1tab[]; +/* User include file for the Reed-Solomon codec + * Copyright 2002, Phil Karn KA9Q + * May be used under the terms of the GNU General Public License (GPL) + */ + +/* General purpose RS codec, 8-bit symbols */ +void encode_rs_char(void *rs,unsigned char *data,unsigned char *parity); +int decode_rs_char(void *rs,unsigned char *data,int *eras_pos, + int no_eras); +void *init_rs_char(int symsize,int gfpoly, + int fcr,int prim,int nroots, + int pad); +void free_rs_char(void *rs); + +/* General purpose RS codec, integer symbols */ +void encode_rs_int(void *rs,int *data,int *parity); +int decode_rs_int(void *rs,int *data,int *eras_pos,int no_eras); +void *init_rs_int(int symsize,int gfpoly,int fcr, + int prim,int nroots,int pad); +void free_rs_int(void *rs); + +/* CCSDS standard (255,223) RS codec with conventional (*not* dual-basis) + * symbol representation + */ +void encode_rs_8(unsigned char *data,unsigned char *parity,int pad); +int decode_rs_8(unsigned char *data,int *eras_pos,int no_eras,int pad); + +/* CCSDS standard (255,223) RS codec with dual-basis symbol representation */ +void encode_rs_ccsds(unsigned char *data,unsigned char *parity,int pad); +int decode_rs_ccsds(unsigned char *data,int *eras_pos,int no_eras,int pad); + +/* Tables to map from conventional->dual (Taltab) and + * dual->conventional (Tal1tab) bases + */ +extern unsigned char Taltab[],Tal1tab[]; diff --git a/libm65/s3avg.f90 b/libm65/s3avg.f90 index 905a32d3d..c50927bf3 100644 --- a/libm65/s3avg.f90 +++ b/libm65/s3avg.f90 @@ -1,42 +1,42 @@ -subroutine s3avg(nsave,mode65,nutc,ndf,xdt,npol,s3,nkv,decoded) - - real s3(64,63),s3b(64,63) - real s3a(64,63,32) - integer iutc(32),idf(32),ipol(32) - real dt(32) - character*22 decoded - logical ltext - save - - n=nsave - iutc(n)=nutc - idf(n)=ndf - ipol(n)=npol - dt(n)=xdt - s3a(1:64,1:63,n)=s3 - - s3b=0. - nsum=0 - idfdiff=100 - dtdiff=0.2 - do i=1,n - if(mod(iutc(i),2).ne.mod(nutc,2)) cycle - if(abs(ndf-idf(i)).gt.idfdiff) cycle - if(abs(xdt-dt(i)).gt.dtdiff) cycle - s3b=s3b + s3a(1:64,1:63,i) - nsum=nsum+1 - enddo - - decoded=' ' - if(nsum.ge.2) then - nadd=mode65*nsum - call extract(s3b,nadd,ncount,nhist,decoded,ltext) !Extract the message - nkv=nsum - if(ncount.lt.0) then - nkv=0 - decoded=' ' - endif - endif - - return -end subroutine s3avg +subroutine s3avg(nsave,mode65,nutc,ndf,xdt,npol,s3,nkv,decoded) + + real s3(64,63),s3b(64,63) + real s3a(64,63,32) + integer iutc(32),idf(32),ipol(32) + real dt(32) + character*22 decoded + logical ltext + save + + n=nsave + iutc(n)=nutc + idf(n)=ndf + ipol(n)=npol + dt(n)=xdt + s3a(1:64,1:63,n)=s3 + + s3b=0. + nsum=0 + idfdiff=100 + dtdiff=0.2 + do i=1,n + if(mod(iutc(i),2).ne.mod(nutc,2)) cycle + if(abs(ndf-idf(i)).gt.idfdiff) cycle + if(abs(xdt-dt(i)).gt.dtdiff) cycle + s3b=s3b + s3a(1:64,1:63,i) + nsum=nsum+1 + enddo + + decoded=' ' + if(nsum.ge.2) then + nadd=mode65*nsum + call extract(s3b,nadd,ncount,nhist,decoded,ltext) !Extract the message + nkv=nsum + if(ncount.lt.0) then + nkv=0 + decoded=' ' + endif + endif + + return +end subroutine s3avg diff --git a/libm65/set.f b/libm65/set.f index adb17c977..e93740a8a 100644 --- a/libm65/set.f +++ b/libm65/set.f @@ -1,31 +1,31 @@ - subroutine set(a,y,n) - real y(n) - do i=1,n - y(i)=a - enddo - return - end - - subroutine move(x,y,n) - real x(n),y(n) - do i=1,n - y(i)=x(i) - enddo - return - end - - subroutine zero(x,n) - real x(n) - do i=1,n - x(i)=0.0 - enddo - return - end - - subroutine add(a,b,c,n) - real a(n),b(n),c(n) - do i=1,n - c(i)=a(i)+b(i) - enddo - return - end + subroutine set(a,y,n) + real y(n) + do i=1,n + y(i)=a + enddo + return + end + + subroutine move(x,y,n) + real x(n),y(n) + do i=1,n + y(i)=x(i) + enddo + return + end + + subroutine zero(x,n) + real x(n) + do i=1,n + x(i)=0.0 + enddo + return + end + + subroutine add(a,b,c,n) + real a(n),b(n),c(n) + do i=1,n + c(i)=a(i)+b(i) + enddo + return + end diff --git a/libm65/setup65.f b/libm65/setup65.f index 980361e25..25b821e5a 100644 --- a/libm65/setup65.f +++ b/libm65/setup65.f @@ -1,96 +1,96 @@ - subroutine setup65 - -C Defines arrays related to the JT65 pseudo-random synchronizing pattern. -C Executed at program start. - - integer nprc(126) - common/prcom/pr(126),mdat(126),mref(126,2),mdat2(126),mref2(126,2) - -C JT65 - data nprc/ - + 1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0, - + 0,1,0,1,1,0,0,1,0,0,0,1,1,1,0,0,1,1,1,1, - + 0,1,1,0,1,1,1,1,0,0,0,1,1,0,1,0,1,0,1,1, - + 0,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,1, - + 1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1, - + 0,1,0,1,0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,1, - + 1,1,1,1,1,1/ - data mr2/0/ !Silence compiler warning - -C Put the appropriate pseudo-random sequence into pr - nsym=126 - do i=1,nsym - pr(i)=2*nprc(i)-1 - enddo - -C Determine locations of data and reference symbols - k=0 - mr1=0 - do i=1,nsym - if(pr(i).lt.0.0) then - k=k+1 - mdat(k)=i - else - mr2=i - if(mr1.eq.0) mr1=i - endif - enddo - nsig=k - -C Determine the reference symbols for each data symbol. - do k=1,nsig - m=mdat(k) - mref(k,1)=mr1 - do n=1,10 !Get ref symbol before data - if((m-n).gt.0) then - if (pr(m-n).gt.0.0) go to 10 - endif - enddo - go to 12 - 10 mref(k,1)=m-n - 12 mref(k,2)=mr2 - do n=1,10 !Get ref symbol after data - if((m+n).le.nsym) then - if (pr(m+n).gt.0.0) go to 20 - endif - enddo - go to 22 - 20 mref(k,2)=m+n - 22 enddo - -C Now do it all again, using opposite logic on pr(i) - k=0 - mr1=0 - do i=1,nsym - if(pr(i).gt.0.0) then - k=k+1 - mdat2(k)=i - else - mr2=i - if(mr1.eq.0) mr1=i - endif - enddo - nsig=k - - do k=1,nsig - m=mdat2(k) - mref2(k,1)=mr1 - do n=1,10 - if((m-n).gt.0) then - if (pr(m-n).lt.0.0) go to 110 - endif - enddo - go to 112 - 110 mref2(k,1)=m-n - 112 mref2(k,2)=mr2 - do n=1,10 - if((m+n).le.nsym) then - if (pr(m+n).lt.0.0) go to 120 - endif - enddo - go to 122 - 120 mref2(k,2)=m+n - 122 enddo - - return - end + subroutine setup65 + +C Defines arrays related to the JT65 pseudo-random synchronizing pattern. +C Executed at program start. + + integer nprc(126) + common/prcom/pr(126),mdat(126),mref(126,2),mdat2(126),mref2(126,2) + +C JT65 + data nprc/ + + 1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0, + + 0,1,0,1,1,0,0,1,0,0,0,1,1,1,0,0,1,1,1,1, + + 0,1,1,0,1,1,1,1,0,0,0,1,1,0,1,0,1,0,1,1, + + 0,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,1, + + 1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1, + + 0,1,0,1,0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,1, + + 1,1,1,1,1,1/ + data mr2/0/ !Silence compiler warning + +C Put the appropriate pseudo-random sequence into pr + nsym=126 + do i=1,nsym + pr(i)=2*nprc(i)-1 + enddo + +C Determine locations of data and reference symbols + k=0 + mr1=0 + do i=1,nsym + if(pr(i).lt.0.0) then + k=k+1 + mdat(k)=i + else + mr2=i + if(mr1.eq.0) mr1=i + endif + enddo + nsig=k + +C Determine the reference symbols for each data symbol. + do k=1,nsig + m=mdat(k) + mref(k,1)=mr1 + do n=1,10 !Get ref symbol before data + if((m-n).gt.0) then + if (pr(m-n).gt.0.0) go to 10 + endif + enddo + go to 12 + 10 mref(k,1)=m-n + 12 mref(k,2)=mr2 + do n=1,10 !Get ref symbol after data + if((m+n).le.nsym) then + if (pr(m+n).gt.0.0) go to 20 + endif + enddo + go to 22 + 20 mref(k,2)=m+n + 22 enddo + +C Now do it all again, using opposite logic on pr(i) + k=0 + mr1=0 + do i=1,nsym + if(pr(i).gt.0.0) then + k=k+1 + mdat2(k)=i + else + mr2=i + if(mr1.eq.0) mr1=i + endif + enddo + nsig=k + + do k=1,nsig + m=mdat2(k) + mref2(k,1)=mr1 + do n=1,10 + if((m-n).gt.0) then + if (pr(m-n).lt.0.0) go to 110 + endif + enddo + go to 112 + 110 mref2(k,1)=m-n + 112 mref2(k,2)=mr2 + do n=1,10 + if((m+n).le.nsym) then + if (pr(m+n).lt.0.0) go to 120 + endif + enddo + go to 122 + 120 mref2(k,2)=m+n + 122 enddo + + return + end diff --git a/libm65/sleep_msec.f90 b/libm65/sleep_msec.f90 index 7308d410b..66841b895 100644 --- a/libm65/sleep_msec.f90 +++ b/libm65/sleep_msec.f90 @@ -1,3 +1,3 @@ -subroutine sleep_msec(n) - return -end subroutine sleep_msec +subroutine sleep_msec(n) + return +end subroutine sleep_msec diff --git a/libm65/sort.f b/libm65/sort.f index 41f18e3f8..7888b0cfd 100644 --- a/libm65/sort.f +++ b/libm65/sort.f @@ -1,4 +1,4 @@ - subroutine sort(n,arr) - call ssort(arr,tmp,n,1) - return - end + subroutine sort(n,arr) + call ssort(arr,tmp,n,1) + return + end diff --git a/libm65/ssort.f b/libm65/ssort.f index cea0c2d42..fa508ace6 100644 --- a/libm65/ssort.f +++ b/libm65/ssort.f @@ -1,287 +1,287 @@ - subroutine ssort (x,y,n,kflag) -c***purpose sort an array and optionally make the same interchanges in -c an auxiliary array. the array may be sorted in increasing -c or decreasing order. a slightly modified quicksort -c algorithm is used. -c -c ssort sorts array x and optionally makes the same interchanges in -c array y. the array x may be sorted in increasing order or -c decreasing order. a slightly modified quicksort algorithm is used. -c -c description of parameters -c x - array of values to be sorted -c y - array to be (optionally) carried along -c n - number of values in array x to be sorted -c kflag - control parameter -c = 2 means sort x in increasing order and carry y along. -c = 1 means sort x in increasing order (ignoring y) -c = -1 means sort x in decreasing order (ignoring y) -c = -2 means sort x in decreasing order and carry y along. - - integer kflag, n -! real x(n), y(n) -! real r, t, tt, tty, ty - integer x(n), y(n) - integer r, t, tt, tty, ty - integer i, ij, j, k, kk, l, m, nn - integer il(21), iu(21) - - nn = n - if (nn .lt. 1) then -! print*,'ssort: The number of sort elements is not positive.' -! print*,'ssort: n = ',nn,' kflag = ',kflag - return - endif -c - kk = abs(kflag) - if (kk.ne.1 .and. kk.ne.2) then - print *, - + 'the sort control parameter, k, is not 2, 1, -1, or -2.' - return - endif -c -c alter array x to get decreasing order if needed -c - if (kflag .le. -1) then - do 10 i=1,nn - x(i) = -x(i) - 10 continue - endif -c - if (kk .eq. 2) go to 100 -c -c sort x only -c - m = 1 - i = 1 - j = nn - r = 0.375e0 -c - 20 if (i .eq. j) go to 60 - if (r .le. 0.5898437e0) then - r = r+3.90625e-2 - else - r = r-0.21875e0 - endif -c - 30 k = i -c -c select a central element of the array and save it in location t -c - ij = i + int((j-i)*r) - t = x(ij) -c -c if first element of array is greater than t, interchange with t -c - if (x(i) .gt. t) then - x(ij) = x(i) - x(i) = t - t = x(ij) - endif - l = j -c -c if last element of array is less than than t, interchange with t -c - if (x(j) .lt. t) then - x(ij) = x(j) - x(j) = t - t = x(ij) -c -c if first element of array is greater than t, interchange with t -c - if (x(i) .gt. t) then - x(ij) = x(i) - x(i) = t - t = x(ij) - endif - endif -c -c find an element in the second half of the array which is smaller -c than t -c - 40 l = l-1 - if (x(l) .gt. t) go to 40 -c -c find an element in the first half of the array which is greater -c than t -c - 50 k = k+1 - if (x(k) .lt. t) go to 50 -c -c interchange these elements -c - if (k .le. l) then - tt = x(l) - x(l) = x(k) - x(k) = tt - go to 40 - endif -c -c save upper and lower subscripts of the array yet to be sorted -c - if (l-i .gt. j-k) then - il(m) = i - iu(m) = l - i = k - m = m+1 - else - il(m) = k - iu(m) = j - j = l - m = m+1 - endif - go to 70 -c -c begin again on another portion of the unsorted array -c - 60 m = m-1 - if (m .eq. 0) go to 190 - i = il(m) - j = iu(m) -c - 70 if (j-i .ge. 1) go to 30 - if (i .eq. 1) go to 20 - i = i-1 -c - 80 i = i+1 - if (i .eq. j) go to 60 - t = x(i+1) - if (x(i) .le. t) go to 80 - k = i -c - 90 x(k+1) = x(k) - k = k-1 - if (t .lt. x(k)) go to 90 - x(k+1) = t - go to 80 -c -c sort x and carry y along -c - 100 m = 1 - i = 1 - j = nn - r = 0.375e0 -c - 110 if (i .eq. j) go to 150 - if (r .le. 0.5898437e0) then - r = r+3.90625e-2 - else - r = r-0.21875e0 - endif -c - 120 k = i -c -c select a central element of the array and save it in location t -c - ij = i + int((j-i)*r) - t = x(ij) - ty = y(ij) -c -c if first element of array is greater than t, interchange with t -c - if (x(i) .gt. t) then - x(ij) = x(i) - x(i) = t - t = x(ij) - y(ij) = y(i) - y(i) = ty - ty = y(ij) - endif - l = j -c -c if last element of array is less than t, interchange with t -c - if (x(j) .lt. t) then - x(ij) = x(j) - x(j) = t - t = x(ij) - y(ij) = y(j) - y(j) = ty - ty = y(ij) -c -c if first element of array is greater than t, interchange with t -c - if (x(i) .gt. t) then - x(ij) = x(i) - x(i) = t - t = x(ij) - y(ij) = y(i) - y(i) = ty - ty = y(ij) - endif - endif -c -c find an element in the second half of the array which is smaller -c than t -c - 130 l = l-1 - if (x(l) .gt. t) go to 130 -c -c find an element in the first half of the array which is greater -c than t -c - 140 k = k+1 - if (x(k) .lt. t) go to 140 -c -c interchange these elements -c - if (k .le. l) then - tt = x(l) - x(l) = x(k) - x(k) = tt - tty = y(l) - y(l) = y(k) - y(k) = tty - go to 130 - endif -c -c save upper and lower subscripts of the array yet to be sorted -c - if (l-i .gt. j-k) then - il(m) = i - iu(m) = l - i = k - m = m+1 - else - il(m) = k - iu(m) = j - j = l - m = m+1 - endif - go to 160 -c -c begin again on another portion of the unsorted array -c - 150 m = m-1 - if (m .eq. 0) go to 190 - i = il(m) - j = iu(m) -c - 160 if (j-i .ge. 1) go to 120 - if (i .eq. 1) go to 110 - i = i-1 -c - 170 i = i+1 - if (i .eq. j) go to 150 - t = x(i+1) - ty = y(i+1) - if (x(i) .le. t) go to 170 - k = i -c - 180 x(k+1) = x(k) - y(k+1) = y(k) - k = k-1 - if (t .lt. x(k)) go to 180 - x(k+1) = t - y(k+1) = ty - go to 170 -c -c clean up -c - 190 if (kflag .le. -1) then - do 200 i=1,nn - x(i) = -x(i) - 200 continue - endif - return - end + subroutine ssort (x,y,n,kflag) +c***purpose sort an array and optionally make the same interchanges in +c an auxiliary array. the array may be sorted in increasing +c or decreasing order. a slightly modified quicksort +c algorithm is used. +c +c ssort sorts array x and optionally makes the same interchanges in +c array y. the array x may be sorted in increasing order or +c decreasing order. a slightly modified quicksort algorithm is used. +c +c description of parameters +c x - array of values to be sorted +c y - array to be (optionally) carried along +c n - number of values in array x to be sorted +c kflag - control parameter +c = 2 means sort x in increasing order and carry y along. +c = 1 means sort x in increasing order (ignoring y) +c = -1 means sort x in decreasing order (ignoring y) +c = -2 means sort x in decreasing order and carry y along. + + integer kflag, n +! real x(n), y(n) +! real r, t, tt, tty, ty + integer x(n), y(n) + integer r, t, tt, tty, ty + integer i, ij, j, k, kk, l, m, nn + integer il(21), iu(21) + + nn = n + if (nn .lt. 1) then +! print*,'ssort: The number of sort elements is not positive.' +! print*,'ssort: n = ',nn,' kflag = ',kflag + return + endif +c + kk = abs(kflag) + if (kk.ne.1 .and. kk.ne.2) then + print *, + + 'the sort control parameter, k, is not 2, 1, -1, or -2.' + return + endif +c +c alter array x to get decreasing order if needed +c + if (kflag .le. -1) then + do 10 i=1,nn + x(i) = -x(i) + 10 continue + endif +c + if (kk .eq. 2) go to 100 +c +c sort x only +c + m = 1 + i = 1 + j = nn + r = 0.375e0 +c + 20 if (i .eq. j) go to 60 + if (r .le. 0.5898437e0) then + r = r+3.90625e-2 + else + r = r-0.21875e0 + endif +c + 30 k = i +c +c select a central element of the array and save it in location t +c + ij = i + int((j-i)*r) + t = x(ij) +c +c if first element of array is greater than t, interchange with t +c + if (x(i) .gt. t) then + x(ij) = x(i) + x(i) = t + t = x(ij) + endif + l = j +c +c if last element of array is less than than t, interchange with t +c + if (x(j) .lt. t) then + x(ij) = x(j) + x(j) = t + t = x(ij) +c +c if first element of array is greater than t, interchange with t +c + if (x(i) .gt. t) then + x(ij) = x(i) + x(i) = t + t = x(ij) + endif + endif +c +c find an element in the second half of the array which is smaller +c than t +c + 40 l = l-1 + if (x(l) .gt. t) go to 40 +c +c find an element in the first half of the array which is greater +c than t +c + 50 k = k+1 + if (x(k) .lt. t) go to 50 +c +c interchange these elements +c + if (k .le. l) then + tt = x(l) + x(l) = x(k) + x(k) = tt + go to 40 + endif +c +c save upper and lower subscripts of the array yet to be sorted +c + if (l-i .gt. j-k) then + il(m) = i + iu(m) = l + i = k + m = m+1 + else + il(m) = k + iu(m) = j + j = l + m = m+1 + endif + go to 70 +c +c begin again on another portion of the unsorted array +c + 60 m = m-1 + if (m .eq. 0) go to 190 + i = il(m) + j = iu(m) +c + 70 if (j-i .ge. 1) go to 30 + if (i .eq. 1) go to 20 + i = i-1 +c + 80 i = i+1 + if (i .eq. j) go to 60 + t = x(i+1) + if (x(i) .le. t) go to 80 + k = i +c + 90 x(k+1) = x(k) + k = k-1 + if (t .lt. x(k)) go to 90 + x(k+1) = t + go to 80 +c +c sort x and carry y along +c + 100 m = 1 + i = 1 + j = nn + r = 0.375e0 +c + 110 if (i .eq. j) go to 150 + if (r .le. 0.5898437e0) then + r = r+3.90625e-2 + else + r = r-0.21875e0 + endif +c + 120 k = i +c +c select a central element of the array and save it in location t +c + ij = i + int((j-i)*r) + t = x(ij) + ty = y(ij) +c +c if first element of array is greater than t, interchange with t +c + if (x(i) .gt. t) then + x(ij) = x(i) + x(i) = t + t = x(ij) + y(ij) = y(i) + y(i) = ty + ty = y(ij) + endif + l = j +c +c if last element of array is less than t, interchange with t +c + if (x(j) .lt. t) then + x(ij) = x(j) + x(j) = t + t = x(ij) + y(ij) = y(j) + y(j) = ty + ty = y(ij) +c +c if first element of array is greater than t, interchange with t +c + if (x(i) .gt. t) then + x(ij) = x(i) + x(i) = t + t = x(ij) + y(ij) = y(i) + y(i) = ty + ty = y(ij) + endif + endif +c +c find an element in the second half of the array which is smaller +c than t +c + 130 l = l-1 + if (x(l) .gt. t) go to 130 +c +c find an element in the first half of the array which is greater +c than t +c + 140 k = k+1 + if (x(k) .lt. t) go to 140 +c +c interchange these elements +c + if (k .le. l) then + tt = x(l) + x(l) = x(k) + x(k) = tt + tty = y(l) + y(l) = y(k) + y(k) = tty + go to 130 + endif +c +c save upper and lower subscripts of the array yet to be sorted +c + if (l-i .gt. j-k) then + il(m) = i + iu(m) = l + i = k + m = m+1 + else + il(m) = k + iu(m) = j + j = l + m = m+1 + endif + go to 160 +c +c begin again on another portion of the unsorted array +c + 150 m = m-1 + if (m .eq. 0) go to 190 + i = il(m) + j = iu(m) +c + 160 if (j-i .ge. 1) go to 120 + if (i .eq. 1) go to 110 + i = i-1 +c + 170 i = i+1 + if (i .eq. j) go to 150 + t = x(i+1) + ty = y(i+1) + if (x(i) .le. t) go to 170 + k = i +c + 180 x(k+1) = x(k) + y(k+1) = y(k) + k = k-1 + if (t .lt. x(k)) go to 180 + x(k+1) = t + y(k+1) = ty + go to 170 +c +c clean up +c + 190 if (kflag .le. -1) then + do 200 i=1,nn + x(i) = -x(i) + 200 continue + endif + return + end diff --git a/libm65/sun.f b/libm65/sun.f index f9772070e..a3f326e7f 100644 --- a/libm65/sun.f +++ b/libm65/sun.f @@ -1,88 +1,88 @@ - subroutine sun(y,m,DD,UT,lon,lat,RA,Dec,LST,Az,El,mjd,day) - - implicit none - - integer y !Year - integer m !Month - integer DD !Day - integer mjd !Modified Julian Date - real UT !UTC in hours - real RA,Dec !RA and Dec of sun - -C NB: Double caps here are single caps in the writeup. - -C Orbital elements of the Sun (also N=0, i=0, a=1): - real w !Argument of perihelion - real e !Eccentricity - real MM !Mean anomaly - real Ls !Mean longitude - -C Other standard variables: - real v !True anomaly - real EE !Eccentric anomaly - real ecl !Obliquity of the ecliptic - real d !Ephemeris time argument in days - real r !Distance to sun, AU - real xv,yv !x and y coords in ecliptic - real lonsun !Ecliptic long and lat of sun -C Ecliptic coords of sun (geocentric) - real xs,ys -C Equatorial coords of sun (geocentric) - real xe,ye,ze - real lon,lat - real GMST0,LST,HA - real xx,yy,zz - real xhor,yhor,zhor - real Az,El - - real day - real rad - data rad/57.2957795/ - -C Time in days, with Jan 0, 2000 equal to 0.0: - d=367*y - 7*(y+(m+9)/12)/4 + 275*m/9 + DD - 730530 + UT/24.0 - mjd=d + 51543 - ecl = 23.4393 - 3.563e-7 * d - -C Compute updated orbital elements for Sun: - w = 282.9404 + 4.70935e-5 * d - e = 0.016709 - 1.151e-9 * d - MM = mod(356.0470d0 + 0.9856002585d0 * d + 360000.d0,360.d0) - Ls = mod(w+MM+720.0,360.0) - - EE = MM + e*rad*sin(MM/rad) * (1.0 + e*cos(M/rad)) - EE = EE - (EE - e*rad*sin(EE/rad)-MM) / (1.0 - e*cos(EE/rad)) - - xv = cos(EE/rad) - e - yv = sqrt(1.0-e*e) * sin(EE/rad) - v = rad*atan2(yv,xv) - r = sqrt(xv*xv + yv*yv) - lonsun = mod(v + w + 720.0,360.0) -C Ecliptic coordinates of sun (rectangular): - xs = r * cos(lonsun/rad) - ys = r * sin(lonsun/rad) - -C Equatorial coordinates of sun (rectangular): - xe = xs - ye = ys * cos(ecl/rad) - ze = ys * sin(ecl/rad) - -C RA and Dec in degrees: - RA = rad*atan2(ye,xe) - Dec = rad*atan2(ze,sqrt(xe*xe + ye*ye)) - - GMST0 = (Ls + 180.0)/15.0 - LST = mod(GMST0+UT+lon/15.0+48.0,24.0) !LST in hours - HA = 15.0*LST - RA !HA in degrees - xx = cos(HA/rad)*cos(Dec/rad) - yy = sin(HA/rad)*cos(Dec/rad) - zz = sin(Dec/rad) - xhor = xx*sin(lat/rad) - zz*cos(lat/rad) - yhor = yy - zhor = xx*cos(lat/rad) + zz*sin(lat/rad) - Az = mod(rad*atan2(yhor,xhor) + 180.0 + 360.0,360.0) - El = rad*asin(zhor) - day=d-1.5 - - return - end + subroutine sun(y,m,DD,UT,lon,lat,RA,Dec,LST,Az,El,mjd,day) + + implicit none + + integer y !Year + integer m !Month + integer DD !Day + integer mjd !Modified Julian Date + real UT !UTC in hours + real RA,Dec !RA and Dec of sun + +C NB: Double caps here are single caps in the writeup. + +C Orbital elements of the Sun (also N=0, i=0, a=1): + real w !Argument of perihelion + real e !Eccentricity + real MM !Mean anomaly + real Ls !Mean longitude + +C Other standard variables: + real v !True anomaly + real EE !Eccentric anomaly + real ecl !Obliquity of the ecliptic + real d !Ephemeris time argument in days + real r !Distance to sun, AU + real xv,yv !x and y coords in ecliptic + real lonsun !Ecliptic long and lat of sun +C Ecliptic coords of sun (geocentric) + real xs,ys +C Equatorial coords of sun (geocentric) + real xe,ye,ze + real lon,lat + real GMST0,LST,HA + real xx,yy,zz + real xhor,yhor,zhor + real Az,El + + real day + real rad + data rad/57.2957795/ + +C Time in days, with Jan 0, 2000 equal to 0.0: + d=367*y - 7*(y+(m+9)/12)/4 + 275*m/9 + DD - 730530 + UT/24.0 + mjd=d + 51543 + ecl = 23.4393 - 3.563e-7 * d + +C Compute updated orbital elements for Sun: + w = 282.9404 + 4.70935e-5 * d + e = 0.016709 - 1.151e-9 * d + MM = mod(356.0470d0 + 0.9856002585d0 * d + 360000.d0,360.d0) + Ls = mod(w+MM+720.0,360.0) + + EE = MM + e*rad*sin(MM/rad) * (1.0 + e*cos(M/rad)) + EE = EE - (EE - e*rad*sin(EE/rad)-MM) / (1.0 - e*cos(EE/rad)) + + xv = cos(EE/rad) - e + yv = sqrt(1.0-e*e) * sin(EE/rad) + v = rad*atan2(yv,xv) + r = sqrt(xv*xv + yv*yv) + lonsun = mod(v + w + 720.0,360.0) +C Ecliptic coordinates of sun (rectangular): + xs = r * cos(lonsun/rad) + ys = r * sin(lonsun/rad) + +C Equatorial coordinates of sun (rectangular): + xe = xs + ye = ys * cos(ecl/rad) + ze = ys * sin(ecl/rad) + +C RA and Dec in degrees: + RA = rad*atan2(ye,xe) + Dec = rad*atan2(ze,sqrt(xe*xe + ye*ye)) + + GMST0 = (Ls + 180.0)/15.0 + LST = mod(GMST0+UT+lon/15.0+48.0,24.0) !LST in hours + HA = 15.0*LST - RA !HA in degrees + xx = cos(HA/rad)*cos(Dec/rad) + yy = sin(HA/rad)*cos(Dec/rad) + zz = sin(Dec/rad) + xhor = xx*sin(lat/rad) - zz*cos(lat/rad) + yhor = yy + zhor = xx*cos(lat/rad) + zz*sin(lat/rad) + Az = mod(rad*atan2(yhor,xhor) + 180.0 + 360.0,360.0) + El = rad*asin(zhor) + day=d-1.5 + + return + end diff --git a/libm65/symspec.f90 b/libm65/symspec.f90 index 64ec3e9f3..262efab19 100644 --- a/libm65/symspec.f90 +++ b/libm65/symspec.f90 @@ -1,193 +1,193 @@ -subroutine symspec(k,nxpol,ndiskdat,nb,nbslider,idphi,nfsample,fgreen, & - iqadjust,iqapply,gainx,gainy,phasex,phasey,rejectx,rejecty, & - pxdb,pydb,ssz5a,nkhz,ihsym,nzap,slimit,lstrong) - -! k pointer to the most recent new data -! nxpol 0/1 to indicate single- or dual-polarization -! ndiskdat 0/1 to indicate if data from disk -! nb 0/1 status of noise blanker -! idphi Phase correction for Y channel, degrees -! nfsample sample rate (Hz) -! fgreen Frequency of green marker in I/Q calibrate mode (-48.0 to +48.0 kHz) -! iqadjust 0/1 to indicate whether IQ adjustment is active -! iqapply 0/1 to indicate whether to apply I/Q calibration -! pxdb power in x channel (0-60 dB) -! pydb power in y channel (0-60 dB) -! ssz5a polarized spectrum, for waterfall display -! nkhz integer kHz portion of center frequency, e.g., 125 for 144.125 -! ihsym index number of this half-symbol (1-322) -! nzap number of samples zero'ed by noise blanker - - parameter (NSMAX=60*96000) !Total sample intervals per minute - parameter (NFFT=32768) !Length of FFTs - real*8 ts,hsym - real*8 fcenter - common/datcom/dd(4,5760000),ss(4,322,NFFT),savg(4,NFFT),fcenter,nutc,junk(34) - real*4 ssz5a(NFFT),w(NFFT) - complex z,zfac - complex zsumx,zsumy - complex cx(NFFT),cy(NFFT) - complex cx0(0:1023),cx1(0:1023) - complex cy0(0:1023),cy1(0:1023) - logical*1 lstrong(0:1023) - data rms/999.0/,k0/99999999/,nadjx/0/,nadjy/0/ - save - - if(k.gt.5751000) go to 999 - if(k.lt.NFFT) then - ihsym=0 - go to 999 !Wait for enough samples to start - endif - if(k.lt.k0) k1=0 - if(k0.eq.99999999) then - pi=4.0*atan(1.0) - do i=1,NFFT - w(i)=(sin(i*pi/NFFT))**2 - enddo - endif - - nzap=0 - sigmas=1.5*(10.0**(0.01*nbslider)) + 0.7 - peaklimit=sigmas*max(10.0,rms) - faclim=3.0 - px=0. - py=0. - - iqapply0=0 - iqadjust0=0 - if(iqadjust.ne.0) iqapply0=0 - nwindow=2 - nfft2=1024 - kstep=nfft2 - if(nwindow.ne.0) kstep=nfft2/2 - nblks=(k-k1)/kstep - do nblk=1,nblks - j=k1+1 - do i=0,nfft2-1 - cx0(i)=cmplx(dd(1,j+i),dd(2,j+i)) - if(nxpol.ne.0) cy0(i)=cmplx(dd(3,j+i),dd(4,j+i)) - enddo - call timf2(nxpol,nfft2,nwindow,nb,peaklimit,iqadjust0,iqapply0,faclim, & - cx0,cy0,gainx,gainy,phasex,phasey,cx1,cy1,slimit,lstrong, & - px,py,nzap) - - do i=0,kstep-1 - dd(1,j+i)=real(cx1(i)) - dd(2,j+i)=aimag(cx1(i)) - if(nxpol.ne.0) then - dd(3,j+i)=real(cy1(i)) - dd(4,j+i)=aimag(cy1(i)) - endif - enddo - k1=k1+kstep - enddo - - hsym=2048.d0*96000.d0/11025.d0 !Samples per JT65 half-symbol - if(nfsample.eq.95238) hsym=2048.d0*95238.1d0/11025.d0 - npts=NFFT !Samples used in each half-symbol FFT - - if(k.lt.k0) then - ts=1.d0 - hsym - savg=0. - ihsym=0 - endif - k0=k - ihsym=ihsym+1 - ja=ts+hsym !Index of first sample - jb=ja+npts-1 !Last sample - - ts=ts+hsym - i=0 - fac=0.0002 - dphi=idphi/57.2957795 - zfac=fac*cmplx(cos(dphi),sin(dphi)) - do j=ja,jb !Copy data into cx, cy - x1=dd(1,j) - x2=dd(2,j) - if(nxpol.ne.0) then - x3=dd(3,j) - x4=dd(4,j) - else - x3=0. - x4=0. - endif - i=i+1 - cx(i)=fac*cmplx(x1,x2) - cy(i)=zfac*cmplx(x3,x4) !NB: cy includes dphi correction - enddo - - if(nzap/178.lt.50 .and. (ndiskdat.eq.0 .or. ihsym.lt.280)) then - nsum=nblks*kstep - nzap - if(nsum.le.0) nsum=1 - rmsx=sqrt(0.5*px/nsum) - rmsy=sqrt(0.5*py/nsum) - rms=rmsx - if(nxpol.ne.0) rms=sqrt((px+py)/(4.0*nsum)) - endif - pxdb=0. - pydb=0. - if(rmsx.gt.1.0) pxdb=20.0*log10(rmsx) - if(rmsy.gt.1.0) pydb=20.0*log10(rmsy) - if(pxdb.gt.60.0) pxdb=60.0 - if(pydb.gt.60.0) pydb=60.0 - - cx=w*cx !Apply window for 2nd forward FFT - if(nxpol.ne.0) cy=w*cy - - call four2a(cx,NFFT,1,1,1) !Second forward FFT - if(iqadjust.eq.0) nadjx=0 - if(iqadjust.ne.0 .and. nadjx.lt.50) call iqcal(nadjx,cx,NFFT,gainx,phasex, & - zsumx,ipkx,rejectx0) - if(iqapply.ne.0) call iqfix(cx,NFFT,gainx,phasex) - - if(nxpol.ne.0) then - call four2a(cy,NFFT,1,1,1) - if(iqadjust.eq.0) nadjy=0 - if(iqadjust.ne.0 .and. nadjy.lt.50) call iqcal(nadjy,cy,NFFT,gainy,phasey,& - zsumy,ipky,rejecty) - if(iqapply.ne.0) call iqfix(cy,NFFT,gainy,phasey) - endif - - n=ihsym - do i=1,NFFT - sx=real(cx(i))**2 + aimag(cx(i))**2 - ss(1,n,i)=sx ! Pol = 0 - savg(1,i)=savg(1,i) + sx - - if(nxpol.ne.0) then - z=cx(i) + cy(i) - s45=0.5*(real(z)**2 + aimag(z)**2) - ss(2,n,i)=s45 ! Pol = 45 - savg(2,i)=savg(2,i) + s45 - - sy=real(cy(i))**2 + aimag(cy(i))**2 - ss(3,n,i)=sy ! Pol = 90 - savg(3,i)=savg(3,i) + sy - - z=cx(i) - cy(i) - s135=0.5*(real(z)**2 + aimag(z)**2) - ss(4,n,i)=s135 ! Pol = 135 - savg(4,i)=savg(4,i) + s135 - - z=cx(i)*conjg(cy(i)) - q=sx - sy - u=2.0*real(z) - ssz5a(i)=0.707*sqrt(q*q + u*u) !Spectrum of linear polarization -! Leif's formula: -! ssz5a(i)=0.5*(sx+sy) + (real(z)**2 + aimag(z)**2 - sx*sy)/(sx+sy) - else - ssz5a(i)=sx - endif - enddo - if(ihsym.eq.278) then - if(iqadjust.ne.0 .and. ipkx.ne.0 .and. ipky.ne.0) then - rejectx=10.0*log10(savg(1,1+nfft-ipkx)/savg(1,1+ipkx)) - rejecty=10.0*log10(savg(3,1+nfft-ipky)/savg(3,1+ipky)) - endif - endif - - nkhz=nint(1000.d0*(fcenter-int(fcenter))) - if(fcenter.eq.0.d0) nkhz=125 - -999 return -end subroutine symspec +subroutine symspec(k,nxpol,ndiskdat,nb,nbslider,idphi,nfsample,fgreen, & + iqadjust,iqapply,gainx,gainy,phasex,phasey,rejectx,rejecty, & + pxdb,pydb,ssz5a,nkhz,ihsym,nzap,slimit,lstrong) + +! k pointer to the most recent new data +! nxpol 0/1 to indicate single- or dual-polarization +! ndiskdat 0/1 to indicate if data from disk +! nb 0/1 status of noise blanker +! idphi Phase correction for Y channel, degrees +! nfsample sample rate (Hz) +! fgreen Frequency of green marker in I/Q calibrate mode (-48.0 to +48.0 kHz) +! iqadjust 0/1 to indicate whether IQ adjustment is active +! iqapply 0/1 to indicate whether to apply I/Q calibration +! pxdb power in x channel (0-60 dB) +! pydb power in y channel (0-60 dB) +! ssz5a polarized spectrum, for waterfall display +! nkhz integer kHz portion of center frequency, e.g., 125 for 144.125 +! ihsym index number of this half-symbol (1-322) +! nzap number of samples zero'ed by noise blanker + + parameter (NSMAX=60*96000) !Total sample intervals per minute + parameter (NFFT=32768) !Length of FFTs + real*8 ts,hsym + real*8 fcenter + common/datcom/dd(4,5760000),ss(4,322,NFFT),savg(4,NFFT),fcenter,nutc,junk(34) + real*4 ssz5a(NFFT),w(NFFT) + complex z,zfac + complex zsumx,zsumy + complex cx(NFFT),cy(NFFT) + complex cx0(0:1023),cx1(0:1023) + complex cy0(0:1023),cy1(0:1023) + logical*1 lstrong(0:1023) + data rms/999.0/,k0/99999999/,nadjx/0/,nadjy/0/ + save + + if(k.gt.5751000) go to 999 + if(k.lt.NFFT) then + ihsym=0 + go to 999 !Wait for enough samples to start + endif + if(k.lt.k0) k1=0 + if(k0.eq.99999999) then + pi=4.0*atan(1.0) + do i=1,NFFT + w(i)=(sin(i*pi/NFFT))**2 + enddo + endif + + nzap=0 + sigmas=1.5*(10.0**(0.01*nbslider)) + 0.7 + peaklimit=sigmas*max(10.0,rms) + faclim=3.0 + px=0. + py=0. + + iqapply0=0 + iqadjust0=0 + if(iqadjust.ne.0) iqapply0=0 + nwindow=2 + nfft2=1024 + kstep=nfft2 + if(nwindow.ne.0) kstep=nfft2/2 + nblks=(k-k1)/kstep + do nblk=1,nblks + j=k1+1 + do i=0,nfft2-1 + cx0(i)=cmplx(dd(1,j+i),dd(2,j+i)) + if(nxpol.ne.0) cy0(i)=cmplx(dd(3,j+i),dd(4,j+i)) + enddo + call timf2(nxpol,nfft2,nwindow,nb,peaklimit,iqadjust0,iqapply0,faclim, & + cx0,cy0,gainx,gainy,phasex,phasey,cx1,cy1,slimit,lstrong, & + px,py,nzap) + + do i=0,kstep-1 + dd(1,j+i)=real(cx1(i)) + dd(2,j+i)=aimag(cx1(i)) + if(nxpol.ne.0) then + dd(3,j+i)=real(cy1(i)) + dd(4,j+i)=aimag(cy1(i)) + endif + enddo + k1=k1+kstep + enddo + + hsym=2048.d0*96000.d0/11025.d0 !Samples per JT65 half-symbol + if(nfsample.eq.95238) hsym=2048.d0*95238.1d0/11025.d0 + npts=NFFT !Samples used in each half-symbol FFT + + if(k.lt.k0) then + ts=1.d0 - hsym + savg=0. + ihsym=0 + endif + k0=k + ihsym=ihsym+1 + ja=ts+hsym !Index of first sample + jb=ja+npts-1 !Last sample + + ts=ts+hsym + i=0 + fac=0.0002 + dphi=idphi/57.2957795 + zfac=fac*cmplx(cos(dphi),sin(dphi)) + do j=ja,jb !Copy data into cx, cy + x1=dd(1,j) + x2=dd(2,j) + if(nxpol.ne.0) then + x3=dd(3,j) + x4=dd(4,j) + else + x3=0. + x4=0. + endif + i=i+1 + cx(i)=fac*cmplx(x1,x2) + cy(i)=zfac*cmplx(x3,x4) !NB: cy includes dphi correction + enddo + + if(nzap/178.lt.50 .and. (ndiskdat.eq.0 .or. ihsym.lt.280)) then + nsum=nblks*kstep - nzap + if(nsum.le.0) nsum=1 + rmsx=sqrt(0.5*px/nsum) + rmsy=sqrt(0.5*py/nsum) + rms=rmsx + if(nxpol.ne.0) rms=sqrt((px+py)/(4.0*nsum)) + endif + pxdb=0. + pydb=0. + if(rmsx.gt.1.0) pxdb=20.0*log10(rmsx) + if(rmsy.gt.1.0) pydb=20.0*log10(rmsy) + if(pxdb.gt.60.0) pxdb=60.0 + if(pydb.gt.60.0) pydb=60.0 + + cx=w*cx !Apply window for 2nd forward FFT + if(nxpol.ne.0) cy=w*cy + + call four2a(cx,NFFT,1,1,1) !Second forward FFT + if(iqadjust.eq.0) nadjx=0 + if(iqadjust.ne.0 .and. nadjx.lt.50) call iqcal(nadjx,cx,NFFT,gainx,phasex, & + zsumx,ipkx,rejectx0) + if(iqapply.ne.0) call iqfix(cx,NFFT,gainx,phasex) + + if(nxpol.ne.0) then + call four2a(cy,NFFT,1,1,1) + if(iqadjust.eq.0) nadjy=0 + if(iqadjust.ne.0 .and. nadjy.lt.50) call iqcal(nadjy,cy,NFFT,gainy,phasey,& + zsumy,ipky,rejecty) + if(iqapply.ne.0) call iqfix(cy,NFFT,gainy,phasey) + endif + + n=ihsym + do i=1,NFFT + sx=real(cx(i))**2 + aimag(cx(i))**2 + ss(1,n,i)=sx ! Pol = 0 + savg(1,i)=savg(1,i) + sx + + if(nxpol.ne.0) then + z=cx(i) + cy(i) + s45=0.5*(real(z)**2 + aimag(z)**2) + ss(2,n,i)=s45 ! Pol = 45 + savg(2,i)=savg(2,i) + s45 + + sy=real(cy(i))**2 + aimag(cy(i))**2 + ss(3,n,i)=sy ! Pol = 90 + savg(3,i)=savg(3,i) + sy + + z=cx(i) - cy(i) + s135=0.5*(real(z)**2 + aimag(z)**2) + ss(4,n,i)=s135 ! Pol = 135 + savg(4,i)=savg(4,i) + s135 + + z=cx(i)*conjg(cy(i)) + q=sx - sy + u=2.0*real(z) + ssz5a(i)=0.707*sqrt(q*q + u*u) !Spectrum of linear polarization +! Leif's formula: +! ssz5a(i)=0.5*(sx+sy) + (real(z)**2 + aimag(z)**2 - sx*sy)/(sx+sy) + else + ssz5a(i)=sx + endif + enddo + if(ihsym.eq.278) then + if(iqadjust.ne.0 .and. ipkx.ne.0 .and. ipky.ne.0) then + rejectx=10.0*log10(savg(1,1+nfft-ipkx)/savg(1,1+ipkx)) + rejecty=10.0*log10(savg(3,1+nfft-ipky)/savg(3,1+ipky)) + endif + endif + + nkhz=nint(1000.d0*(fcenter-int(fcenter))) + if(fcenter.eq.0.d0) nkhz=125 + +999 return +end subroutine symspec diff --git a/libm65/tastro.f90 b/libm65/tastro.f90 index d9ede4a67..fac5c8003 100644 --- a/libm65/tastro.f90 +++ b/libm65/tastro.f90 @@ -1,35 +1,35 @@ -program tastro - - implicit real*8 (a-h,o-z) - - character grid*6 - character*9 cauxra,cauxdec - - character*12 clock(3) - integer nt(8) - equivalence (nt(1),nyear) - - grid='FN20qi' - nfreq=144 - cauxra='00:00:00' - -10 call date_and_time(clock(1),clock(2),clock(3),nt) - ih=ihour-ntz/60 - if(ih.le.0) then - ih=ih+24 - nday=nday+1 - endif - uth8=ih + imin/60.d0 + isec/3600.d0 + ims/3600000.d0 - call astro0(nyear,month,nday,uth8,nfreq,grid,cauxra,cauxdec, & - AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, & - dbMoon8,RAMoon8,DecMoon8,HA8,Dgrd8,sd8,poloffset8,xnr8,dfdt,dfdt0, & - RaAux8,DecAux8,AzAux8,ElAux8,width1,width2,w501,w502,xlst8) - - write(*,1010) nyear,month,nday,ih,imin,isec,AzMoon8,ElMoon8, & - AzSun8,ElSun8,ndop,dgrd8,ntsky -1010 format(i4,i3,i3,i4.2,':',i2.2,':',i2.2,4f8.1,i6,f6.1,i6) - - call system('sleep 1') - go to 10 - -end program tastro +program tastro + + implicit real*8 (a-h,o-z) + + character grid*6 + character*9 cauxra,cauxdec + + character*12 clock(3) + integer nt(8) + equivalence (nt(1),nyear) + + grid='FN20qi' + nfreq=144 + cauxra='00:00:00' + +10 call date_and_time(clock(1),clock(2),clock(3),nt) + ih=ihour-ntz/60 + if(ih.le.0) then + ih=ih+24 + nday=nday+1 + endif + uth8=ih + imin/60.d0 + isec/3600.d0 + ims/3600000.d0 + call astro0(nyear,month,nday,uth8,nfreq,grid,cauxra,cauxdec, & + AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, & + dbMoon8,RAMoon8,DecMoon8,HA8,Dgrd8,sd8,poloffset8,xnr8,dfdt,dfdt0, & + RaAux8,DecAux8,AzAux8,ElAux8,width1,width2,w501,w502,xlst8) + + write(*,1010) nyear,month,nday,ih,imin,isec,AzMoon8,ElMoon8, & + AzSun8,ElSun8,ndop,dgrd8,ntsky +1010 format(i4,i3,i3,i4.2,':',i2.2,':',i2.2,4f8.1,i6,f6.1,i6) + + call system('sleep 1') + go to 10 + +end program tastro diff --git a/libm65/timf2.f90 b/libm65/timf2.f90 index d2bc704fb..29adaf4c1 100644 --- a/libm65/timf2.f90 +++ b/libm65/timf2.f90 @@ -1,220 +1,220 @@ -subroutine timf2(nxpol,nfft,nwindow,nb,peaklimit,iqadjust,iqapply,faclim, & - cx0,cy0,gainx,gainy,phasex,phasey,cx1,cy1,slimit,lstrong,px,py,nzap) - -! Sequential processing of time-domain I/Q data, using Linrad-like -! "first FFT" and "first backward FFT". - -! cx0,cy0 - complex input data -! nfft - length of FFTs -! nwindow - 0 for no window, 2 for sin^2 window -! iqapply - 0/1 determines if I/Q phase and amplitude corrections applied -! gainx,y - gain error in Q channel, relative to I -! phasex,y - phase error -! cx1,cy1 - output data - -! Non-windowed processing means no overlap, so kstep=nfft. -! Sin^2 window has 50% overlap, kstep=nfft/2. - -! Frequencies with strong signals are identified and separated. The back -! transforms are done separately for weak and strong signals, so that -! noise blanking can be applied to the weak-signal portion. Strong and -! weak are finally re-combined in the time domain. - - parameter (MAXFFT=1024,MAXNH=MAXFFT/2) - parameter (MAXSIGS=100) - complex cx0(0:nfft-1),cx1(0:nfft-1) - complex cy0(0:nfft-1),cy1(0:nfft-1) - complex cx(0:MAXFFT-1),cxt(0:MAXFFT-1) - complex cy(0:MAXFFT-1),cyt(0:MAXFFT-1) - complex cxs(0:MAXFFT-1),covxs(0:MAXNH-1) !Strong X signals - complex cys(0:MAXFFT-1),covys(0:MAXNH-1) !Strong Y signals - complex cxw(0:MAXFFT-1),covxw(0:MAXNH-1) !Weak X signals - complex cyw(0:MAXFFT-1),covyw(0:MAXNH-1) !Weak Y signals - real*4 w(0:MAXFFT-1) - real*4 s(0:MAXFFT-1),stmp(0:MAXFFT-1) - logical*1 lstrong(0:MAXFFT-1),lprev - integer ia(MAXSIGS),ib(MAXSIGS) - complex h,u,v - logical first - data first/.true./ - save w,covxs,covxw,covys,covyw,s,ntc,ntot,nh,kstep,fac,first - - if(first) then - pi=4.0*atan(1.0) - do i=0,nfft-1 - w(i)=(sin(i*pi/nfft))**2 - enddo - covxs=0. - covxw=0. - covys=0. - covyw=0. - s=0. - ntc=0 - ntot=0 - nh=nfft/2 - kstep=nfft - if(nwindow.eq.2) kstep=nh - fac=1.0/nfft - slimit=1.e30 - first=.false. - endif - - cx(0:nfft-1)=cx0 - if(nwindow.eq.2) cx(0:nfft-1)=w(0:nfft-1)*cx(0:nfft-1) - call four2a(cx,nfft,1,1,1) !First forward FFT - - if(nxpol.ne.0) then - cy(0:nfft-1)=cy0 - if(nwindow.eq.2) cy(0:nfft-1)=w(0:nfft-1)*cy(0:nfft-1) - call four2a(cy,nfft,1,1,1) !First forward FFT - endif - - if(iqapply.ne.0) then !Apply I/Q corrections - h=gainx*cmplx(cos(phasex),sin(phasex)) - v=0. - do i=0,nfft-1 - u=cx(i) - if(i.gt.0) v=cx(nfft-i) - x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & - (real(u) - real(v))*real(h) - y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & - (real(u) - real(v))*aimag(h) - cxt(i)=0.5*cmplx(x,y) - enddo - else - cxt(0:nfft-1)=cx(0:nfft-1) - endif - - if(nxpol.ne.0) then - if(iqapply.ne.0) then !Apply I/Q corrections - h=gainy*cmplx(cos(phasey),sin(phasey)) - v=0. - do i=0,nfft-1 - u=cy(i) - if(i.gt.0) v=cy(nfft-i) - x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & - (real(u) - real(v))*real(h) - y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & - (real(u) - real(v))*aimag(h) - cyt(i)=0.5*cmplx(x,y) - enddo - else - cyt(0:nfft-1)=cy(0:nfft-1) - endif - endif - -! Identify frequencies with strong signals, copy frequency-domain -! data into array cs (strong) or cw (weak). - - ntot=ntot+1 - if(mod(ntot,128).eq.5) then - call pctile(s,stmp,1024,50,xmedian) - slimit=faclim*xmedian - endif - - if(ntc.lt.96000/nfft) ntc=ntc+1 - uu=1.0/ntc - smax=0. - do i=0,nfft-1 - p=real(cxt(i))**2 + aimag(cxt(i))**2 - if(nxpol.ne.0) p=p + real(cyt(i))**2 + aimag(cyt(i))**2 - s(i)=(1.0-uu)*s(i) + uu*p - lstrong(i)=(s(i).gt.slimit) - if(s(i).gt.smax) smax=s(i) - enddo - - nsigs=0 - lprev=.false. - iwid=1 - ib=-99 - do i=0,nfft-1 - if(lstrong(i) .and. (.not.lprev)) then - if(nsigs.lt.MAXSIGS) nsigs=nsigs+1 - ia(nsigs)=i-iwid - if(ia(nsigs).lt.0) ia(nsigs)=0 - endif - if(.not.lstrong(i) .and. lprev) then - ib(nsigs)=i-1+iwid - if(ib(nsigs).gt.nfft-1) ib(nsigs)=nfft-1 - endif - lprev=lstrong(i) - enddo - - if(nsigs.gt.0) then - do i=1,nsigs - ja=ia(i) - jb=ib(i) - if(ja.lt.0 .or. ja.gt.nfft-1 .or. jb.lt.0 .or. jb.gt.nfft-1) then - cycle - endif - if(jb.eq.-99) jb=ja + min(2*iwid,nfft-1) - lstrong(ja:jb)=.true. - enddo - endif - - do i=0,nfft-1 - if(lstrong(i)) then - cxs(i)=fac*cxt(i) - cxw(i)=0. - if(nxpol.ne.0) then - cys(i)=fac*cyt(i) - cyw(i)=0. - endif - else - cxw(i)=fac*cxt(i) - cxs(i)=0. - if(nxpol.ne.0) then - cyw(i)=fac*cyt(i) - cys(i)=0. - endif - endif - enddo - - call four2a(cxw,nfft,1,-1,1) !Transform weak and strong X - call four2a(cxs,nfft,1,-1,1) !back to time domain, separately - - if(nxpol.ne.0) then - call four2a(cyw,nfft,1,-1,1) !Transform weak and strong Y - call four2a(cys,nfft,1,-1,1) !back to time domain, separately - endif - - if(nwindow.eq.2) then - cxw(0:nh-1)=cxw(0:nh-1)+covxw(0:nh-1) !Add previous segment's 2nd half - covxw(0:nh-1)=cxw(nh:nfft-1) !Save 2nd half - cxs(0:nh-1)=cxs(0:nh-1)+covxs(0:nh-1) !Ditto for strong signals - covxs(0:nh-1)=cxs(nh:nfft-1) - - if(nxpol.ne.0) then - cyw(0:nh-1)=cyw(0:nh-1)+covyw(0:nh-1) !Add previous segment's 2nd half - covyw(0:nh-1)=cyw(nh:nfft-1) !Save 2nd half - cys(0:nh-1)=cys(0:nh-1)+covys(0:nh-1) !Ditto for strong signals - covys(0:nh-1)=cys(nh:nfft-1) - endif - endif - -! Apply noise blanking to weak data - if(nb.ne.0) then - do i=0,kstep-1 - peak=abs(cxw(i)) - if(nxpol.ne.0) peak=max(peak,abs(cyw(i))) - if(peak.gt.peaklimit) then - cxw(i)=0. - if(nxpol.ne.0) cyw(i)=0. - nzap=nzap+1 - endif - enddo - endif - -! Compute power levels from weak data only - do i=0,kstep-1 - px=px + real(cxw(i))**2 + aimag(cxw(i))**2 - if(nxpol.ne.0) py=py + real(cyw(i))**2 + aimag(cyw(i))**2 - enddo - - cx1(0:kstep-1)=cxw(0:kstep-1) + cxs(0:kstep-1) !Recombine weak + strong - if(nxpol.ne.0) then - cy1(0:kstep-1)=cyw(0:kstep-1) + cys(0:kstep-1) !Weak + strong - endif - - return -end subroutine timf2 +subroutine timf2(nxpol,nfft,nwindow,nb,peaklimit,iqadjust,iqapply,faclim, & + cx0,cy0,gainx,gainy,phasex,phasey,cx1,cy1,slimit,lstrong,px,py,nzap) + +! Sequential processing of time-domain I/Q data, using Linrad-like +! "first FFT" and "first backward FFT". + +! cx0,cy0 - complex input data +! nfft - length of FFTs +! nwindow - 0 for no window, 2 for sin^2 window +! iqapply - 0/1 determines if I/Q phase and amplitude corrections applied +! gainx,y - gain error in Q channel, relative to I +! phasex,y - phase error +! cx1,cy1 - output data + +! Non-windowed processing means no overlap, so kstep=nfft. +! Sin^2 window has 50% overlap, kstep=nfft/2. + +! Frequencies with strong signals are identified and separated. The back +! transforms are done separately for weak and strong signals, so that +! noise blanking can be applied to the weak-signal portion. Strong and +! weak are finally re-combined in the time domain. + + parameter (MAXFFT=1024,MAXNH=MAXFFT/2) + parameter (MAXSIGS=100) + complex cx0(0:nfft-1),cx1(0:nfft-1) + complex cy0(0:nfft-1),cy1(0:nfft-1) + complex cx(0:MAXFFT-1),cxt(0:MAXFFT-1) + complex cy(0:MAXFFT-1),cyt(0:MAXFFT-1) + complex cxs(0:MAXFFT-1),covxs(0:MAXNH-1) !Strong X signals + complex cys(0:MAXFFT-1),covys(0:MAXNH-1) !Strong Y signals + complex cxw(0:MAXFFT-1),covxw(0:MAXNH-1) !Weak X signals + complex cyw(0:MAXFFT-1),covyw(0:MAXNH-1) !Weak Y signals + real*4 w(0:MAXFFT-1) + real*4 s(0:MAXFFT-1),stmp(0:MAXFFT-1) + logical*1 lstrong(0:MAXFFT-1),lprev + integer ia(MAXSIGS),ib(MAXSIGS) + complex h,u,v + logical first + data first/.true./ + save w,covxs,covxw,covys,covyw,s,ntc,ntot,nh,kstep,fac,first + + if(first) then + pi=4.0*atan(1.0) + do i=0,nfft-1 + w(i)=(sin(i*pi/nfft))**2 + enddo + covxs=0. + covxw=0. + covys=0. + covyw=0. + s=0. + ntc=0 + ntot=0 + nh=nfft/2 + kstep=nfft + if(nwindow.eq.2) kstep=nh + fac=1.0/nfft + slimit=1.e30 + first=.false. + endif + + cx(0:nfft-1)=cx0 + if(nwindow.eq.2) cx(0:nfft-1)=w(0:nfft-1)*cx(0:nfft-1) + call four2a(cx,nfft,1,1,1) !First forward FFT + + if(nxpol.ne.0) then + cy(0:nfft-1)=cy0 + if(nwindow.eq.2) cy(0:nfft-1)=w(0:nfft-1)*cy(0:nfft-1) + call four2a(cy,nfft,1,1,1) !First forward FFT + endif + + if(iqapply.ne.0) then !Apply I/Q corrections + h=gainx*cmplx(cos(phasex),sin(phasex)) + v=0. + do i=0,nfft-1 + u=cx(i) + if(i.gt.0) v=cx(nfft-i) + x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & + (real(u) - real(v))*real(h) + y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & + (real(u) - real(v))*aimag(h) + cxt(i)=0.5*cmplx(x,y) + enddo + else + cxt(0:nfft-1)=cx(0:nfft-1) + endif + + if(nxpol.ne.0) then + if(iqapply.ne.0) then !Apply I/Q corrections + h=gainy*cmplx(cos(phasey),sin(phasey)) + v=0. + do i=0,nfft-1 + u=cy(i) + if(i.gt.0) v=cy(nfft-i) + x=real(u) + real(v) - (aimag(u) + aimag(v))*aimag(h) + & + (real(u) - real(v))*real(h) + y=aimag(u) - aimag(v) + (aimag(u) + aimag(v))*real(h) + & + (real(u) - real(v))*aimag(h) + cyt(i)=0.5*cmplx(x,y) + enddo + else + cyt(0:nfft-1)=cy(0:nfft-1) + endif + endif + +! Identify frequencies with strong signals, copy frequency-domain +! data into array cs (strong) or cw (weak). + + ntot=ntot+1 + if(mod(ntot,128).eq.5) then + call pctile(s,stmp,1024,50,xmedian) + slimit=faclim*xmedian + endif + + if(ntc.lt.96000/nfft) ntc=ntc+1 + uu=1.0/ntc + smax=0. + do i=0,nfft-1 + p=real(cxt(i))**2 + aimag(cxt(i))**2 + if(nxpol.ne.0) p=p + real(cyt(i))**2 + aimag(cyt(i))**2 + s(i)=(1.0-uu)*s(i) + uu*p + lstrong(i)=(s(i).gt.slimit) + if(s(i).gt.smax) smax=s(i) + enddo + + nsigs=0 + lprev=.false. + iwid=1 + ib=-99 + do i=0,nfft-1 + if(lstrong(i) .and. (.not.lprev)) then + if(nsigs.lt.MAXSIGS) nsigs=nsigs+1 + ia(nsigs)=i-iwid + if(ia(nsigs).lt.0) ia(nsigs)=0 + endif + if(.not.lstrong(i) .and. lprev) then + ib(nsigs)=i-1+iwid + if(ib(nsigs).gt.nfft-1) ib(nsigs)=nfft-1 + endif + lprev=lstrong(i) + enddo + + if(nsigs.gt.0) then + do i=1,nsigs + ja=ia(i) + jb=ib(i) + if(ja.lt.0 .or. ja.gt.nfft-1 .or. jb.lt.0 .or. jb.gt.nfft-1) then + cycle + endif + if(jb.eq.-99) jb=ja + min(2*iwid,nfft-1) + lstrong(ja:jb)=.true. + enddo + endif + + do i=0,nfft-1 + if(lstrong(i)) then + cxs(i)=fac*cxt(i) + cxw(i)=0. + if(nxpol.ne.0) then + cys(i)=fac*cyt(i) + cyw(i)=0. + endif + else + cxw(i)=fac*cxt(i) + cxs(i)=0. + if(nxpol.ne.0) then + cyw(i)=fac*cyt(i) + cys(i)=0. + endif + endif + enddo + + call four2a(cxw,nfft,1,-1,1) !Transform weak and strong X + call four2a(cxs,nfft,1,-1,1) !back to time domain, separately + + if(nxpol.ne.0) then + call four2a(cyw,nfft,1,-1,1) !Transform weak and strong Y + call four2a(cys,nfft,1,-1,1) !back to time domain, separately + endif + + if(nwindow.eq.2) then + cxw(0:nh-1)=cxw(0:nh-1)+covxw(0:nh-1) !Add previous segment's 2nd half + covxw(0:nh-1)=cxw(nh:nfft-1) !Save 2nd half + cxs(0:nh-1)=cxs(0:nh-1)+covxs(0:nh-1) !Ditto for strong signals + covxs(0:nh-1)=cxs(nh:nfft-1) + + if(nxpol.ne.0) then + cyw(0:nh-1)=cyw(0:nh-1)+covyw(0:nh-1) !Add previous segment's 2nd half + covyw(0:nh-1)=cyw(nh:nfft-1) !Save 2nd half + cys(0:nh-1)=cys(0:nh-1)+covys(0:nh-1) !Ditto for strong signals + covys(0:nh-1)=cys(nh:nfft-1) + endif + endif + +! Apply noise blanking to weak data + if(nb.ne.0) then + do i=0,kstep-1 + peak=abs(cxw(i)) + if(nxpol.ne.0) peak=max(peak,abs(cyw(i))) + if(peak.gt.peaklimit) then + cxw(i)=0. + if(nxpol.ne.0) cyw(i)=0. + nzap=nzap+1 + endif + enddo + endif + +! Compute power levels from weak data only + do i=0,kstep-1 + px=px + real(cxw(i))**2 + aimag(cxw(i))**2 + if(nxpol.ne.0) py=py + real(cyw(i))**2 + aimag(cyw(i))**2 + enddo + + cx1(0:kstep-1)=cxw(0:kstep-1) + cxs(0:kstep-1) !Recombine weak + strong + if(nxpol.ne.0) then + cy1(0:kstep-1)=cyw(0:kstep-1) + cys(0:kstep-1) !Weak + strong + endif + + return +end subroutine timf2 diff --git a/libm65/tm2.f90 b/libm65/tm2.f90 index 9d7777750..bd8361187 100644 --- a/libm65/tm2.f90 +++ b/libm65/tm2.f90 @@ -1,14 +1,14 @@ -subroutine tm2(day,xlat4,xlon4,xl4,b4) - - implicit real*8 (a-h,o-z) - parameter (RADS=0.0174532925199433d0) - - real*4 day4,xlat4,xlon4,xl4,b4 - - glat=xlat4*RADS - glong=xlon4*RADS - call tmoonsub(day,glat,glong,el,rv,xl,b,pax) - xl4=xl - b4=b - -end subroutine tm2 +subroutine tm2(day,xlat4,xlon4,xl4,b4) + + implicit real*8 (a-h,o-z) + parameter (RADS=0.0174532925199433d0) + + real*4 day4,xlat4,xlon4,xl4,b4 + + glat=xlat4*RADS + glong=xlon4*RADS + call tmoonsub(day,glat,glong,el,rv,xl,b,pax) + xl4=xl + b4=b + +end subroutine tm2 diff --git a/libm65/tmoonsub.c b/libm65/tmoonsub.c index 3b171b540..29ac28b49 100644 --- a/libm65/tmoonsub.c +++ b/libm65/tmoonsub.c @@ -1,514 +1,514 @@ -#include -#include -#include - -#define RADS 0.0174532925199433 -#define DEGS 57.2957795130823 -#define TPI 6.28318530717959 -#define PI 3.1415927 - -/* ratio of earth radius to astronomical unit */ -#define ER_OVER_AU 0.0000426352325194252 - -/* all prototypes here */ - -double getcoord(int coord); -void getargs(int argc, char *argv[], int *y, int *m, double *tz, double *glong, double *glat); -double range(double y); -double rangerad(double y); -double days(int y, int m, int dn, double hour); -double days_(int *y, int *m, int *dn, double *hour); -void moonpos(double, double *, double *, double *); -void sunpos(double , double *, double *, double *); -double moontransit(int y, int m, int d, double timezone, double glat, double glong, int *nt); -double atan22(double y, double x); -double epsilon(double d); -void equatorial(double d, double *lon, double *lat, double *r); -void ecliptic(double d, double *lon, double *lat, double *r); -double gst(double d); -void topo(double lst, double glat, double *alp, double *dec, double *r); -double alt(double glat, double ha, double dec); -void libration(double day, double lambda, double beta, double alpha, double *l, double *b, double *p); -void illumination(double day, double lra, double ldec, double dr, double sra, double sdec, double *pabl, double *ill); -int daysinmonth(int y, int m); -int isleap(int y); -void tmoonsub_(double *day, double *glat, double *glong, double *moonalt, - double *mrv, double *l, double *b, double *paxis); - -static const char -*usage = " Usage: tmoon date[yyyymm] timz[+/-h.hh] long[+/-dddmm] lat[+/-ddmm]\n" - "example: tmoon 200009 0 -00155 5230\n"; - -/* - getargs() gets the arguments from the command line, does some basic error - checking, and converts arguments into numerical form. Arguments are passed - back in pointers. Error messages print to stderr so re-direction of output - to file won't leave users blind. Error checking prints list of all errors - in a command line before quitting. -*/ -void getargs(int argc, char *argv[], int *y, int *m, double *tz, - double *glong, double *glat) { - - int date, latitude, longitude; - int mflag = 0, yflag = 0, longflag = 0, latflag = 0, tzflag = 0; - int longminflag = 0, latminflag = 0, dflag = 0; - - /* if not right number of arguments, then print example command line */ - - if (argc !=5) { - fprintf(stderr, usage); - exit(EXIT_FAILURE); - } - - date = atoi(argv[1]); - *y = date / 100; - *m = date - *y * 100; - *tz = (double) atof(argv[2]); - longitude = atoi(argv[3]); - latitude = atoi(argv[4]); - *glong = RADS * getcoord(longitude); - *glat = RADS * getcoord(latitude); - - /* set a flag for each error found */ - - if (*m > 12 || *m < 1) mflag = 1; - if (*y > 2500) yflag = 1; - if (date < 150001) dflag = 1; - if (fabs((float) *glong) > 180 * RADS) longflag = 1; - if (abs(longitude) % 100 > 59) longminflag = 1; - if (fabs((float) *glat) > 90 * RADS) latflag = 1; - if (abs(latitude) % 100 > 59) latminflag = 1; - if (fabs((float) *tz) > 12) tzflag = 1; - - /* print all the errors found */ - - if (dflag == 1) { - fprintf(stderr, "date: dates must be in form yyyymm, gregorian, and later than 1500 AD\n"); - } - if (yflag == 1) { - fprintf(stderr, "date: too far in future - accurate from 1500 to 2500\n"); - } - if (mflag == 1) { - fprintf(stderr, "date: month must be in range 0 to 12, eg - August 2000 is entered as 200008\n"); - } - if (tzflag == 1) { - fprintf(stderr, "timz: must be in range +/- 12 hours, eg -6 for Chicago\n"); - } - if (longflag == 1) { - fprintf(stderr, "long: must be in range +/- 180 degrees\n"); - } - if (longminflag == 1) { - fprintf(stderr, "long: last two digits are arcmin - max 59\n"); - } - if (latflag == 1) { - fprintf(stderr, " lat: must be in range +/- 90 degrees\n"); - } - if (latminflag == 1) { - fprintf(stderr, " lat: last two digits are arcmin - max 59\n"); - } - - /* quits if one or more flags set */ - - if (dflag + mflag + yflag + longflag + latflag + tzflag + longminflag + latminflag > 0) { - exit(EXIT_FAILURE); - } - -} - -/* - returns coordinates in decimal degrees given the - coord as a ddmm value stored in an integer. -*/ -double getcoord(int coord) { - int west = 1; - double glg, deg; - if (coord < 0) west = -1; - glg = fabs((double) coord/100); - deg = floor(glg); - glg = west* (deg + (glg - deg)*100 / 60); - return(glg); -} - -/* - days() takes the year, month, day in the month and decimal hours - in the day and returns the number of days since J2000.0. - Assumes Gregorian calendar. -*/ -double days(int y, int m, int d, double h) { - int a, b; - double day; - - /* - The lines below work from 1900 march to feb 2100 - a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d; - day = (double)a - 730531.5 + hour / 24; - */ - - /* These lines work for any Gregorian date since 0 AD */ - if (m ==1 || m==2) { - m +=12; - y -= 1; - } - a = y / 100; - b = 2 - a + a/4; - day = floor(365.25*(y + 4716)) + floor(30.6001*(m + 1)) - + d + b - 1524.5 - 2451545 + h/24; - return(day); -} -double days_(int *y0, int *m0, int *d0, double *h0) -{ - return days(*y0,*m0,*d0,*h0); -} - -/* -Returns 1 if y a leap year, and 0 otherwise, according -to the Gregorian calendar -*/ -int isleap(int y) { - int a = 0; - if(y % 4 == 0) a = 1; - if(y % 100 == 0) a = 0; - if(y % 400 == 0) a = 1; - return(a); -} - -/* -Given the year and the month, function returns the -number of days in the month. Valid for Gregorian -calendar. -*/ -int daysinmonth(int y, int m) { - int b = 31; - if(m == 2) { - if(isleap(y) == 1) b= 29; - else b = 28; - } - if(m == 4 || m == 6 || m == 9 || m == 11) b = 30; - return(b); -} - -/* -moonpos() takes days from J2000.0 and returns ecliptic coordinates -of moon in the pointers. Note call by reference. -This function is within a couple of arcminutes most of the time, -and is truncated from the Meeus Ch45 series, themselves truncations of -ELP-2000. Returns moon distance in earth radii. -Terms have been written out explicitly rather than using the -table based method as only a small number of terms is -retained. -*/ -void moonpos(double d, double *lambda, double *beta, double *rvec) { - double dl, dB, dR, L, D, M, M1, F, e, lm, bm, rm, t; - - t = d / 36525; - - L = range(218.3164591 + 481267.88134236 * t) * RADS; - D = range(297.8502042 + 445267.1115168 * t) * RADS; - M = range(357.5291092 + 35999.0502909 * t) * RADS; - M1 = range(134.9634114 + 477198.8676313 * t - .008997 * t * t) * RADS; - F = range(93.27209929999999 + 483202.0175273 * t - .0034029*t*t)*RADS; - e = 1 - .002516 * t; - - dl = 6288774 * sin(M1); - dl += 1274027 * sin(2 * D - M1); - dl += 658314 * sin(2 * D); - dl += 213618 * sin(2 * M1); - dl -= e * 185116 * sin(M); - dl -= 114332 * sin(2 * F) ; - dl += 58793 * sin(2 * D - 2 * M1); - dl += e * 57066 * sin(2 * D - M - M1) ; - dl += 53322 * sin(2 * D + M1); - dl += e * 45758 * sin(2 * D - M); - dl -= e * 40923 * sin(M - M1); - dl -= 34720 * sin(D) ; - dl -= e * 30383 * sin(M + M1) ; - dl += 15327 * sin(2 * D - 2 * F) ; - dl -= 12528 * sin(M1 + 2 * F); - dl += 10980 * sin(M1 - 2 * F); - lm = rangerad(L + dl / 1000000 * RADS); - - dB = 5128122 * sin(F); - dB += 280602 * sin(M1 + F); - dB += 277693 * sin(M1 - F); - dB += 173237 * sin(2 * D - F); - dB += 55413 * sin(2 * D - M1 + F); - dB += 46271 * sin(2 * D - M1 - F); - dB += 32573 * sin(2 * D + F); - dB += 17198 * sin(2 * M1 + F); - dB += 9266 * sin(2 * D + M1 - F); - dB += 8822 * sin(2 * M1 - F); - dB += e * 8216 * sin(2 * D - M - F); - dB += 4324 * sin(2 * D - 2 * M1 - F); - bm = dB / 1000000 * RADS; - - dR = -20905355 * cos(M1); - dR -= 3699111 * cos(2 * D - M1); - dR -= 2955968 * cos(2 * D); - dR -= 569925 * cos(2 * M1); - dR += e * 48888 * cos(M); - dR -= 3149 * cos(2 * F); - dR += 246158 * cos(2 * D - 2 * M1); - dR -= e * 152138 * cos(2 * D - M - M1) ; - dR -= 170733 * cos(2 * D + M1); - dR -= e * 204586 * cos(2 * D - M); - dR -= e * 129620 * cos(M - M1); - dR += 108743 * cos(D); - dR += e * 104755 * cos(M + M1); - dR += 79661 * cos(M1 - 2 * F); - rm = 385000.56 + dR / 1000; - - *lambda = lm; - *beta = bm; - /* distance to Moon must be in Earth radii */ - *rvec = rm / 6378.14; -} - -/* -topomoon() takes the local siderial time, the geographical -latitude of the observer, and pointers to the geocentric -equatorial coordinates. The function overwrites the geocentric -coordinates with topocentric coordinates on a simple spherical -earth model (no polar flattening). Expects Moon-Earth distance in -Earth radii. Formulas scavenged from Astronomical Almanac 'low -precision formulae for Moon position' page D46. -*/ - -void topo(double lst, double glat, double *alp, double *dec, double *r) { - double x, y, z, r1; - x = *r * cos(*dec) * cos(*alp) - cos(glat) * cos(lst); - y = *r * cos(*dec) * sin(*alp) - cos(glat) * sin(lst); - z = *r * sin(*dec) - sin(glat); - r1 = sqrt(x*x + y*y + z*z); - *alp = atan22(y, x); - *dec = asin(z / r1); - *r = r1; -} - -/* -moontransit() takes date, the time zone and geographic longitude -of observer and returns the time (decimal hours) of lunar transit -on that day if there is one, and sets the notransit flag if there -isn't. See Explanatory Supplement to Astronomical Almanac -section 9.32 and 9.31 for the method. -*/ - -double moontransit(int y, int m, int d, double tz, double glat, double glong, int *notransit) { - double hm, ht, ht1, lon, lat, rv, dnew, lst; - int itcount; - - ht1 = 180 * RADS; - ht = 0; - itcount = 0; - *notransit = 0; - do { - ht = ht1; - itcount++; - dnew = days(y, m, d, ht * DEGS/15) - tz/24; - lst = gst(dnew) + glong; - /* find the topocentric Moon ra (hence hour angle) and dec */ - moonpos(dnew, &lon, &lat, &rv); - equatorial(dnew, &lon, &lat, &rv); - topo(lst, glat, &lon, &lat, &rv); - hm = rangerad(lst - lon); - ht1 = rangerad(ht - hm); - /* if no convergence, then no transit on that day */ - if (itcount > 30) { - *notransit = 1; - break; - } - } - while (fabs(ht - ht1) > 0.04 * RADS); - return(ht1); -} - -/* - Calculates the selenographic coordinates of either the sub Earth point - (optical libration) or the sub-solar point (selen. coords of centre of - bright hemisphere). Based on Meeus chapter 51 but neglects physical - libration and nutation, with some simplification of the formulas. -*/ -void libration(double day, double lambda, double beta, double alpha, double *l, double *b, double *p) { - double i, f, omega, w, y, x, a, t, eps; - t = day / 36525; - i = 1.54242 * RADS; - eps = epsilon(day); - f = range(93.2720993 + 483202.0175273 * t - .0034029 * t * t) * RADS; - omega = range(125.044555 - 1934.1361849 * t + .0020762 * t * t) * RADS; - w = lambda - omega; - y = sin(w) * cos(beta) * cos(i) - sin(beta) * sin(i); - x = cos(w) * cos(beta); - a = atan22(y, x); - *l = a - f; - - /* kludge to catch cases of 'round the back' angles */ - if (*l < -90 * RADS) *l += TPI; - if (*l > 90 * RADS) *l -= TPI; - *b = asin(-sin(w) * cos(beta) * sin(i) - sin(beta) * cos(i)); - - /* pa pole axis - not used for Sun stuff */ - x = sin(i) * sin(omega); - y = sin(i) * cos(omega) * cos(eps) - cos(i) * sin(eps); - w = atan22(x, y); - *p = rangerad(asin(sqrt(x*x + y*y) * cos(alpha - w) / cos(*b))); -} - -/* - Takes: days since J2000.0, eq coords Moon, ratio of moon to sun distance, - eq coords Sun - Returns: position angle of bright limb wrt NCP, percentage illumination - of Sun -*/ -void illumination(double day, double lra, double ldec, double dr, double sra, double sdec, double *pabl, double *ill) { - double x, y, phi, i; - y = cos(sdec) * sin(sra - lra); - x = sin(sdec) * cos(ldec) - cos(sdec) * sin(ldec) * cos (sra - lra); - *pabl = atan22(y, x); - phi = acos(sin(sdec) * sin(ldec) + cos(sdec) * cos(ldec) * cos(sra-lra)); - i = atan22(sin(phi) , (dr - cos(phi))); - *ill = 0.5*(1 + cos(i)); -} - -/* -sunpos() takes days from J2000.0 and returns ecliptic longitude -of Sun in the pointers. Latitude is zero at this level of precision, -but pointer left in for consistency in number of arguments. -This function is within 0.01 degree (1 arcmin) almost all the time -for a century either side of J2000.0. This is from the 'low precision -fomulas for the Sun' from C24 of Astronomical Alamanac -*/ -void sunpos(double d, double *lambda, double *beta, double *rvec) { - double L, g, ls, bs, rs; - - L = range(280.461 + .9856474 * d) * RADS; - g = range(357.528 + .9856003 * d) * RADS; - ls = L + (1.915 * sin(g) + .02 * sin(2 * g)) * RADS; - bs = 0; - rs = 1.00014 - .01671 * cos(g) - .00014 * cos(2 * g); - *lambda = ls; - *beta = bs; - *rvec = rs; -} - -/* -this routine returns the altitude given the days since J2000.0 -the hour angle and declination of the object and the latitude -of the observer. Used to find the Sun's altitude to put a letter -code on the transit time, and to find the Moon's altitude at -transit just to make sure that the Moon is visible. -*/ -double alt(double glat, double ha, double dec) { - return(asin(sin(dec) * sin(glat) + cos(dec) * cos(glat) * cos(ha))); -} - -/* returns an angle in degrees in the range 0 to 360 */ -double range(double x) { - double a, b; - b = x / 360; - a = 360 * (b - floor(b)); - if (a < 0) - a = 360 + a; - return(a); -} - -/* returns an angle in rads in the range 0 to two pi */ -double rangerad(double x) { - double a, b; - b = x / TPI; - a = TPI * (b - floor(b)); - if (a < 0) - a = TPI + a; - return(a); -} - -/* -gets the atan2 function returning angles in the right -order and range -*/ -double atan22(double y, double x) { - double a; - - a = atan2(y, x); - if (a < 0) a += TPI; - return(a); -} - -/* -returns mean obliquity of ecliptic in radians given days since -J2000.0. -*/ -double epsilon(double d) { - double t = d/ 36525; - return((23.4392911111111 - (t* (46.8150 + 0.00059*t)/3600)) *RADS); -} - -/* -replaces ecliptic coordinates with equatorial coordinates -note: call by reference destroys original values -R is unchanged. -*/ -void equatorial(double d, double *lon, double *lat, double *r) { - double eps, ceps, seps, l, b; - - l = *lon; - b = * lat; - eps = epsilon(d); - ceps = cos(eps); - seps = sin(eps); - *lon = atan22(sin(l)*ceps - tan(b)*seps, cos(l)); - *lat = asin(sin(b)*ceps + cos(b)*seps*sin(l)); -} - -/* -replaces equatorial coordinates with ecliptic ones. Inverse -of above, but used to find topocentric ecliptic coords. -*/ -void ecliptic(double d, double *lon, double *lat, double *r) { - double eps, ceps, seps, alp, dec; - alp = *lon; - dec = *lat; - eps = epsilon(d); - ceps = cos(eps); - seps = sin(eps); - *lon = atan22(sin(alp)*ceps + tan(dec)*seps, cos(alp)); - *lat = asin(sin(dec)*ceps - cos(dec)*seps*sin(alp)); -} - -/* -returns the siderial time at greenwich meridian as -an angle in radians given the days since J2000.0 -*/ -double gst( double d) { - double t = d / 36525; - double theta; - theta = range(280.46061837 + 360.98564736629 * d + 0.000387933 * t * t); - return(theta * RADS); -} - -void tmoonsub_(double *day, double *glat, double *glong, double *moonalt, - double *mrv, double *l, double *b, double *paxis) -{ - double mlambda, mbeta; - double malpha, mdelta; - double lst, mhr; - double tlambda, tbeta, trv; - - lst = gst(*day) + *glong; - - /* find Moon topocentric coordinates for libration calculations */ - - moonpos(*day, &mlambda, &mbeta, mrv); - malpha = mlambda; - mdelta = mbeta; - equatorial(*day, &malpha, &mdelta, mrv); - topo(lst, *glat, &malpha, &mdelta, mrv); - mhr = rangerad(lst - malpha); - *moonalt = alt(*glat, mhr, mdelta); - - /* Optical libration and Position angle of the Pole */ - - tlambda = malpha; - tbeta = mdelta; - trv = *mrv; - ecliptic(*day, &tlambda, &tbeta, &trv); - libration(*day, tlambda, tbeta, malpha, l, b, paxis); -} +#include +#include +#include + +#define RADS 0.0174532925199433 +#define DEGS 57.2957795130823 +#define TPI 6.28318530717959 +#define PI 3.1415927 + +/* ratio of earth radius to astronomical unit */ +#define ER_OVER_AU 0.0000426352325194252 + +/* all prototypes here */ + +double getcoord(int coord); +void getargs(int argc, char *argv[], int *y, int *m, double *tz, double *glong, double *glat); +double range(double y); +double rangerad(double y); +double days(int y, int m, int dn, double hour); +double days_(int *y, int *m, int *dn, double *hour); +void moonpos(double, double *, double *, double *); +void sunpos(double , double *, double *, double *); +double moontransit(int y, int m, int d, double timezone, double glat, double glong, int *nt); +double atan22(double y, double x); +double epsilon(double d); +void equatorial(double d, double *lon, double *lat, double *r); +void ecliptic(double d, double *lon, double *lat, double *r); +double gst(double d); +void topo(double lst, double glat, double *alp, double *dec, double *r); +double alt(double glat, double ha, double dec); +void libration(double day, double lambda, double beta, double alpha, double *l, double *b, double *p); +void illumination(double day, double lra, double ldec, double dr, double sra, double sdec, double *pabl, double *ill); +int daysinmonth(int y, int m); +int isleap(int y); +void tmoonsub_(double *day, double *glat, double *glong, double *moonalt, + double *mrv, double *l, double *b, double *paxis); + +static const char +*usage = " Usage: tmoon date[yyyymm] timz[+/-h.hh] long[+/-dddmm] lat[+/-ddmm]\n" + "example: tmoon 200009 0 -00155 5230\n"; + +/* + getargs() gets the arguments from the command line, does some basic error + checking, and converts arguments into numerical form. Arguments are passed + back in pointers. Error messages print to stderr so re-direction of output + to file won't leave users blind. Error checking prints list of all errors + in a command line before quitting. +*/ +void getargs(int argc, char *argv[], int *y, int *m, double *tz, + double *glong, double *glat) { + + int date, latitude, longitude; + int mflag = 0, yflag = 0, longflag = 0, latflag = 0, tzflag = 0; + int longminflag = 0, latminflag = 0, dflag = 0; + + /* if not right number of arguments, then print example command line */ + + if (argc !=5) { + fprintf(stderr, usage); + exit(EXIT_FAILURE); + } + + date = atoi(argv[1]); + *y = date / 100; + *m = date - *y * 100; + *tz = (double) atof(argv[2]); + longitude = atoi(argv[3]); + latitude = atoi(argv[4]); + *glong = RADS * getcoord(longitude); + *glat = RADS * getcoord(latitude); + + /* set a flag for each error found */ + + if (*m > 12 || *m < 1) mflag = 1; + if (*y > 2500) yflag = 1; + if (date < 150001) dflag = 1; + if (fabs((float) *glong) > 180 * RADS) longflag = 1; + if (abs(longitude) % 100 > 59) longminflag = 1; + if (fabs((float) *glat) > 90 * RADS) latflag = 1; + if (abs(latitude) % 100 > 59) latminflag = 1; + if (fabs((float) *tz) > 12) tzflag = 1; + + /* print all the errors found */ + + if (dflag == 1) { + fprintf(stderr, "date: dates must be in form yyyymm, gregorian, and later than 1500 AD\n"); + } + if (yflag == 1) { + fprintf(stderr, "date: too far in future - accurate from 1500 to 2500\n"); + } + if (mflag == 1) { + fprintf(stderr, "date: month must be in range 0 to 12, eg - August 2000 is entered as 200008\n"); + } + if (tzflag == 1) { + fprintf(stderr, "timz: must be in range +/- 12 hours, eg -6 for Chicago\n"); + } + if (longflag == 1) { + fprintf(stderr, "long: must be in range +/- 180 degrees\n"); + } + if (longminflag == 1) { + fprintf(stderr, "long: last two digits are arcmin - max 59\n"); + } + if (latflag == 1) { + fprintf(stderr, " lat: must be in range +/- 90 degrees\n"); + } + if (latminflag == 1) { + fprintf(stderr, " lat: last two digits are arcmin - max 59\n"); + } + + /* quits if one or more flags set */ + + if (dflag + mflag + yflag + longflag + latflag + tzflag + longminflag + latminflag > 0) { + exit(EXIT_FAILURE); + } + +} + +/* + returns coordinates in decimal degrees given the + coord as a ddmm value stored in an integer. +*/ +double getcoord(int coord) { + int west = 1; + double glg, deg; + if (coord < 0) west = -1; + glg = fabs((double) coord/100); + deg = floor(glg); + glg = west* (deg + (glg - deg)*100 / 60); + return(glg); +} + +/* + days() takes the year, month, day in the month and decimal hours + in the day and returns the number of days since J2000.0. + Assumes Gregorian calendar. +*/ +double days(int y, int m, int d, double h) { + int a, b; + double day; + + /* + The lines below work from 1900 march to feb 2100 + a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d; + day = (double)a - 730531.5 + hour / 24; + */ + + /* These lines work for any Gregorian date since 0 AD */ + if (m ==1 || m==2) { + m +=12; + y -= 1; + } + a = y / 100; + b = 2 - a + a/4; + day = floor(365.25*(y + 4716)) + floor(30.6001*(m + 1)) + + d + b - 1524.5 - 2451545 + h/24; + return(day); +} +double days_(int *y0, int *m0, int *d0, double *h0) +{ + return days(*y0,*m0,*d0,*h0); +} + +/* +Returns 1 if y a leap year, and 0 otherwise, according +to the Gregorian calendar +*/ +int isleap(int y) { + int a = 0; + if(y % 4 == 0) a = 1; + if(y % 100 == 0) a = 0; + if(y % 400 == 0) a = 1; + return(a); +} + +/* +Given the year and the month, function returns the +number of days in the month. Valid for Gregorian +calendar. +*/ +int daysinmonth(int y, int m) { + int b = 31; + if(m == 2) { + if(isleap(y) == 1) b= 29; + else b = 28; + } + if(m == 4 || m == 6 || m == 9 || m == 11) b = 30; + return(b); +} + +/* +moonpos() takes days from J2000.0 and returns ecliptic coordinates +of moon in the pointers. Note call by reference. +This function is within a couple of arcminutes most of the time, +and is truncated from the Meeus Ch45 series, themselves truncations of +ELP-2000. Returns moon distance in earth radii. +Terms have been written out explicitly rather than using the +table based method as only a small number of terms is +retained. +*/ +void moonpos(double d, double *lambda, double *beta, double *rvec) { + double dl, dB, dR, L, D, M, M1, F, e, lm, bm, rm, t; + + t = d / 36525; + + L = range(218.3164591 + 481267.88134236 * t) * RADS; + D = range(297.8502042 + 445267.1115168 * t) * RADS; + M = range(357.5291092 + 35999.0502909 * t) * RADS; + M1 = range(134.9634114 + 477198.8676313 * t - .008997 * t * t) * RADS; + F = range(93.27209929999999 + 483202.0175273 * t - .0034029*t*t)*RADS; + e = 1 - .002516 * t; + + dl = 6288774 * sin(M1); + dl += 1274027 * sin(2 * D - M1); + dl += 658314 * sin(2 * D); + dl += 213618 * sin(2 * M1); + dl -= e * 185116 * sin(M); + dl -= 114332 * sin(2 * F) ; + dl += 58793 * sin(2 * D - 2 * M1); + dl += e * 57066 * sin(2 * D - M - M1) ; + dl += 53322 * sin(2 * D + M1); + dl += e * 45758 * sin(2 * D - M); + dl -= e * 40923 * sin(M - M1); + dl -= 34720 * sin(D) ; + dl -= e * 30383 * sin(M + M1) ; + dl += 15327 * sin(2 * D - 2 * F) ; + dl -= 12528 * sin(M1 + 2 * F); + dl += 10980 * sin(M1 - 2 * F); + lm = rangerad(L + dl / 1000000 * RADS); + + dB = 5128122 * sin(F); + dB += 280602 * sin(M1 + F); + dB += 277693 * sin(M1 - F); + dB += 173237 * sin(2 * D - F); + dB += 55413 * sin(2 * D - M1 + F); + dB += 46271 * sin(2 * D - M1 - F); + dB += 32573 * sin(2 * D + F); + dB += 17198 * sin(2 * M1 + F); + dB += 9266 * sin(2 * D + M1 - F); + dB += 8822 * sin(2 * M1 - F); + dB += e * 8216 * sin(2 * D - M - F); + dB += 4324 * sin(2 * D - 2 * M1 - F); + bm = dB / 1000000 * RADS; + + dR = -20905355 * cos(M1); + dR -= 3699111 * cos(2 * D - M1); + dR -= 2955968 * cos(2 * D); + dR -= 569925 * cos(2 * M1); + dR += e * 48888 * cos(M); + dR -= 3149 * cos(2 * F); + dR += 246158 * cos(2 * D - 2 * M1); + dR -= e * 152138 * cos(2 * D - M - M1) ; + dR -= 170733 * cos(2 * D + M1); + dR -= e * 204586 * cos(2 * D - M); + dR -= e * 129620 * cos(M - M1); + dR += 108743 * cos(D); + dR += e * 104755 * cos(M + M1); + dR += 79661 * cos(M1 - 2 * F); + rm = 385000.56 + dR / 1000; + + *lambda = lm; + *beta = bm; + /* distance to Moon must be in Earth radii */ + *rvec = rm / 6378.14; +} + +/* +topomoon() takes the local siderial time, the geographical +latitude of the observer, and pointers to the geocentric +equatorial coordinates. The function overwrites the geocentric +coordinates with topocentric coordinates on a simple spherical +earth model (no polar flattening). Expects Moon-Earth distance in +Earth radii. Formulas scavenged from Astronomical Almanac 'low +precision formulae for Moon position' page D46. +*/ + +void topo(double lst, double glat, double *alp, double *dec, double *r) { + double x, y, z, r1; + x = *r * cos(*dec) * cos(*alp) - cos(glat) * cos(lst); + y = *r * cos(*dec) * sin(*alp) - cos(glat) * sin(lst); + z = *r * sin(*dec) - sin(glat); + r1 = sqrt(x*x + y*y + z*z); + *alp = atan22(y, x); + *dec = asin(z / r1); + *r = r1; +} + +/* +moontransit() takes date, the time zone and geographic longitude +of observer and returns the time (decimal hours) of lunar transit +on that day if there is one, and sets the notransit flag if there +isn't. See Explanatory Supplement to Astronomical Almanac +section 9.32 and 9.31 for the method. +*/ + +double moontransit(int y, int m, int d, double tz, double glat, double glong, int *notransit) { + double hm, ht, ht1, lon, lat, rv, dnew, lst; + int itcount; + + ht1 = 180 * RADS; + ht = 0; + itcount = 0; + *notransit = 0; + do { + ht = ht1; + itcount++; + dnew = days(y, m, d, ht * DEGS/15) - tz/24; + lst = gst(dnew) + glong; + /* find the topocentric Moon ra (hence hour angle) and dec */ + moonpos(dnew, &lon, &lat, &rv); + equatorial(dnew, &lon, &lat, &rv); + topo(lst, glat, &lon, &lat, &rv); + hm = rangerad(lst - lon); + ht1 = rangerad(ht - hm); + /* if no convergence, then no transit on that day */ + if (itcount > 30) { + *notransit = 1; + break; + } + } + while (fabs(ht - ht1) > 0.04 * RADS); + return(ht1); +} + +/* + Calculates the selenographic coordinates of either the sub Earth point + (optical libration) or the sub-solar point (selen. coords of centre of + bright hemisphere). Based on Meeus chapter 51 but neglects physical + libration and nutation, with some simplification of the formulas. +*/ +void libration(double day, double lambda, double beta, double alpha, double *l, double *b, double *p) { + double i, f, omega, w, y, x, a, t, eps; + t = day / 36525; + i = 1.54242 * RADS; + eps = epsilon(day); + f = range(93.2720993 + 483202.0175273 * t - .0034029 * t * t) * RADS; + omega = range(125.044555 - 1934.1361849 * t + .0020762 * t * t) * RADS; + w = lambda - omega; + y = sin(w) * cos(beta) * cos(i) - sin(beta) * sin(i); + x = cos(w) * cos(beta); + a = atan22(y, x); + *l = a - f; + + /* kludge to catch cases of 'round the back' angles */ + if (*l < -90 * RADS) *l += TPI; + if (*l > 90 * RADS) *l -= TPI; + *b = asin(-sin(w) * cos(beta) * sin(i) - sin(beta) * cos(i)); + + /* pa pole axis - not used for Sun stuff */ + x = sin(i) * sin(omega); + y = sin(i) * cos(omega) * cos(eps) - cos(i) * sin(eps); + w = atan22(x, y); + *p = rangerad(asin(sqrt(x*x + y*y) * cos(alpha - w) / cos(*b))); +} + +/* + Takes: days since J2000.0, eq coords Moon, ratio of moon to sun distance, + eq coords Sun + Returns: position angle of bright limb wrt NCP, percentage illumination + of Sun +*/ +void illumination(double day, double lra, double ldec, double dr, double sra, double sdec, double *pabl, double *ill) { + double x, y, phi, i; + y = cos(sdec) * sin(sra - lra); + x = sin(sdec) * cos(ldec) - cos(sdec) * sin(ldec) * cos (sra - lra); + *pabl = atan22(y, x); + phi = acos(sin(sdec) * sin(ldec) + cos(sdec) * cos(ldec) * cos(sra-lra)); + i = atan22(sin(phi) , (dr - cos(phi))); + *ill = 0.5*(1 + cos(i)); +} + +/* +sunpos() takes days from J2000.0 and returns ecliptic longitude +of Sun in the pointers. Latitude is zero at this level of precision, +but pointer left in for consistency in number of arguments. +This function is within 0.01 degree (1 arcmin) almost all the time +for a century either side of J2000.0. This is from the 'low precision +fomulas for the Sun' from C24 of Astronomical Alamanac +*/ +void sunpos(double d, double *lambda, double *beta, double *rvec) { + double L, g, ls, bs, rs; + + L = range(280.461 + .9856474 * d) * RADS; + g = range(357.528 + .9856003 * d) * RADS; + ls = L + (1.915 * sin(g) + .02 * sin(2 * g)) * RADS; + bs = 0; + rs = 1.00014 - .01671 * cos(g) - .00014 * cos(2 * g); + *lambda = ls; + *beta = bs; + *rvec = rs; +} + +/* +this routine returns the altitude given the days since J2000.0 +the hour angle and declination of the object and the latitude +of the observer. Used to find the Sun's altitude to put a letter +code on the transit time, and to find the Moon's altitude at +transit just to make sure that the Moon is visible. +*/ +double alt(double glat, double ha, double dec) { + return(asin(sin(dec) * sin(glat) + cos(dec) * cos(glat) * cos(ha))); +} + +/* returns an angle in degrees in the range 0 to 360 */ +double range(double x) { + double a, b; + b = x / 360; + a = 360 * (b - floor(b)); + if (a < 0) + a = 360 + a; + return(a); +} + +/* returns an angle in rads in the range 0 to two pi */ +double rangerad(double x) { + double a, b; + b = x / TPI; + a = TPI * (b - floor(b)); + if (a < 0) + a = TPI + a; + return(a); +} + +/* +gets the atan2 function returning angles in the right +order and range +*/ +double atan22(double y, double x) { + double a; + + a = atan2(y, x); + if (a < 0) a += TPI; + return(a); +} + +/* +returns mean obliquity of ecliptic in radians given days since +J2000.0. +*/ +double epsilon(double d) { + double t = d/ 36525; + return((23.4392911111111 - (t* (46.8150 + 0.00059*t)/3600)) *RADS); +} + +/* +replaces ecliptic coordinates with equatorial coordinates +note: call by reference destroys original values +R is unchanged. +*/ +void equatorial(double d, double *lon, double *lat, double *r) { + double eps, ceps, seps, l, b; + + l = *lon; + b = * lat; + eps = epsilon(d); + ceps = cos(eps); + seps = sin(eps); + *lon = atan22(sin(l)*ceps - tan(b)*seps, cos(l)); + *lat = asin(sin(b)*ceps + cos(b)*seps*sin(l)); +} + +/* +replaces equatorial coordinates with ecliptic ones. Inverse +of above, but used to find topocentric ecliptic coords. +*/ +void ecliptic(double d, double *lon, double *lat, double *r) { + double eps, ceps, seps, alp, dec; + alp = *lon; + dec = *lat; + eps = epsilon(d); + ceps = cos(eps); + seps = sin(eps); + *lon = atan22(sin(alp)*ceps + tan(dec)*seps, cos(alp)); + *lat = asin(sin(dec)*ceps - cos(dec)*seps*sin(alp)); +} + +/* +returns the siderial time at greenwich meridian as +an angle in radians given the days since J2000.0 +*/ +double gst( double d) { + double t = d / 36525; + double theta; + theta = range(280.46061837 + 360.98564736629 * d + 0.000387933 * t * t); + return(theta * RADS); +} + +void tmoonsub_(double *day, double *glat, double *glong, double *moonalt, + double *mrv, double *l, double *b, double *paxis) +{ + double mlambda, mbeta; + double malpha, mdelta; + double lst, mhr; + double tlambda, tbeta, trv; + + lst = gst(*day) + *glong; + + /* find Moon topocentric coordinates for libration calculations */ + + moonpos(*day, &mlambda, &mbeta, mrv); + malpha = mlambda; + mdelta = mbeta; + equatorial(*day, &malpha, &mdelta, mrv); + topo(lst, *glat, &malpha, &mdelta, mrv); + mhr = rangerad(lst - malpha); + *moonalt = alt(*glat, mhr, mdelta); + + /* Optical libration and Position angle of the Pole */ + + tlambda = malpha; + tbeta = mdelta; + trv = *mrv; + ecliptic(*day, &tlambda, &tbeta, &trv); + libration(*day, tlambda, tbeta, malpha, l, b, paxis); +} diff --git a/libm65/toxyz.f b/libm65/toxyz.f index e3fe52b7c..9f75d5de1 100644 --- a/libm65/toxyz.f +++ b/libm65/toxyz.f @@ -1,25 +1,25 @@ - subroutine toxyz(alpha,delta,r,vec) - - implicit real*8 (a-h,o-z) - real*8 vec(3) - - vec(1)=r*cos(delta)*cos(alpha) - vec(2)=r*cos(delta)*sin(alpha) - vec(3)=r*sin(delta) - - return - end - - subroutine fromxyz(vec,alpha,delta,r) - - implicit real*8 (a-h,o-z) - real*8 vec(3) - data twopi/6.283185307d0/ - - r=sqrt(vec(1)**2 + vec(2)**2 + vec(3)**2) - alpha=atan2(vec(2),vec(1)) - if(alpha.lt.0.d0) alpha=alpha+twopi - delta=asin(vec(3)/r) - - return - end + subroutine toxyz(alpha,delta,r,vec) + + implicit real*8 (a-h,o-z) + real*8 vec(3) + + vec(1)=r*cos(delta)*cos(alpha) + vec(2)=r*cos(delta)*sin(alpha) + vec(3)=r*sin(delta) + + return + end + + subroutine fromxyz(vec,alpha,delta,r) + + implicit real*8 (a-h,o-z) + real*8 vec(3) + data twopi/6.283185307d0/ + + r=sqrt(vec(1)**2 + vec(2)**2 + vec(3)**2) + alpha=atan2(vec(2),vec(1)) + if(alpha.lt.0.d0) alpha=alpha+twopi + delta=asin(vec(3)/r) + + return + end diff --git a/libm65/trimlist.f b/libm65/trimlist.f index 1834b4cac..a28c0446a 100644 --- a/libm65/trimlist.f +++ b/libm65/trimlist.f @@ -1,28 +1,28 @@ - subroutine trimlist(sig,km,ftol,indx,nsiz,nz) - - parameter (MAXMSG=1000) !Size of decoded message list - real sig(MAXMSG,30) - integer indx(MAXMSG),nsiz(MAXMSG) - -C 1 2 3 4 5 6 7 8 -C nfile nutc freq snr dt ipol flip sync - - call indexx(km,sig(1,3),indx) !Sort list by frequency - - n=1 - i0=1 - do i=2,km - j0=indx(i-1) - j=indx(i) - if(sig(j,3)-sig(j0,3).gt.ftol) then - nsiz(n)=i-i0 - i0=i - n=n+1 - endif - enddo - nz=n - nsiz(nz)=km+1-i0 - nsiz(nz+1)=-1 - - return - end + subroutine trimlist(sig,km,ftol,indx,nsiz,nz) + + parameter (MAXMSG=1000) !Size of decoded message list + real sig(MAXMSG,30) + integer indx(MAXMSG),nsiz(MAXMSG) + +C 1 2 3 4 5 6 7 8 +C nfile nutc freq snr dt ipol flip sync + + call indexx(km,sig(1,3),indx) !Sort list by frequency + + n=1 + i0=1 + do i=2,km + j0=indx(i-1) + j=indx(i) + if(sig(j,3)-sig(j0,3).gt.ftol) then + nsiz(n)=i-i0 + i0=i + n=n+1 + endif + enddo + nz=n + nsiz(nz)=km+1-i0 + nsiz(nz+1)=-1 + + return + end diff --git a/libm65/twkfreq.f b/libm65/twkfreq.f index 0199342ef..364e17c02 100644 --- a/libm65/twkfreq.f +++ b/libm65/twkfreq.f @@ -1,29 +1,29 @@ - subroutine twkfreq(c4aa,c4bb,n5,a) - - complex c4aa(n5) - complex c4bb(n5) - real a(5) - complex w,wstep - data twopi/6.283185307/ - -C Apply AFC corrections to the c4aa and c4bb data - w=1.0 - wstep=1.0 - x0=0.5*(n5+1) - s=2.0/n5 - do i=1,n5 - x=s*(i-x0) - if(mod(i,1000).eq.1) then - p2=1.5*x*x - 0.5 -! p3=2.5*(x**3) - 1.5*x -! p4=4.375*(x**4) - 3.75*(x**2) + 0.375 - dphi=(a(1) + x*a(2) + p2*a(3)) * (twopi/1378.125) - wstep=cmplx(cos(dphi),sin(dphi)) - endif - w=w*wstep - c4aa(i)=w*c4aa(i) - c4bb(i)=w*c4bb(i) - enddo - - return - end + subroutine twkfreq(c4aa,c4bb,n5,a) + + complex c4aa(n5) + complex c4bb(n5) + real a(5) + complex w,wstep + data twopi/6.283185307/ + +C Apply AFC corrections to the c4aa and c4bb data + w=1.0 + wstep=1.0 + x0=0.5*(n5+1) + s=2.0/n5 + do i=1,n5 + x=s*(i-x0) + if(mod(i,1000).eq.1) then + p2=1.5*x*x - 0.5 +! p3=2.5*(x**3) - 1.5*x +! p4=4.375*(x**4) - 3.75*(x**2) + 0.375 + dphi=(a(1) + x*a(2) + p2*a(3)) * (twopi/1378.125) + wstep=cmplx(cos(dphi),sin(dphi)) + endif + w=w*wstep + c4aa(i)=w*c4aa(i) + c4bb(i)=w*c4bb(i) + enddo + + return + end diff --git a/libm65/unpackcall.f b/libm65/unpackcall.f index feb5bb466..9a5a218c3 100644 --- a/libm65/unpackcall.f +++ b/libm65/unpackcall.f @@ -1,142 +1,142 @@ - subroutine unpackcall(ncall,word,iv2,psfx) - - parameter (NBASE=37*36*10*27*27*27) - character word*12,c*37,psfx*4 - - data c/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ '/ - - n=ncall - iv2=0 - if(n.ge.262177560) go to 20 - word='......' - if(n.ge.262177560) go to 999 !Plain text message ... - i=mod(n,27)+11 - word(6:6)=c(i:i) - n=n/27 - i=mod(n,27)+11 - word(5:5)=c(i:i) - n=n/27 - i=mod(n,27)+11 - word(4:4)=c(i:i) - n=n/27 - i=mod(n,10)+1 - word(3:3)=c(i:i) - n=n/10 - i=mod(n,36)+1 - word(2:2)=c(i:i) - n=n/36 - i=n+1 - word(1:1)=c(i:i) - do i=1,4 - if(word(i:i).ne.' ') go to 10 - enddo - go to 999 - 10 word=word(i:) - go to 999 - - 20 if(n.ge.267796946) go to 999 - -! We have a JT65v2 message - if((n.ge.262178563) .and. (n.le.264002071)) Then -! CQ with prefix - iv2=1 - n=n-262178563 - i=mod(n,37)+1 - psfx(4:4)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(3:3)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(2:2)=c(i:i) - n=n/37 - i=n+1 - psfx(1:1)=c(i:i) - endif - - if((n.ge.264002072) .and. (n.le.265825580)) Then -! QRZ with prefix - iv2=2 - n=n-264002072 - i=mod(n,37)+1 - psfx(4:4)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(3:3)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(2:2)=c(i:i) - n=n/37 - i=n+1 - psfx(1:1)=c(i:i) - endif - - if((n.ge.265825581) .and. (n.le.267649089)) Then -! DE with prefix - iv2=3 - n=n-265825581 - i=mod(n,37)+1 - psfx(4:4)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(3:3)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(2:2)=c(i:i) - n=n/37 - i=n+1 - psfx(1:1)=c(i:i) - endif - - if((n.ge.267649090) .and. (n.le.267698374)) Then -! CQ with suffix - iv2=4 - n=n-267649090 - i=mod(n,37)+1 - psfx(3:3)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(2:2)=c(i:i) - n=n/37 - i=n+1 - psfx(1:1)=c(i:i) - endif - - if((n.ge.267698375) .and. (n.le.267747659)) Then -! QRZ with suffix - iv2=5 - n=n-267698375 - i=mod(n,37)+1 - psfx(3:3)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(2:2)=c(i:i) - n=n/37 - i=n+1 - psfx(1:1)=c(i:i) - endif - - if((n.ge.267747660) .and. (n.le.267796944)) Then -! DE with suffix - iv2=6 - n=n-267747660 - i=mod(n,37)+1 - psfx(3:3)=c(i:i) - n=n/37 - i=mod(n,37)+1 - psfx(2:2)=c(i:i) - n=n/37 - i=n+1 - psfx(1:1)=c(i:i) - endif - - if(n.eq.267796945) Then -! DE with no prefix or suffix - iv2=7 - psfx = ' ' - endif - - 999 if(word(1:3).eq.'3D0') word='3DA0'//word(4:) - - return - end + subroutine unpackcall(ncall,word,iv2,psfx) + + parameter (NBASE=37*36*10*27*27*27) + character word*12,c*37,psfx*4 + + data c/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ '/ + + n=ncall + iv2=0 + if(n.ge.262177560) go to 20 + word='......' + if(n.ge.262177560) go to 999 !Plain text message ... + i=mod(n,27)+11 + word(6:6)=c(i:i) + n=n/27 + i=mod(n,27)+11 + word(5:5)=c(i:i) + n=n/27 + i=mod(n,27)+11 + word(4:4)=c(i:i) + n=n/27 + i=mod(n,10)+1 + word(3:3)=c(i:i) + n=n/10 + i=mod(n,36)+1 + word(2:2)=c(i:i) + n=n/36 + i=n+1 + word(1:1)=c(i:i) + do i=1,4 + if(word(i:i).ne.' ') go to 10 + enddo + go to 999 + 10 word=word(i:) + go to 999 + + 20 if(n.ge.267796946) go to 999 + +! We have a JT65v2 message + if((n.ge.262178563) .and. (n.le.264002071)) Then +! CQ with prefix + iv2=1 + n=n-262178563 + i=mod(n,37)+1 + psfx(4:4)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(3:3)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(2:2)=c(i:i) + n=n/37 + i=n+1 + psfx(1:1)=c(i:i) + endif + + if((n.ge.264002072) .and. (n.le.265825580)) Then +! QRZ with prefix + iv2=2 + n=n-264002072 + i=mod(n,37)+1 + psfx(4:4)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(3:3)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(2:2)=c(i:i) + n=n/37 + i=n+1 + psfx(1:1)=c(i:i) + endif + + if((n.ge.265825581) .and. (n.le.267649089)) Then +! DE with prefix + iv2=3 + n=n-265825581 + i=mod(n,37)+1 + psfx(4:4)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(3:3)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(2:2)=c(i:i) + n=n/37 + i=n+1 + psfx(1:1)=c(i:i) + endif + + if((n.ge.267649090) .and. (n.le.267698374)) Then +! CQ with suffix + iv2=4 + n=n-267649090 + i=mod(n,37)+1 + psfx(3:3)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(2:2)=c(i:i) + n=n/37 + i=n+1 + psfx(1:1)=c(i:i) + endif + + if((n.ge.267698375) .and. (n.le.267747659)) Then +! QRZ with suffix + iv2=5 + n=n-267698375 + i=mod(n,37)+1 + psfx(3:3)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(2:2)=c(i:i) + n=n/37 + i=n+1 + psfx(1:1)=c(i:i) + endif + + if((n.ge.267747660) .and. (n.le.267796944)) Then +! DE with suffix + iv2=6 + n=n-267747660 + i=mod(n,37)+1 + psfx(3:3)=c(i:i) + n=n/37 + i=mod(n,37)+1 + psfx(2:2)=c(i:i) + n=n/37 + i=n+1 + psfx(1:1)=c(i:i) + endif + + if(n.eq.267796945) Then +! DE with no prefix or suffix + iv2=7 + psfx = ' ' + endif + + 999 if(word(1:3).eq.'3D0') word='3DA0'//word(4:) + + return + end diff --git a/libm65/unpackgrid.f b/libm65/unpackgrid.f index 76bf8f099..bc4ea1eb2 100644 --- a/libm65/unpackgrid.f +++ b/libm65/unpackgrid.f @@ -1,32 +1,32 @@ - subroutine unpackgrid(ng,grid) - - parameter (NGBASE=180*180) - character grid*4,grid6*6 - - grid=' ' - if(ng.ge.32400) go to 10 - dlat=mod(ng,180)-90 - dlong=(ng/180)*2 - 180 + 2 - call deg2grid(dlong,dlat,grid6) - grid=grid6(:4) - go to 100 - - 10 n=ng-NGBASE-1 - if(n.ge.1 .and.n.le.30) then - write(grid,1012) -n - 1012 format(i3.2) - else if(n.ge.31 .and.n.le.60) then - n=n-30 - write(grid,1022) -n - 1022 format('R',i3.2) - else if(n.eq.61) then - grid='RO' - else if(n.eq.62) then - grid='RRR' - else if(n.eq.63) then - grid='73' - endif - - 100 return - end - + subroutine unpackgrid(ng,grid) + + parameter (NGBASE=180*180) + character grid*4,grid6*6 + + grid=' ' + if(ng.ge.32400) go to 10 + dlat=mod(ng,180)-90 + dlong=(ng/180)*2 - 180 + 2 + call deg2grid(dlong,dlat,grid6) + grid=grid6(:4) + go to 100 + + 10 n=ng-NGBASE-1 + if(n.ge.1 .and.n.le.30) then + write(grid,1012) -n + 1012 format(i3.2) + else if(n.ge.31 .and.n.le.60) then + n=n-30 + write(grid,1022) -n + 1022 format('R',i3.2) + else if(n.eq.61) then + grid='RO' + else if(n.eq.62) then + grid='RRR' + else if(n.eq.63) then + grid='73' + endif + + 100 return + end + diff --git a/libm65/unpackmsg.f b/libm65/unpackmsg.f index 07bbd7b88..f9d3962fd 100644 --- a/libm65/unpackmsg.f +++ b/libm65/unpackmsg.f @@ -1,100 +1,100 @@ - subroutine unpackmsg(dat,msg) - - parameter (NBASE=37*36*10*27*27*27) - parameter (NGBASE=180*180) - integer dat(12) - character c1*12,c2*12,grid*4,msg*22,grid6*6,psfx*4,junk2*4 - logical cqnnn - - cqnnn=.false. - nc1=ishft(dat(1),22) + ishft(dat(2),16) + ishft(dat(3),10)+ - + ishft(dat(4),4) + iand(ishft(dat(5),-2),15) - - nc2=ishft(iand(dat(5),3),26) + ishft(dat(6),20) + - + ishft(dat(7),14) + ishft(dat(8),8) + ishft(dat(9),2) + - + iand(ishft(dat(10),-4),3) - - ng=ishft(iand(dat(10),15),12) + ishft(dat(11),6) + dat(12) - - if(ng.gt.32768) then - call unpacktext(nc1,nc2,ng,msg) - go to 100 - endif - - call unpackcall(nc1,c1,iv2,psfx) - if(iv2.eq.0) then -! This is an "original JT65" message - if(nc1.eq.NBASE+1) c1='CQ ' - if(nc1.eq.NBASE+2) c1='QRZ ' - nfreq=nc1-NBASE-3 - if(nfreq.ge.0 .and. nfreq.le.999) then - write(c1,1002) nfreq - 1002 format('CQ ',i3.3) - cqnnn=.true. - endif - endif - - call unpackcall(nc2,c2,junk1,junk2) - call unpackgrid(ng,grid) - - if(iv2.gt.0) then -! This is a JT65v2 message - n1=len_trim(psfx) - n2=len_trim(c2) - if(iv2.eq.1) msg='CQ '//psfx(:n1)//'/'//c2(:n2)//' '//grid - if(iv2.eq.2) msg='QRZ '//psfx(:n1)//'/'//c2(:n2)//' '//grid - if(iv2.eq.3) msg='DE '//psfx(:n1)//'/'//c2(:n2)//' '//grid - if(iv2.eq.4) msg='CQ '//c2(:n2)//'/'//psfx(:n1)//' '//grid - if(iv2.eq.5) msg='QRZ '//c2(:n2)//'/'//psfx(:n1)//' '//grid - if(iv2.eq.6) msg='DE '//c2(:n2)//'/'//psfx(:n1)//' '//grid - if(iv2.eq.7) msg='DE '//c2(:n2)//' '//grid - go to 100 - else - - endif - - grid6=grid//'ma' - call grid2k(grid6,k) - if(k.ge.1 .and. k.le.450) call getpfx2(k,c1) - if(k.ge.451 .and. k.le.900) call getpfx2(k,c2) - - i=index(c1,char(0)) - if(i.ge.3) c1=c1(1:i-1)//' ' - i=index(c2,char(0)) - if(i.ge.3) c2=c2(1:i-1)//' ' - - msg=' ' - j=0 - if(cqnnn) then - msg=c1//' ' - j=7 !### ??? ### - go to 10 - endif - - do i=1,12 - j=j+1 - msg(j:j)=c1(i:i) - if(c1(i:i).eq.' ') go to 10 - enddo - j=j+1 - msg(j:j)=' ' - - 10 do i=1,12 - if(j.le.21) j=j+1 - msg(j:j)=c2(i:i) - if(c2(i:i).eq.' ') go to 20 - enddo - if(j.le.21) j=j+1 - msg(j:j)=' ' - - 20 if(k.eq.0) then - do i=1,4 - if(j.le.21) j=j+1 - msg(j:j)=grid(i:i) - enddo - if(j.le.21) j=j+1 - msg(j:j)=' ' - endif - - 100 return - end + subroutine unpackmsg(dat,msg) + + parameter (NBASE=37*36*10*27*27*27) + parameter (NGBASE=180*180) + integer dat(12) + character c1*12,c2*12,grid*4,msg*22,grid6*6,psfx*4,junk2*4 + logical cqnnn + + cqnnn=.false. + nc1=ishft(dat(1),22) + ishft(dat(2),16) + ishft(dat(3),10)+ + + ishft(dat(4),4) + iand(ishft(dat(5),-2),15) + + nc2=ishft(iand(dat(5),3),26) + ishft(dat(6),20) + + + ishft(dat(7),14) + ishft(dat(8),8) + ishft(dat(9),2) + + + iand(ishft(dat(10),-4),3) + + ng=ishft(iand(dat(10),15),12) + ishft(dat(11),6) + dat(12) + + if(ng.gt.32768) then + call unpacktext(nc1,nc2,ng,msg) + go to 100 + endif + + call unpackcall(nc1,c1,iv2,psfx) + if(iv2.eq.0) then +! This is an "original JT65" message + if(nc1.eq.NBASE+1) c1='CQ ' + if(nc1.eq.NBASE+2) c1='QRZ ' + nfreq=nc1-NBASE-3 + if(nfreq.ge.0 .and. nfreq.le.999) then + write(c1,1002) nfreq + 1002 format('CQ ',i3.3) + cqnnn=.true. + endif + endif + + call unpackcall(nc2,c2,junk1,junk2) + call unpackgrid(ng,grid) + + if(iv2.gt.0) then +! This is a JT65v2 message + n1=len_trim(psfx) + n2=len_trim(c2) + if(iv2.eq.1) msg='CQ '//psfx(:n1)//'/'//c2(:n2)//' '//grid + if(iv2.eq.2) msg='QRZ '//psfx(:n1)//'/'//c2(:n2)//' '//grid + if(iv2.eq.3) msg='DE '//psfx(:n1)//'/'//c2(:n2)//' '//grid + if(iv2.eq.4) msg='CQ '//c2(:n2)//'/'//psfx(:n1)//' '//grid + if(iv2.eq.5) msg='QRZ '//c2(:n2)//'/'//psfx(:n1)//' '//grid + if(iv2.eq.6) msg='DE '//c2(:n2)//'/'//psfx(:n1)//' '//grid + if(iv2.eq.7) msg='DE '//c2(:n2)//' '//grid + go to 100 + else + + endif + + grid6=grid//'ma' + call grid2k(grid6,k) + if(k.ge.1 .and. k.le.450) call getpfx2(k,c1) + if(k.ge.451 .and. k.le.900) call getpfx2(k,c2) + + i=index(c1,char(0)) + if(i.ge.3) c1=c1(1:i-1)//' ' + i=index(c2,char(0)) + if(i.ge.3) c2=c2(1:i-1)//' ' + + msg=' ' + j=0 + if(cqnnn) then + msg=c1//' ' + j=7 !### ??? ### + go to 10 + endif + + do i=1,12 + j=j+1 + msg(j:j)=c1(i:i) + if(c1(i:i).eq.' ') go to 10 + enddo + j=j+1 + msg(j:j)=' ' + + 10 do i=1,12 + if(j.le.21) j=j+1 + msg(j:j)=c2(i:i) + if(c2(i:i).eq.' ') go to 20 + enddo + if(j.le.21) j=j+1 + msg(j:j)=' ' + + 20 if(k.eq.0) then + do i=1,4 + if(j.le.21) j=j+1 + msg(j:j)=grid(i:i) + enddo + if(j.le.21) j=j+1 + msg(j:j)=' ' + endif + + 100 return + end diff --git a/libm65/unpacktext.f b/libm65/unpacktext.f index 54022226d..0923e7eb1 100644 --- a/libm65/unpacktext.f +++ b/libm65/unpacktext.f @@ -1,35 +1,35 @@ - subroutine unpacktext(nc1,nc2,nc3,msg) - - character*22 msg - character*44 c - data c/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ +-./?'/ - - nc3=iand(nc3,32767) !Remove the "plain text" bit - if(iand(nc1,1).ne.0) nc3=nc3+32768 - nc1=nc1/2 - if(iand(nc2,1).ne.0) nc3=nc3+65536 - nc2=nc2/2 - - do i=5,1,-1 - j=mod(nc1,42)+1 - msg(i:i)=c(j:j) - nc1=nc1/42 - enddo - - do i=10,6,-1 - j=mod(nc2,42)+1 - msg(i:i)=c(j:j) - nc2=nc2/42 - enddo - - do i=13,11,-1 - j=mod(nc3,42)+1 - msg(i:i)=c(j:j) - nc3=nc3/42 - enddo - msg(14:22) = ' ' - - return - end - - + subroutine unpacktext(nc1,nc2,nc3,msg) + + character*22 msg + character*44 c + data c/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ +-./?'/ + + nc3=iand(nc3,32767) !Remove the "plain text" bit + if(iand(nc1,1).ne.0) nc3=nc3+32768 + nc1=nc1/2 + if(iand(nc2,1).ne.0) nc3=nc3+65536 + nc2=nc2/2 + + do i=5,1,-1 + j=mod(nc1,42)+1 + msg(i:i)=c(j:j) + nc1=nc1/42 + enddo + + do i=10,6,-1 + j=mod(nc2,42)+1 + msg(i:i)=c(j:j) + nc2=nc2/42 + enddo + + do i=13,11,-1 + j=mod(nc3,42)+1 + msg(i:i)=c(j:j) + nc3=nc3/42 + enddo + msg(14:22) = ' ' + + return + end + + diff --git a/libm65/wrapkarn.c b/libm65/wrapkarn.c index 1b1a6311f..9e0a51caf 100644 --- a/libm65/wrapkarn.c +++ b/libm65/wrapkarn.c @@ -1,70 +1,70 @@ -#include -#include -#include -#include -#include -#include "rs.h" - -static void *rs; -static int first=1; - -void rs_encode_(int *dgen, int *sent) -// Encode JT65 data dgen[12], producing sent[63]. -{ - int dat1[12]; - int b[51]; - int i; - - if(first) { - // Initialize the JT65 codec - rs=init_rs_int(6,0x43,3,1,51,0); - first=0; - } - - // Reverse data order for the Karn codec. - for(i=0; i<12; i++) { - dat1[i]=dgen[11-i]; - } - // Compute the parity symbols - encode_rs_int(rs,dat1,b); - - // Move parity symbols and data into sent[] array, in reverse order. - for (i = 0; i < 51; i++) sent[50-i] = b[i]; - for (i = 0; i < 12; i++) sent[i+51] = dat1[11-i]; -} - -void rs_decode_(int *recd0, int *era0, int *numera0, int *decoded, int *nerr) -// Decode JT65 received data recd0[63], producing decoded[12]. -// Erasures are indicated in era0[numera]. The number of corrected -// errors is *nerr. If the data are uncorrectable, *nerr=-1 is returned. -{ - int numera; - int i; - int era_pos[50]; - int recd[63]; - - if(first) { - rs=init_rs_int(6,0x43,3,1,51,0); - first=0; - } - - numera=*numera0; - for(i=0; i<12; i++) recd[i]=recd0[62-i]; - for(i=0; i<51; i++) recd[12+i]=recd0[50-i]; - if(numera) - for(i=0; i +#include +#include +#include +#include +#include "rs.h" + +static void *rs; +static int first=1; + +void rs_encode_(int *dgen, int *sent) +// Encode JT65 data dgen[12], producing sent[63]. +{ + int dat1[12]; + int b[51]; + int i; + + if(first) { + // Initialize the JT65 codec + rs=init_rs_int(6,0x43,3,1,51,0); + first=0; + } + + // Reverse data order for the Karn codec. + for(i=0; i<12; i++) { + dat1[i]=dgen[11-i]; + } + // Compute the parity symbols + encode_rs_int(rs,dat1,b); + + // Move parity symbols and data into sent[] array, in reverse order. + for (i = 0; i < 51; i++) sent[50-i] = b[i]; + for (i = 0; i < 12; i++) sent[i+51] = dat1[11-i]; +} + +void rs_decode_(int *recd0, int *era0, int *numera0, int *decoded, int *nerr) +// Decode JT65 received data recd0[63], producing decoded[12]. +// Erasures are indicated in era0[numera]. The number of corrected +// errors is *nerr. If the data are uncorrectable, *nerr=-1 is returned. +{ + int numera; + int i; + int era_pos[50]; + int recd[63]; + + if(first) { + rs=init_rs_int(6,0x43,3,1,51,0); + first=0; + } + + numera=*numera0; + for(i=0; i<12; i++) recd[i]=recd0[62-i]; + for(i=0; i<51; i++) recd[12+i]=recd0[50-i]; + if(numera) + for(i=0; i -#include -#include "mainwindow.h" - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - MainWindow w; - w.show(); - return a.exec(); -} +#include +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp index a65b39a64..6b88b7581 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,1970 +1,1970 @@ -//-------------------------------------------------------------- MainWindow -#include "mainwindow.h" -#include "ui_mainwindow.h" -#include "devsetup.h" -#include "plotter.h" -#include "about.h" -#include "astro.h" -#include "widegraph.h" -#include "messages.h" -#include "bandmap.h" -#include "sleep.h" -#include - -#define NFFT 32768 - -short int iwave[60*11025]; //Wave file for Tx audio -int nwave; //Length of Tx waveform -bool btxok; //True if OK to transmit -double outputLatency; //Latency in seconds -qint16 id[4*60*96000]; - - -Astro* g_pAstro = NULL; -WideGraph* g_pWideGraph = NULL; -Messages* g_pMessages = NULL; - -BandMap* g_pBandMap = NULL; -QSharedMemory mem_m65("mem_m65"); - -QString rev="$Rev: 631 $"; -QString Program_Title_Version=" MAP65 v2.3.0, r" + rev.mid(6,3) + - " by K1JT"; - -extern const int RxDataFrequency = 96000; -extern const int TxDataFrequency = 11025; - -//-------------------------------------------------- MainWindow constructor -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow) -{ - ui->setupUi(this); - - on_EraseButton_clicked(); - ui->labUTC->setStyleSheet( \ - "QLabel { background-color : black; color : yellow; }"); - ui->labTol1->setStyleSheet( \ - "QLabel { background-color : white; color : black; }"); - ui->labTol1->setFrameStyle(QFrame::Panel | QFrame::Sunken); - ui->dxStationGroupBox->setStyleSheet("QFrame{border: 5px groove red}"); - - QActionGroup* paletteGroup = new QActionGroup(this); - ui->actionCuteSDR->setActionGroup(paletteGroup); - ui->actionLinrad->setActionGroup(paletteGroup); - ui->actionAFMHot->setActionGroup(paletteGroup); - ui->actionBlue->setActionGroup(paletteGroup); - - QActionGroup* modeGroup = new QActionGroup(this); - ui->actionJT65A->setActionGroup(modeGroup); - ui->actionJT65B->setActionGroup(modeGroup); - ui->actionJT65C->setActionGroup(modeGroup); - - QActionGroup* saveGroup = new QActionGroup(this); - ui->actionSave_all->setActionGroup(saveGroup); - ui->actionNone->setActionGroup(saveGroup); - - QActionGroup* DepthGroup = new QActionGroup(this); - ui->actionNo_Deep_Search->setActionGroup(DepthGroup); - ui->actionNormal_Deep_Search->setActionGroup(DepthGroup); - ui->actionAggressive_Deep_Search->setActionGroup(DepthGroup); - - QButtonGroup* txMsgButtonGroup = new QButtonGroup; - txMsgButtonGroup->addButton(ui->txrb1,1); - txMsgButtonGroup->addButton(ui->txrb2,2); - txMsgButtonGroup->addButton(ui->txrb3,3); - txMsgButtonGroup->addButton(ui->txrb4,4); - txMsgButtonGroup->addButton(ui->txrb5,5); - txMsgButtonGroup->addButton(ui->txrb6,6); - connect(txMsgButtonGroup,SIGNAL(buttonClicked(int)),SLOT(set_ntx(int))); - connect(ui->decodedTextBrowser,SIGNAL(selectCallsign(bool)),this, - SLOT(selectCall2(bool))); - - setWindowTitle(Program_Title_Version); - - connect(&soundInThread, SIGNAL(readyForFFT(int)), - this, SLOT(dataSink(int))); - connect(&soundInThread, SIGNAL(error(QString)), this, - SLOT(showSoundInError(QString))); - connect(&soundInThread, SIGNAL(status(QString)), this, - SLOT(showStatusMessage(QString))); - createStatusBar(); - - connect(&proc_m65, SIGNAL(readyReadStandardOutput()), - this, SLOT(readFromStdout())); - - connect(&proc_m65, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(m65_error())); - - connect(&proc_m65, SIGNAL(readyReadStandardError()), - this, SLOT(readFromStderr())); - - QTimer *guiTimer = new QTimer(this); - connect(guiTimer, SIGNAL(timeout()), this, SLOT(guiUpdate())); - guiTimer->start(100); //Don't change the 100 ms! - - m_auto=false; - m_waterfallAvg = 1; - m_network = true; - m_txFirst=false; - m_txMute=false; - btxok=false; - m_restart=false; - m_transmitting=false; - m_killAll=false; - m_widebandDecode=false; - m_ntx=1; - m_myCall="K1JT"; - m_myGrid="FN20qi"; - m_appDir = QApplication::applicationDirPath(); - m_saveDir="/users/joe/map65/install/save"; - m_azelDir="/users/joe/map65/install/"; - m_txFreq=125; - m_setftx=0; - m_loopall=false; - m_startAnother=false; - m_saveAll=false; - m_onlyEME=false; - m_sec0=-1; - m_hsym0=-1; - m_palette="CuteSDR"; - m_map65RxLog=1; //Write Date and Time to all65.txt - m_nutc0=9999; - m_kb8rq=false; - m_NB=false; - m_mode="JT65B"; - m_mode65=2; - m_fs96000=true; - m_udpPort=50004; - m_adjustIQ=0; - m_applyIQcal=0; - m_colors="000066ff0000ffff00969696646464"; - - ui->xThermo->setFillBrush(Qt::green); - ui->yThermo->setFillBrush(Qt::magenta); - -#ifdef WIN32 - while(true) { - int iret=killbyname("m65.exe"); - if(iret == 603) break; - if(iret != 0) msgBox("KillByName return code: " + - QString::number(iret)); - } -#endif - - if(!mem_m65.attach()) { - if (!mem_m65.create(sizeof(datcom_))) { - msgBox("Unable to create shared memory segment."); - } - } - char *to = (char*)mem_m65.data(); - int size=sizeof(datcom_); - if(datcom_.newdat==0) { - int noffset = 4*4*5760000 + 4*4*322*32768 + 4*4*32768; - to += noffset; - size -= noffset; - } - memset(to,0,size); //Zero all decoding params in shared memory - - PaError paerr=Pa_Initialize(); //Initialize Portaudio - if(paerr!=paNoError) { - msgBox("Unable to initialize PortAudio."); - } - readSettings(); //Restore user's setup params - QFile lockFile(m_appDir + "/.lock"); //Create .lock so m65 will wait - lockFile.open(QIODevice::ReadWrite); - QFile quitFile(m_appDir + "/.lock"); - quitFile.remove(); - proc_m65.start(QDir::toNativeSeparators(m_appDir + "/m65 -s")); - - m_pbdecoding_style1="QPushButton{background-color: cyan; \ - border-style: outset; border-width: 1px; border-radius: 5px; \ - border-color: black; min-width: 5em; padding: 3px;}"; - m_pbmonitor_style="QPushButton{background-color: #00ff00; \ - border-style: outset; border-width: 1px; border-radius: 5px; \ - border-color: black; min-width: 5em; padding: 3px;}"; - m_pbAutoOn_style="QPushButton{background-color: red; \ - border-style: outset; border-width: 1px; border-radius: 5px; \ - border-color: black; min-width: 5em; padding: 3px;}"; - - genStdMsgs(""); - - on_actionAstro_Data_triggered(); //Create the other windows - on_actionWide_Waterfall_triggered(); - on_actionMessages_triggered(); - on_actionBand_Map_triggered(); - g_pMessages->setColors(m_colors); - g_pBandMap->setColors(m_colors); - g_pAstro->setFontSize(m_astroFont); - if(m_mode=="JT65A") on_actionJT65A_triggered(); - if(m_mode=="JT65B") on_actionJT65B_triggered(); - if(m_mode=="JT65C") on_actionJT65C_triggered(); - - future1 = new QFuture; - watcher1 = new QFutureWatcher; - connect(watcher1, SIGNAL(finished()),this,SLOT(diskDat())); - - future2 = new QFuture; - watcher2 = new QFutureWatcher; - connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished())); - -// Assign input device and start input thread - soundInThread.setInputDevice(m_paInDevice); - if(m_fs96000) soundInThread.setRate(96000.0); - if(!m_fs96000) soundInThread.setRate(95238.1); - soundInThread.setBufSize(10*7056); - soundInThread.setNetwork(m_network); - soundInThread.setPort(m_udpPort); - if(!m_xpol) soundInThread.setNrx(1); - if(m_xpol) soundInThread.setNrx(2); - soundInThread.start(QThread::HighestPriority); - - // Assign output device and start output thread - soundOutThread.setOutputDevice(m_paOutDevice); -// soundOutThread.start(QThread::HighPriority); - - m_monitoring=true; // Start with Monitoring ON - soundInThread.setMonitoring(m_monitoring); - m_diskData=false; - m_tol=500; - g_pWideGraph->setTol(m_tol); - g_pWideGraph->setFcal(m_fCal); - if(m_fs96000) g_pWideGraph->setFsample(96000); - if(!m_fs96000) g_pWideGraph->setFsample(95238); - g_pWideGraph->m_mult570=m_mult570; - g_pWideGraph->m_cal570=m_cal570; - if(m_initIQplus) g_pWideGraph->initIQplus(); - -// Create "m_worked", a dictionary of all calls in wsjt.log - QFile f("wsjt.log"); - f.open(QIODevice::ReadOnly); - QTextStream in(&f); - QString line,t,callsign; - for(int i=0; i<99999; i++) { - line=in.readLine(); - if(line.length()<=0) break; - t=line.mid(18,12); - callsign=t.mid(0,t.indexOf(",")); - m_worked[callsign]=true; - } - f.close(); - - if(ui->actionLinrad->isChecked()) on_actionLinrad_triggered(); - if(ui->actionCuteSDR->isChecked()) on_actionCuteSDR_triggered(); - if(ui->actionAFMHot->isChecked()) on_actionAFMHot_triggered(); - if(ui->actionBlue->isChecked()) on_actionBlue_triggered(); - // End of MainWindow constructor -} - - //--------------------------------------------------- MainWindow destructor -MainWindow::~MainWindow() -{ - writeSettings(); - if (soundInThread.isRunning()) { - soundInThread.quit(); - soundInThread.wait(3000); - } - if (soundOutThread.isRunning()) { - soundOutThread.quitExecution=true; - soundOutThread.wait(3000); - } - if(!m_decoderBusy) { - QFile lockFile(m_appDir + "/.lock"); - lockFile.remove(); - } - delete ui; -} - -//-------------------------------------------------------- writeSettings() -void MainWindow::writeSettings() -{ - QString inifile = m_appDir + "/map65.ini"; - QSettings settings(inifile, QSettings::IniFormat); - - settings.beginGroup("MainWindow"); - settings.setValue("geometry", saveGeometry()); - settings.setValue("MRUdir", m_path); - settings.setValue("TxFirst",m_txFirst); - settings.setValue("DXcall",ui->dxCallEntry->text()); - settings.setValue("DXgrid",ui->dxGridEntry->text()); - - if(g_pAstro->isVisible()) { - m_astroGeom = g_pAstro->geometry(); - settings.setValue("AstroGeom",m_astroGeom); - } - - if(g_pWideGraph->isVisible()) { - m_wideGraphGeom = g_pWideGraph->geometry(); - settings.setValue("WideGraphGeom",m_wideGraphGeom); - } - if(g_pMessages->isVisible()) { - m_messagesGeom = g_pMessages->geometry(); - settings.setValue("MessagesGeom",m_messagesGeom); - } - if(g_pBandMap->isVisible()) { - m_bandMapGeom = g_pBandMap->geometry(); - settings.setValue("BandMapGeom",m_bandMapGeom); - } - settings.endGroup(); - - settings.beginGroup("Common"); - settings.setValue("MyCall",m_myCall); - settings.setValue("MyGrid",m_myGrid); - settings.setValue("IDint",m_idInt); - settings.setValue("PTTport",m_pttPort); - settings.setValue("AstroFont",m_astroFont); - settings.setValue("Xpol",m_xpol); - settings.setValue("XpolX",m_xpolx); - settings.setValue("SaveDir",m_saveDir); - settings.setValue("AzElDir",m_azelDir); - settings.setValue("DXCCpfx",m_dxccPfx); - settings.setValue("Timeout",m_timeout); - settings.setValue("IQamp",m_IQamp); - settings.setValue("IQphase",m_IQphase); - settings.setValue("ApplyIQcal",m_applyIQcal); - settings.setValue("dPhi",m_dPhi); - settings.setValue("Fcal",m_fCal); - settings.setValue("Fadd",m_fAdd); - settings.setValue("NetworkInput", m_network); - settings.setValue("FSam96000", m_fs96000); - settings.setValue("SoundInIndex",m_nDevIn); - settings.setValue("paInDevice",m_paInDevice); - settings.setValue("SoundOutIndex",m_nDevOut); - settings.setValue("paOutDevice",m_paOutDevice); - settings.setValue("IQswap",m_IQswap); - settings.setValue("Plus10dB",m_10db); - settings.setValue("InitIQplus",m_initIQplus); - settings.setValue("UDPport",m_udpPort); - settings.setValue("PaletteCuteSDR",ui->actionCuteSDR->isChecked()); - settings.setValue("PaletteLinrad",ui->actionLinrad->isChecked()); - settings.setValue("PaletteAFMHot",ui->actionAFMHot->isChecked()); - settings.setValue("PaletteBlue",ui->actionBlue->isChecked()); - settings.setValue("Mode",m_mode); - settings.setValue("SaveNone",ui->actionNone->isChecked()); - settings.setValue("SaveAll",ui->actionSave_all->isChecked()); - settings.setValue("NDepth",m_ndepth); - settings.setValue("NEME",m_onlyEME); - settings.setValue("KB8RQ",m_kb8rq); - settings.setValue("NB",m_NB); - settings.setValue("NBslider",m_NBslider); - settings.setValue("GainX",(double)m_gainx); - settings.setValue("GainY",(double)m_gainy); - settings.setValue("PhaseX",(double)m_phasex); - settings.setValue("PhaseY",(double)m_phasey); - settings.setValue("Mult570",m_mult570); - settings.setValue("Cal570",m_cal570); - settings.setValue("Colors",m_colors); - settings.endGroup(); -} - -//---------------------------------------------------------- readSettings() -void MainWindow::readSettings() -{ - QString inifile = m_appDir + "/map65.ini"; - QSettings settings(inifile, QSettings::IniFormat); - settings.beginGroup("MainWindow"); - restoreGeometry(settings.value("geometry").toByteArray()); - ui->dxCallEntry->setText(settings.value("DXcall","").toString()); - ui->dxGridEntry->setText(settings.value("DXgrid","").toString()); - - m_astroGeom = settings.value("AstroGeom", QRect(71,390,227,403)).toRect(); - - m_wideGraphGeom = settings.value("WideGraphGeom", \ - QRect(45,30,1023,340)).toRect(); - m_messagesGeom = settings.value("MessagesGeom", \ - QRect(800,400,381,400)).toRect(); - m_bandMapGeom = settings.value("BandMapGeom", \ - QRect(280,400,142,400)).toRect(); - m_path = settings.value("MRUdir", m_appDir + "/save").toString(); - m_txFirst = settings.value("TxFirst",false).toBool(); - ui->txFirstCheckBox->setChecked(m_txFirst); - settings.endGroup(); - - settings.beginGroup("Common"); - m_myCall=settings.value("MyCall","").toString(); - m_myGrid=settings.value("MyGrid","").toString(); - m_idInt=settings.value("IDint",0).toInt(); - m_pttPort=settings.value("PTTport",0).toInt(); - m_astroFont=settings.value("AstroFont",20).toInt(); - m_xpol=settings.value("Xpol",false).toBool(); - ui->actionFind_Delta_Phi->setEnabled(m_xpol); - m_xpolx=settings.value("XpolX",false).toBool(); - m_saveDir=settings.value("SaveDir",m_appDir + "/save").toString(); - m_azelDir=settings.value("AzElDir",m_appDir).toString(); - m_dxccPfx=settings.value("DXCCpfx","").toString(); - m_timeout=settings.value("Timeout",20).toInt(); - m_IQamp=settings.value("IQamp",1.0000).toDouble(); - m_IQphase=settings.value("IQphase",0.0).toDouble(); - m_applyIQcal=settings.value("ApplyIQcal",0).toInt(); - ui->actionApply_IQ_Calibration->setChecked(m_applyIQcal!=0); - m_dPhi=settings.value("dPhi",0).toInt(); - m_fCal=settings.value("Fcal",0).toInt(); - m_fAdd=settings.value("FAdd",0).toDouble(); - soundInThread.setFadd(m_fAdd); - m_network = settings.value("NetworkInput",true).toBool(); - m_fs96000 = settings.value("FSam96000",true).toBool(); - m_nDevIn = settings.value("SoundInIndex", 0).toInt(); - m_paInDevice = settings.value("paInDevice",0).toInt(); - m_nDevOut = settings.value("SoundOutIndex", 0).toInt(); - m_paOutDevice = settings.value("paOutDevice",0).toInt(); - m_IQswap = settings.value("IQswap",false).toBool(); - m_10db = settings.value("Plus10dB",false).toBool(); - m_initIQplus = settings.value("InitIQplus",false).toBool(); - m_udpPort = settings.value("UDPport",50004).toInt(); - soundInThread.setSwapIQ(m_IQswap); - soundInThread.set10db(m_10db); - soundInThread.setPort(m_udpPort); - ui->actionCuteSDR->setChecked(settings.value( - "PaletteCuteSDR",true).toBool()); - ui->actionLinrad->setChecked(settings.value( - "PaletteLinrad",false).toBool()); - ui->actionAFMHot->setChecked(settings.value( - "PaletteAFMHot",false).toBool()); - ui->actionBlue->setChecked(settings.value( - "PaletteBlue",false).toBool()); - m_mode=settings.value("Mode","JT65B").toString(); - ui->actionNone->setChecked(settings.value("SaveNone",true).toBool()); - ui->actionSave_all->setChecked(settings.value("SaveAll",false).toBool()); - m_saveAll=ui->actionSave_all->isChecked(); - m_ndepth=settings.value("NDepth",0).toInt(); - m_onlyEME=settings.value("NEME",false).toBool(); - ui->actionOnly_EME_calls->setChecked(m_onlyEME); - m_kb8rq=settings.value("KB8RQ",false).toBool(); - ui->actionF4_sets_Tx6->setChecked(m_kb8rq); - m_NB=settings.value("NB",false).toBool(); - ui->NBcheckBox->setChecked(m_NB); - m_NBslider=settings.value("NBslider",40).toInt(); - ui->NBslider->setValue(m_NBslider); - m_gainx=settings.value("GainX",1.0).toFloat(); - m_gainy=settings.value("GainY",1.0).toFloat(); - m_phasex=settings.value("PhaseX",0.0).toFloat(); - m_phasey=settings.value("PhaseY",0.0).toFloat(); - m_mult570=settings.value("Mult570",2).toInt(); - m_cal570=settings.value("Cal570",0.0).toDouble(); - m_colors=settings.value("Colors","000066ff0000ffff00969696646464").toString(); - settings.endGroup(); - - if(!ui->actionLinrad->isChecked() && !ui->actionCuteSDR->isChecked() && - !ui->actionAFMHot->isChecked() && !ui->actionBlue->isChecked()) { - on_actionLinrad_triggered(); - ui->actionLinrad->setChecked(true); - } - if(m_ndepth==0) ui->actionNo_Deep_Search->setChecked(true); - if(m_ndepth==1) ui->actionNormal_Deep_Search->setChecked(true); - if(m_ndepth==2) ui->actionAggressive_Deep_Search->setChecked(true); -} - -//-------------------------------------------------------------- dataSink() -void MainWindow::dataSink(int k) -{ - static float s[NFFT],splot[NFFT]; - static int n=0; - static int ihsym=0; - static int nzap=0; - static int n60z=0; - static int nkhz; - static int nfsample=96000; - static int nxpol=0; - static float fgreen; - static int ndiskdat; - static int nb; - static int nadj=0; - static float px=0.0,py=0.0; - static uchar lstrong[1024]; - static float rejectx; - static float rejecty; - static float slimit; - - - if(m_diskData) { - ndiskdat=1; - datcom_.ndiskdat=1; - } else { - ndiskdat=0; - datcom_.ndiskdat=0; - } -// Get x and y power, polarized spectrum, nkhz, and ihsym - nb=0; - if(m_NB) nb=1; - nfsample=96000; - if(!m_fs96000) nfsample=95238; - nxpol=0; - if(m_xpol) nxpol=1; - fgreen=(float)g_pWideGraph->fGreen(); - nadj++; - if(m_adjustIQ==0) nadj=0; - symspec_(&k, &nxpol, &ndiskdat, &nb, &m_NBslider, &m_dPhi, &nfsample, - &fgreen, &m_adjustIQ, &m_applyIQcal, &m_gainx, &m_gainy, &m_phasex, - &m_phasey, &rejectx, &rejecty, &px, &py, s, &nkhz, - &ihsym, &nzap, &slimit, lstrong); - QString t; - m_pctZap=nzap/178.3; - if(m_xpol) t.sprintf(" Rx noise: %5.1f %5.1f %5.1f %% ",px,py,m_pctZap); - if(!m_xpol) t.sprintf(" Rx noise: %5.1f %5.1f %% ",px,m_pctZap); - lab4->setText(t); - ui->xThermo->setValue((double)px); //Update the bargraphs - ui->yThermo->setValue((double)py); - if(m_monitoring || m_diskData) { - g_pWideGraph->dataSink2(s,nkhz,ihsym,m_diskData,lstrong); - } - - if(nadj == 10) { - if(m_xpol) { - t.sprintf("Amp: %6.4f %6.4f Phase: %6.4f %6.4f", - m_gainx,m_gainy,m_phasex,m_phasey); - } else { - t.sprintf("Amp: %6.4f Phase: %6.4f",m_gainx,m_phasex); - } - ui->decodedTextBrowser->append(t); - m_adjustIQ=0; - } - - //Average over specified number of spectra - if (n==0) { - for (int i=0; i=m_waterfallAvg) { - for (int i=0; isetFuture(*future2); - } - } - soundInThread.m_dataSinkBusy=false; -} - -void MainWindow::showSoundInError(const QString& errorMsg) - {QMessageBox::critical(this, tr("Error in SoundIn"), errorMsg);} - -void MainWindow::showStatusMessage(const QString& statusMsg) - {statusBar()->showMessage(statusMsg);} - -void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog -{ - DevSetup dlg(this); - dlg.m_myCall=m_myCall; - dlg.m_myGrid=m_myGrid; - dlg.m_idInt=m_idInt; - dlg.m_pttPort=m_pttPort; - dlg.m_astroFont=m_astroFont; - dlg.m_xpol=m_xpol; - dlg.m_xpolx=m_xpolx; - dlg.m_saveDir=m_saveDir; - dlg.m_azelDir=m_azelDir; - dlg.m_dxccPfx=m_dxccPfx; - dlg.m_timeout=m_timeout; - dlg.m_dPhi=m_dPhi; - dlg.m_fCal=m_fCal; - dlg.m_fAdd=m_fAdd; - dlg.m_network=m_network; - dlg.m_fs96000=m_fs96000; - dlg.m_nDevIn=m_nDevIn; - dlg.m_nDevOut=m_nDevOut; - dlg.m_udpPort=m_udpPort; - dlg.m_IQswap=m_IQswap; - dlg.m_10db=m_10db; - dlg.m_initIQplus=m_initIQplus; - dlg.m_cal570=m_cal570; - dlg.m_mult570=m_mult570; - dlg.m_colors=m_colors; - - dlg.initDlg(); - if(dlg.exec() == QDialog::Accepted) { - m_myCall=dlg.m_myCall; - m_myGrid=dlg.m_myGrid; - m_idInt=dlg.m_idInt; - m_pttPort=dlg.m_pttPort; - m_astroFont=dlg.m_astroFont; - if(g_pAstro->isVisible()) g_pAstro->setFontSize(m_astroFont); - m_xpol=dlg.m_xpol; - ui->actionFind_Delta_Phi->setEnabled(m_xpol); - m_xpolx=dlg.m_xpolx; - m_saveDir=dlg.m_saveDir; - m_azelDir=dlg.m_azelDir; - m_dxccPfx=dlg.m_dxccPfx; - m_timeout=dlg.m_timeout; - m_dPhi=dlg.m_dPhi; - m_fCal=dlg.m_fCal; - m_fAdd=dlg.m_fAdd; - g_pWideGraph->setFcal(m_fCal); - m_fs96000=dlg.m_fs96000; - m_network=dlg.m_network; - m_nDevIn=dlg.m_nDevIn; - m_paInDevice=dlg.m_paInDevice; - m_nDevOut=dlg.m_nDevOut; - m_paOutDevice=dlg.m_paOutDevice; - m_udpPort=dlg.m_udpPort; - m_IQswap=dlg.m_IQswap; - m_10db=dlg.m_10db; - m_initIQplus=dlg.m_initIQplus; - m_colors=dlg.m_colors; - g_pMessages->setColors(m_colors); - g_pBandMap->setColors(m_colors); - m_cal570=dlg.m_cal570; - m_mult570=dlg.m_mult570; - g_pWideGraph->m_mult570=m_mult570; - g_pWideGraph->m_cal570=m_cal570; - soundInThread.setSwapIQ(m_IQswap); - soundInThread.set10db(m_10db); - - if(dlg.m_restartSoundIn) { - soundInThread.quit(); - soundInThread.wait(1000); - soundInThread.setNetwork(m_network); - if(m_fs96000) soundInThread.setRate(96000.0); - if(!m_fs96000) soundInThread.setRate(95238.1); - soundInThread.setFadd(m_fAdd); - if(!m_xpol) soundInThread.setNrx(1); - if(m_xpol) soundInThread.setNrx(2); - soundInThread.setInputDevice(m_paInDevice); - soundInThread.start(QThread::HighestPriority); - } - - if(dlg.m_restartSoundOut) { - soundOutThread.quitExecution=true; - soundOutThread.wait(1000); - soundOutThread.setOutputDevice(m_paOutDevice); -// soundOutThread.start(QThread::HighPriority); - } - } -} - -void MainWindow::on_monitorButton_clicked() //Monitor -{ - m_monitoring=true; - soundInThread.setMonitoring(true); - m_diskData=false; -} -void MainWindow::on_actionLinrad_triggered() //Linrad palette -{ - if(g_pWideGraph != NULL) g_pWideGraph->setPalette("Linrad"); -} - -void MainWindow::on_actionCuteSDR_triggered() //CuteSDR palette -{ - if(g_pWideGraph != NULL) g_pWideGraph->setPalette("CuteSDR"); -} - -void MainWindow::on_actionAFMHot_triggered() -{ - if(g_pWideGraph != NULL) g_pWideGraph->setPalette("AFMHot"); -} - -void MainWindow::on_actionBlue_triggered() -{ - if(g_pWideGraph != NULL) g_pWideGraph->setPalette("Blue"); -} - -void MainWindow::on_actionAbout_triggered() //Display "About" -{ - CAboutDlg dlg(this,Program_Title_Version); - dlg.exec(); -} - -void MainWindow::on_autoButton_clicked() //Auto -{ - m_auto = !m_auto; - if(m_auto) { - ui->autoButton->setStyleSheet(m_pbAutoOn_style); - ui->autoButton->setText("Auto is ON"); - } else { - btxok=false; - ui->autoButton->setStyleSheet(""); - ui->autoButton->setText("Auto is OFF"); - on_monitorButton_clicked(); - } -} - -void MainWindow::on_stopTxButton_clicked() //Stop Tx -{ - if(m_auto) on_autoButton_clicked(); - btxok=false; -} - -void MainWindow::keyPressEvent( QKeyEvent *e ) //keyPressEvent -{ - switch(e->key()) - { - case Qt::Key_F3: - m_txMute=!m_txMute; - break; - case Qt::Key_F4: - ui->dxCallEntry->setText(""); - ui->dxGridEntry->setText(""); - if(m_kb8rq) { - m_ntx=6; - ui->txrb6->setChecked(true); - } - case Qt::Key_F6: - if(e->modifiers() & Qt::ShiftModifier) { - on_actionDecode_remaining_files_in_directory_triggered(); - } - break; - case Qt::Key_F11: - if(e->modifiers() & Qt::ShiftModifier) { - } else { - int n0=g_pWideGraph->DF(); - int n=(n0 + 10000) % 5; - if(n==0) n=5; - g_pWideGraph->setDF(n0-n); - } - break; - case Qt::Key_F12: - if(e->modifiers() & Qt::ShiftModifier) { - } else { - int n0=g_pWideGraph->DF(); - int n=(n0 + 10000) % 5; - if(n==0) n=5; - g_pWideGraph->setDF(n0+n); - } - break; - case Qt::Key_G: - if(e->modifiers() & Qt::AltModifier) { - genStdMsgs(""); - break; - } - case Qt::Key_L: - if(e->modifiers() & Qt::ControlModifier) { - lookup(); - genStdMsgs(""); - break; - } - } -} - -void MainWindow::bumpDF(int n) //bumpDF() -{ - if(n==11) { - int n0=g_pWideGraph->DF(); - int n=(n0 + 10000) % 5; - if(n==0) n=5; - g_pWideGraph->setDF(n0-n); - } - if(n==12) { - int n0=g_pWideGraph->DF(); - int n=(n0 + 10000) % 5; - if(n==0) n=5; - g_pWideGraph->setDF(n0+n); - } -} - -bool MainWindow::eventFilter(QObject *object, QEvent *event) //eventFilter() -{ - if (event->type() == QEvent::KeyPress) { - //Use the event in parent using its keyPressEvent() - QKeyEvent *keyEvent = static_cast(event); - MainWindow::keyPressEvent(keyEvent); - return QObject::eventFilter(object, event); - } - return QObject::eventFilter(object, event); -} - -void MainWindow::createStatusBar() //createStatusBar -{ - lab1 = new QLabel("Receiving"); - lab1->setAlignment(Qt::AlignHCenter); - lab1->setMinimumSize(QSize(80,10)); - lab1->setStyleSheet("QLabel{background-color: #00ff00}"); - lab1->setFrameStyle(QFrame::Panel | QFrame::Sunken); - statusBar()->addWidget(lab1); - - lab2 = new QLabel("QSO freq: 125"); - lab2->setAlignment(Qt::AlignHCenter); - lab2->setMinimumSize(QSize(90,10)); - lab2->setFrameStyle(QFrame::Panel | QFrame::Sunken); - statusBar()->addWidget(lab2); - - lab3 = new QLabel("QSO DF: 0"); - lab3->setAlignment(Qt::AlignHCenter); - lab3->setMinimumSize(QSize(80,10)); - lab3->setFrameStyle(QFrame::Panel | QFrame::Sunken); - statusBar()->addWidget(lab3); - - lab4 = new QLabel(""); - lab4->setAlignment(Qt::AlignHCenter); - lab4->setMinimumSize(QSize(80,10)); - lab4->setFrameStyle(QFrame::Panel | QFrame::Sunken); - statusBar()->addWidget(lab4); - - lab5 = new QLabel(""); - lab5->setAlignment(Qt::AlignHCenter); - lab5->setMinimumSize(QSize(50,10)); - lab5->setFrameStyle(QFrame::Panel | QFrame::Sunken); - statusBar()->addWidget(lab5); -} - -void MainWindow::on_tolSpinBox_valueChanged(int i) //tolSpinBox -{ - static int ntol[] = {10,20,50,100,200,500,1000}; - m_tol=ntol[i]; - g_pWideGraph->setTol(m_tol); - ui->labTol1->setText(QString::number(ntol[i])); -} - -void MainWindow::on_actionExit_triggered() //Exit() -{ - OnExit(); -} - -void MainWindow::closeEvent(QCloseEvent*) -{ - OnExit(); -} - -void MainWindow::OnExit() -{ - g_pWideGraph->saveSettings(); - m_killAll=true; - mem_m65.detach(); - QFile quitFile(m_appDir + "/.quit"); - quitFile.open(QIODevice::ReadWrite); - QFile lockFile(m_appDir + "/.lock"); - lockFile.remove(); // Allow m65 to terminate - bool b=proc_m65.waitForFinished(1000); - if(!b) proc_m65.kill(); - quitFile.remove(); - qApp->exit(0); // Exit the event loop -} - -void MainWindow::on_stopButton_clicked() //stopButton -{ - m_monitoring=false; - soundInThread.setMonitoring(m_monitoring); - m_loopall=false; -} - -void MainWindow::msgBox(QString t) //msgBox -{ - msgBox0.setText(t); - msgBox0.exec(); -} - -void MainWindow::stub() //stub() -{ - msgBox("Not yet implemented."); -} - -void MainWindow::on_actionOnline_Users_Guide_triggered() //Display manual -{ - QDesktopServices::openUrl(QUrl( - "http://www.physics.princeton.edu/pulsar/K1JT/MAP65_Beta_Release.pdf", - QUrl::TolerantMode)); -} - -void MainWindow::on_actionAstro_Data_triggered() //Display Astro -{ - if(g_pAstro==NULL) { - g_pAstro = new Astro(0); - g_pAstro->setWindowTitle("Astronomical Data"); - Qt::WindowFlags flags = Qt::Dialog | Qt::WindowCloseButtonHint | - Qt::WindowMinimizeButtonHint; - g_pAstro->setWindowFlags(flags); - g_pAstro->setGeometry(m_astroGeom); - } - g_pAstro->show(); -} - -void MainWindow::on_actionWide_Waterfall_triggered() //Display Waterfalls -{ - if(g_pWideGraph==NULL) { - g_pWideGraph = new WideGraph(0); - g_pWideGraph->setWindowTitle("Wide Graph"); - g_pWideGraph->setGeometry(m_wideGraphGeom); - Qt::WindowFlags flags = Qt::WindowCloseButtonHint | - Qt::WindowMinimizeButtonHint; - g_pWideGraph->setWindowFlags(flags); - connect(g_pWideGraph, SIGNAL(freezeDecode2(int)),this, - SLOT(freezeDecode(int))); - connect(g_pWideGraph, SIGNAL(f11f12(int)),this, - SLOT(bumpDF(int))); - } - g_pWideGraph->show(); -} - -void MainWindow::on_actionBand_Map_triggered() //Display BandMap -{ - if(g_pBandMap==NULL) { - g_pBandMap = new BandMap(0); - g_pBandMap->setWindowTitle("Band Map"); - Qt::WindowFlags flags = Qt::Dialog | Qt::WindowCloseButtonHint | - Qt::WindowMinimizeButtonHint; - g_pBandMap->setWindowFlags(flags); - g_pBandMap->setGeometry(m_bandMapGeom); - } - g_pBandMap->show(); -} - -void MainWindow::on_actionMessages_triggered() //Display Messages -{ - if(g_pMessages==NULL) { - g_pMessages = new Messages(0); - g_pMessages->setWindowTitle("Messages"); - Qt::WindowFlags flags = Qt::Dialog | Qt::WindowCloseButtonHint | - Qt::WindowMinimizeButtonHint; - g_pMessages->setWindowFlags(flags); - g_pMessages->setGeometry(m_messagesGeom); - connect(g_pMessages, SIGNAL(click2OnCallsign(QString, QString)),this, - SLOT(doubleClickOnMessages(QString, QString))); - } - g_pMessages->show(); -} - -void MainWindow::on_actionOpen_triggered() //Open File -{ - m_monitoring=false; - soundInThread.setMonitoring(m_monitoring); - QString fname; - if(m_xpol) { - fname=QFileDialog::getOpenFileName(this, "Open File", m_path, - "MAP65 Files (*.tf2)"); - } else { - fname=QFileDialog::getOpenFileName(this, "Open File", m_path, - "MAP65 Files (*.iq)"); - } - if(fname != "") { - m_path=fname; - int i; - i=fname.indexOf(".iq") - 11; - if(m_xpol) i=fname.indexOf(".tf2") - 11; - if(i>=0) { - lab1->setStyleSheet("QLabel{background-color: #66ff66}"); - lab1->setText(" " + fname.mid(i,15) + " "); - } - on_stopButton_clicked(); - m_diskData=true; - int dbDgrd=0; - if(m_myCall=="K1JT" and m_idInt<0) dbDgrd=m_idInt; - *future1 = QtConcurrent::run(getfile, fname, m_xpol, dbDgrd); - watcher1->setFuture(*future1); - } -} - -void MainWindow::on_actionOpen_next_in_directory_triggered() //Open Next -{ - int i,len; - QFileInfo fi(m_path); - QStringList list; - list= fi.dir().entryList().filter(".iq"); - len=14; - if(m_xpol) { - list= fi.dir().entryList().filter(".tf2"); - len=15; - } - for (i = 0; i < list.size()-1; ++i) { - if(i==list.size()-2) m_loopall=false; - if(list.at(i)==m_path.right(len)) { - int n=m_path.length(); - QString fname=m_path.replace(n-len,len,list.at(i+1)); - m_path=fname; - int i; - i=fname.indexOf(".iq") - 11; - if(m_xpol) i=fname.indexOf(".tf2") - 11; - if(i>=0) { - lab1->setStyleSheet("QLabel{background-color: #66ff66}"); - lab1->setText(" " + fname.mid(i,len) + " "); - } - m_diskData=true; - int dbDgrd=0; - if(m_myCall=="K1JT" and m_idInt<0) dbDgrd=m_idInt; - *future1 = QtConcurrent::run(getfile, fname, m_xpol, dbDgrd); - watcher1->setFuture(*future1); - return; - } - } -} - //Open all remaining files -void MainWindow::on_actionDecode_remaining_files_in_directory_triggered() -{ - m_loopall=true; - on_actionOpen_next_in_directory_triggered(); -} - -void MainWindow::diskDat() //diskDat() -{ - double hsym; - //These may be redundant?? - m_diskData=true; - datcom_.newdat=1; - - if(m_fs96000) hsym=2048.0*96000.0/11025.0; //Samples per JT65 half-symbol - if(!m_fs96000) hsym=2048.0*95238.1/11025.0; - for(int i=0; i<281; i++) { // Do the half-symbol FFTs - int k = i*hsym + 2048.5; - dataSink(k); - if(i%10 == 0) qApp->processEvents(); //Keep the GUI responsive - } -} - -void MainWindow::diskWriteFinished() //diskWriteFinished -{ -// qDebug() << "diskWriteFinished"; -} - //Delete ../save/*.tf2 -void MainWindow::on_actionDelete_all_tf2_files_in_SaveDir_triggered() -{ - int i; - QString fname; - int ret = QMessageBox::warning(this, "Confirm Delete", - "Are you sure you want to delete all *.tf2 and *.iq files in\n" + - QDir::toNativeSeparators(m_saveDir) + " ?", - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - if(ret==QMessageBox::Yes) { - QDir dir(m_saveDir); - QStringList files=dir.entryList(QDir::Files); - QList::iterator f; - for(f=files.begin(); f!=files.end(); ++f) { - fname=*f; - i=(fname.indexOf(".tf2")); - if(i==11) dir.remove(fname); - i=(fname.indexOf(".iq")); - if(i==11) dir.remove(fname); - } - } -} - //Clear BandMap and Messages windows -void MainWindow::on_actionErase_Band_Map_and_Messages_triggered() -{ - g_pBandMap->setText(""); - g_pMessages->setText(""); - m_map65RxLog |= 4; -} - -void MainWindow::on_actionFind_Delta_Phi_triggered() //Find dPhi -{ - m_map65RxLog |= 8; - on_DecodeButton_clicked(); -} - -void MainWindow::on_actionF4_sets_Tx6_triggered() //F4 sets Tx6 -{ - m_kb8rq = !m_kb8rq; -} - -void MainWindow::on_actionOnly_EME_calls_triggered() //EME calls only -{ - m_onlyEME = ui->actionOnly_EME_calls->isChecked(); -} - -void MainWindow::on_actionNo_shorthands_if_Tx1_triggered() -{ - stub(); -} - -void MainWindow::on_actionNo_Deep_Search_triggered() //No Deep Search -{ - m_ndepth=0; -} - -void MainWindow::on_actionNormal_Deep_Search_triggered() //Normal DS -{ - m_ndepth=1; -} - -void MainWindow::on_actionAggressive_Deep_Search_triggered() //Aggressive DS -{ - m_ndepth=2; -} - -void MainWindow::on_actionNone_triggered() //Save None -{ - m_saveAll=false; -} - -// ### Implement "Save Last" here? ### - -void MainWindow::on_actionSave_all_triggered() //Save All -{ - m_saveAll=true; -} - //Display list of keyboard shortcuts -void MainWindow::on_actionKeyboard_shortcuts_triggered() -{ - stub(); -} - //Display list of mouse commands -void MainWindow::on_actionSpecial_mouse_commands_triggered() -{ - stub(); -} - //Diaplay list of Add-On pfx/sfx -void MainWindow::on_actionAvailable_suffixes_and_add_on_prefixes_triggered() -{ - stub(); -} - -void MainWindow::on_DecodeButton_clicked() //Decode request -{ - int n=m_sec0%60; - if(m_monitoring and n>47 and (n<52 or m_decoderBusy)) return; - if(!m_decoderBusy) { - datcom_.newdat=0; - datcom_.nagain=1; - decode(); - } -} - -void MainWindow::freezeDecode(int n) //freezeDecode() -{ - if(n==2) { - ui->tolSpinBox->setValue(5); - datcom_.ntol=m_tol; - datcom_.mousedf=0; - } else { - ui->tolSpinBox->setValue(3); - datcom_.ntol=m_tol; - } - if(!m_decoderBusy) { - datcom_.nagain=1; - datcom_.newdat=0; - decode(); - } -} - -void MainWindow::decode() //decode() -{ - ui->DecodeButton->setStyleSheet(m_pbdecoding_style1); - if(datcom_.nagain==0 && (!m_diskData)) { - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int imin=ms/60000; - int ihr=imin/60; - imin=imin % 60; - datcom_.nutc=100*ihr + imin; - } - - datcom_.idphi=m_dPhi; - datcom_.mousedf=g_pWideGraph->DF(); - datcom_.mousefqso=g_pWideGraph->QSOfreq(); - datcom_.ndepth=m_ndepth; - datcom_.ndiskdat=0; - if(m_diskData) datcom_.ndiskdat=1; - datcom_.neme=0; - if(ui->actionOnly_EME_calls->isChecked()) datcom_.neme=1; - - int ispan=int(g_pWideGraph->fSpan()); - if(ispan%2 == 1) ispan++; - int ifc=int(1000.0*(datcom_.fcenter - int(datcom_.fcenter))+0.5); - int nfa=g_pWideGraph->nStartFreq(); - int nfb=nfa+ispan; - int nfshift=nfa + ispan/2 - ifc; - - datcom_.nfa=nfa; - datcom_.nfb=nfb; - datcom_.nfcal=m_fCal; - datcom_.nfshift=nfshift; - datcom_.mcall3=0; - if(m_call3Modified) datcom_.mcall3=1; - datcom_.ntimeout=m_timeout; - datcom_.ntol=m_tol; - datcom_.nxant=0; - if(m_xpolx) datcom_.nxant=1; - if(datcom_.nutc < m_nutc0) m_map65RxLog |= 1; //Date and Time to all65.txt - m_nutc0=datcom_.nutc; - datcom_.map65RxLog=m_map65RxLog; - datcom_.nfsample=96000; - if(!m_fs96000) datcom_.nfsample=95238; - datcom_.nxpol=0; - if(m_xpol) datcom_.nxpol=1; - datcom_.mode65=m_mode65; - - QString mcall=(m_myCall+" ").mid(0,12); - QString mgrid=(m_myGrid+" ").mid(0,6); - QString hcall=(ui->dxCallEntry->text()+" ").mid(0,12); - QString hgrid=(ui->dxGridEntry->text()+" ").mid(0,6); - - strncpy(datcom_.mycall, mcall.toAscii(), 12); - strncpy(datcom_.mygrid, mgrid.toAscii(), 6); - strncpy(datcom_.hiscall, hcall.toAscii(), 12); - strncpy(datcom_.hisgrid, hgrid.toAscii(), 6); - strncpy(datcom_.datetime, m_dateTime.toAscii(), 20); - - //newdat=1 ==> this is new data, must do the big FFT - //nagain=1 ==> decode only at fQSO +/- Tol - - char *to = (char*)mem_m65.data(); - char *from = (char*) datcom_.d4; - int size=sizeof(datcom_); - if(datcom_.newdat==0) { - int noffset = 4*4*5760000 + 4*4*322*32768 + 4*4*32768; - to += noffset; - from += noffset; - size -= noffset; - } - memcpy(to, from, qMin(mem_m65.size(), size)); - datcom_.nagain=0; - datcom_.ndiskdat=0; - m_call3Modified=false; - - QFile lockFile(m_appDir + "/.lock"); // Allow m65 to start - lockFile.remove(); - - decodeBusy(true); -} - -void MainWindow::m65_error() //m65_error -{ - if(!m_killAll) { - msgBox("Error starting or running\n" + m_appDir + "/m65 -s"); - exit(1); - } -} - -void MainWindow::readFromStderr() //readFromStderr -{ - QByteArray t=proc_m65.readAllStandardError(); - msgBox(t); -} - - -void MainWindow::readFromStdout() //readFromStdout -{ - while(proc_m65.canReadLine()) - { - QByteArray t=proc_m65.readLine(); - if(t.indexOf("") >= 0) { - if(m_widebandDecode) { - g_pMessages->setText(m_messagesText); - g_pBandMap->setText(m_bandmapText); - m_widebandDecode=false; - } - QFile lockFile(m_appDir + "/.lock"); - lockFile.open(QIODevice::ReadWrite); - ui->DecodeButton->setStyleSheet(""); - decodeBusy(false); - m_map65RxLog=0; - m_startAnother=m_loopall; - return; - } - - if(t.indexOf("!") >= 0) { - int n=t.length(); - if(n>=30) ui->decodedTextBrowser->append(t.mid(1,n-3)); - if(n<30) ui->decodedTextBrowser->append(t.mid(1,n-3)); - n=ui->decodedTextBrowser->verticalScrollBar()->maximum(); - ui->decodedTextBrowser->verticalScrollBar()->setValue(n); - m_messagesText=""; - m_bandmapText=""; - } - - if(t.indexOf("@") >= 0) { - m_messagesText += t.mid(1); - m_widebandDecode=true; - } - - if(t.indexOf("&") >= 0) { - QString q(t); - QString callsign=q.mid(5); - callsign=callsign.mid(0,callsign.indexOf(" ")); - if(callsign.length()>2) { - if(m_worked[callsign]) { - q=q.mid(1,4) + " " + q.mid(5); - } else { - q=q.mid(1,4) + " *" + q.mid(5); - } - m_bandmapText += q; - } - } - } -} - -void MainWindow::on_EraseButton_clicked() //Erase -{ - ui->decodedTextBrowser->clear(); -} - -void MainWindow::decodeBusy(bool b) //decodeBusy() -{ - m_decoderBusy=b; - ui->DecodeButton->setEnabled(!b); - ui->actionOpen->setEnabled(!b); - ui->actionOpen_next_in_directory->setEnabled(!b); - ui->actionDecode_remaining_files_in_directory->setEnabled(!b); -} - -//------------------------------------------------------------- //guiUpdate() -void MainWindow::guiUpdate() -{ - static int iptt0=0; - static int iptt=0; - static bool btxok0=false; - static int nc0=1; - static int nc1=1; - static char msgsent[23]; - static int nsendingsh=0; - int khsym=0; - - double tx1=0.0; - double tx2=126.0*4096.0/11025.0 + 1.8; //### depend on TxDelay? ### - - if(!m_txFirst) { - tx1 += 60.0; - tx2 += 60.0; - } - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int nsec=ms/1000; - double tsec=0.001*ms; - double t120=fmod(tsec,120.0); - bool bTxTime = t120 >= tx1 && t120 < tx2; - - if(m_auto) { - if(bTxTime and iptt==0 and !m_txMute) { - int itx=1; - int ierr = ptt_(&m_pttPort,&itx,&iptt); // Raise PTT - if(ierr != 0) { - on_stopTxButton_clicked(); - char s[18]; - sprintf(s,"Cannot open COM%d",m_pttPort); - msgBox(s); - } - if(!soundOutThread.isRunning()) { - soundOutThread.start(QThread::HighPriority); - } - } - if(!bTxTime || m_txMute) { - btxok=false; - } - } - -// Calculate Tx waveform when needed - if((iptt==1 && iptt0==0) || m_restart) { - char message[23]; - QByteArray ba; - if(m_ntx == 1) ba=ui->tx1->text().toLocal8Bit(); - if(m_ntx == 2) ba=ui->tx2->text().toLocal8Bit(); - if(m_ntx == 3) ba=ui->tx3->text().toLocal8Bit(); - if(m_ntx == 4) ba=ui->tx4->text().toLocal8Bit(); - if(m_ntx == 5) ba=ui->tx5->text().toLocal8Bit(); - if(m_ntx == 6) ba=ui->tx6->text().toLocal8Bit(); - - ba2msg(ba,message); - int len1=22; - int mode65=m_mode65; - double samfac=1.0; - - gen65_(message,&mode65,&samfac,&nsendingsh,msgsent,iwave,&nwave,len1,len1); - msgsent[22]=0; - - if(m_restart) { - QFile f("map65_tx.log"); - f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append); - QTextStream out(&f); - out << QDateTime::currentDateTimeUtc().toString("yyyy-MMM-dd hh:mm") - << " Tx message: " << QString::fromAscii(msgsent) << endl; - f.close(); - } - - m_restart=false; - } - -// If PTT was just raised, start a countdown for raising TxOK: - if(iptt==1 && iptt0==0) nc1=-9; // TxDelay = 0.8 s - if(nc1 <= 0) nc1++; - if(nc1 == 0) { - ui->xThermo->setValue(0.0); //Set the Thermos to zero - ui->yThermo->setValue(0.0); - m_monitoring=false; - soundInThread.setMonitoring(false); - btxok=true; - m_transmitting=true; - - QFile f("map65_tx.log"); - f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append); - QTextStream out(&f); - out << QDateTime::currentDateTimeUtc().toString("yyyy-MMM-dd hh:mm") - << " Tx message: " << QString::fromAscii(msgsent) << endl; - f.close(); - } - -// If btxok was just lowered, start a countdown for lowering PTT - if(!btxok && btxok0 && iptt==1) nc0=-11; //RxDelay = 1.0 s - if(nc0 <= 0) nc0++; - if(nc0 == 0) { - int itx=0; - ptt_(&m_pttPort,&itx,&iptt); // Lower PTT - if(!m_txMute) soundOutThread.quitExecution=true; - m_transmitting=false; - if(m_auto) { - m_monitoring=true; - soundInThread.setMonitoring(m_monitoring); - } - } - - if(iptt == 0 && !btxok) { - // sending="" - // nsendingsh=0 - } - - if(m_monitoring) { - ui->monitorButton->setStyleSheet(m_pbmonitor_style); - } else { - ui->monitorButton->setStyleSheet(""); - } - - lab2->setText("QSO Freq: " + QString::number(g_pWideGraph->QSOfreq())); - lab3->setText("QSO DF: " + QString::number(g_pWideGraph->DF())); - - if(m_startAnother) { - m_startAnother=false; - on_actionOpen_next_in_directory_triggered(); - } - - if(nsec != m_sec0) { //Once per second - soundInThread.setForceCenterFreqMHz(g_pWideGraph->m_dForceCenterFreq); - soundInThread.setForceCenterFreqBool(g_pWideGraph->m_bForceCenterFreq); - - if(m_pctZap>30.0 and !m_transmitting) { - lab4->setStyleSheet("QLabel{background-color: #ff0000}"); - } else { - lab4->setStyleSheet(""); - } - - if(m_transmitting) { - if(nsendingsh==1) { - lab1->setStyleSheet("QLabel{background-color: #66ffff}"); - } else if(nsendingsh==-1) { - lab1->setStyleSheet("QLabel{background-color: #ffccff}"); - } else { - lab1->setStyleSheet("QLabel{background-color: #ffff33}"); - } - char s[37]; - sprintf(s,"Tx: %s",msgsent); - lab1->setText(s); - } else if(m_monitoring) { - lab1->setStyleSheet("QLabel{background-color: #00ff00}"); - m_nrx=soundInThread.nrx(); - khsym=soundInThread.mhsym(); - QString t; - if(m_network) { - if(m_nrx==-1) t="F1"; - if(m_nrx==1) t="I1"; - if(m_nrx==-2) t="F2"; - if(m_nrx==+2) t="I2"; - } else { - if(m_nrx==1) t="S1"; - if(m_nrx==2) t="S2"; - } - if((abs(m_nrx)==1 and m_xpol) or (abs(m_nrx)==2 and !m_xpol)) - lab1->setStyleSheet("QLabel{background-color: #ff1493}"); - if(khsym==m_hsym0) { - t="Nil"; - lab1->setStyleSheet("QLabel{background-color: #ffc0cb}"); - } - lab1->setText("Receiving " + t); - } else if (!m_diskData) { - lab1->setStyleSheet(""); - lab1->setText(""); - } - - QDateTime t = QDateTime::currentDateTimeUtc(); - int fQSO=g_pWideGraph->QSOfreq(); - g_pAstro->astroUpdate(t, m_myGrid, m_hisGrid, fQSO, m_setftx, - m_txFreq, m_azelDir); - m_setftx=0; - QString utc = " " + t.time().toString() + " "; - ui->labUTC->setText(utc); - if((!m_monitoring and !m_diskData) or (khsym==m_hsym0)) { - ui->xThermo->setValue(0.0); // Set Rx levels to 0 - ui->yThermo->setValue(0.0); - lab4->setText(" Rx noise: 0.0 0.0 0.0% "); - } - m_hsym0=khsym; - m_sec0=nsec; - } - iptt0=iptt; - btxok0=btxok; -} - -void MainWindow::ba2msg(QByteArray ba, char message[]) //ba2msg() -{ - bool eom; - eom=false; - for(int i=0;i<22; i++) { - if((int)ba[i] == 0) eom=true; - if(eom) { - message[i]=32; - } else { - message[i]=ba[i]; - } - } - message[22]=0; -} - -void MainWindow::on_txFirstCheckBox_stateChanged(int nstate) //TxFirst -{ - m_txFirst = (nstate==2); -} - -void MainWindow::set_ntx(int n) //set_ntx() -{ - m_ntx=n; -} - -void MainWindow::on_txb1_clicked() //txb1 -{ - m_ntx=1; - ui->txrb1->setChecked(true); - m_restart=true; -} - -void MainWindow::on_txb2_clicked() //txb2 -{ - m_ntx=2; - ui->txrb2->setChecked(true); - m_restart=true; -} - -void MainWindow::on_txb3_clicked() //txb3 -{ - m_ntx=3; - ui->txrb3->setChecked(true); - m_restart=true; -} - -void MainWindow::on_txb4_clicked() //txb4 -{ - m_ntx=4; - ui->txrb4->setChecked(true); - m_restart=true; -} - -void MainWindow::on_txb5_clicked() //txb5 -{ - m_ntx=5; - ui->txrb5->setChecked(true); - m_restart=true; -} - -void MainWindow::on_txb6_clicked() //txb6 -{ - m_ntx=6; - ui->txrb6->setChecked(true); - m_restart=true; -} - -void MainWindow::selectCall2(bool ctrl) //selectCall2 -{ - QString t = ui->decodedTextBrowser->toPlainText(); //Full contents - int i=ui->decodedTextBrowser->textCursor().position(); - int i0=t.lastIndexOf(" ",i); - int i1=t.indexOf(" ",i); - QString hiscall=t.mid(i0+1,i1-i0-1); - if(hiscall!="") { - if(hiscall.length() < 13) doubleClickOnCall(hiscall, ctrl); - } -} - //doubleClickOnCall -void MainWindow::doubleClickOnCall(QString hiscall, bool ctrl) -{ - if(m_worked[hiscall]) { - msgBox("Possible dupe: " + hiscall + " already in log."); - } - ui->dxCallEntry->setText(hiscall); - QString t = ui->decodedTextBrowser->toPlainText(); //Full contents - int i2=ui->decodedTextBrowser->textCursor().position(); - QString t1 = t.mid(0,i2); //contents up to text cursor - int i1=t1.lastIndexOf("\n") + 1; - QString t2 = t1.mid(i1,i2-i1); //selected line - int n = 60*t2.mid(13,2).toInt() + t2.mid(15,2).toInt(); - m_txFirst = ((n%2) == 1); - ui->txFirstCheckBox->setChecked(m_txFirst); - QString rpt=""; - if(ctrl) rpt=t2.mid(23,3); - lookup(); - genStdMsgs(rpt); - if(t2.indexOf(m_myCall)>0) { - m_ntx=2; - ui->txrb2->setChecked(true); - } else { - m_ntx=1; - ui->txrb1->setChecked(true); - } -} - //doubleClickOnMessages -void MainWindow::doubleClickOnMessages(QString hiscall, QString t2) -{ - if(m_worked[hiscall]) { - msgBox("Possible dupe: " + hiscall + " already in log."); - } - ui->dxCallEntry->setText(hiscall); - int n = 60*t2.mid(13,2).toInt() + t2.mid(15,2).toInt(); - m_txFirst = ((n%2) == 1); - ui->txFirstCheckBox->setChecked(m_txFirst); - lookup(); - genStdMsgs(""); - if(t2.indexOf(m_myCall)>0) { - m_ntx=2; - ui->txrb2->setChecked(true); - } else { - m_ntx=1; - ui->txrb1->setChecked(true); - } -} - -void MainWindow::genStdMsgs(QString rpt) //genStdMsgs() -{ - QString hiscall=ui->dxCallEntry->text().toUpper().trimmed(); - ui->dxCallEntry->setText(hiscall); - QString t0=hiscall + " " + m_myCall + " "; - QString t=t0 + m_myGrid.mid(0,4); - msgtype(t, ui->tx1); - if(rpt == "") { - t=t+" OOO"; - msgtype(t, ui->tx2); - msgtype("RO", ui->tx3); - msgtype("RRR", ui->tx4); - msgtype("73", ui->tx5); - } else { - t=t0 + rpt; - msgtype(t, ui->tx2); - t=t0 + "R" + rpt; - msgtype(t, ui->tx3); - t=t0 + "RRR"; - msgtype(t, ui->tx4); - t=t0 + "73"; - msgtype(t, ui->tx5); - } - t="CQ " + m_myCall + " " + m_myGrid.mid(0,4); - msgtype(t, ui->tx6); - m_ntx=1; - ui->txrb1->setChecked(true); -} - -void MainWindow::lookup() //lookup() -{ - QString hiscall=ui->dxCallEntry->text().toUpper().trimmed(); - ui->dxCallEntry->setText(hiscall); - QString call3File = m_appDir + "/CALL3.TXT"; - QFile f(call3File); - if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) { - msgBox("Cannot open " + call3File); - return; - } - char c[132]; - qint64 n=0; - for(int i=0; i<999999; i++) { - n=f.readLine(c,sizeof(c)); - if(n <= 0) { - ui->dxGridEntry->setText(""); - break; - } - QString t=QString(c); - if(t.indexOf(hiscall)==0) { - int i1=t.indexOf(","); - QString hisgrid=t.mid(i1+1,6); - i1=hisgrid.indexOf(","); - if(i1>0) { - hisgrid=hisgrid.mid(0,4); - } else { - hisgrid=hisgrid.mid(0,4) + hisgrid.mid(4,2).toLower(); - } - ui->dxGridEntry->setText(hisgrid); - break; - } - } - f.close(); -} - -void MainWindow::on_lookupButton_clicked() //Lookup button -{ - lookup(); -} - -void MainWindow::on_addButton_clicked() //Add button -{ - if(ui->dxGridEntry->text()=="") { - msgBox("Please enter a valid grid locator."); - return; - } - m_call3Modified=false; - QString hiscall=ui->dxCallEntry->text().toUpper().trimmed(); - QString hisgrid=ui->dxGridEntry->text().trimmed(); - QString newEntry=hiscall + "," + hisgrid; - - int ret = QMessageBox::warning(this, "Add", - newEntry + "\n" + "Is this station known to be active on EME?", - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - if(ret==QMessageBox::Yes) { - newEntry += ",EME,,"; - } else { - newEntry += ",,,"; - } - QString call3File = m_appDir + "/CALL3.TXT"; - QFile f1(call3File); - if(!f1.open(QIODevice::ReadOnly | QIODevice::Text)) { - msgBox("Cannot open " + call3File); - return; - } - QString tmpFile = m_appDir + "/CALL3.TMP"; - QFile f2(tmpFile); - if(!f2.open(QIODevice::WriteOnly | QIODevice::Text)) { - msgBox("Cannot open " + tmpFile); - return; - } - QTextStream in(&f1); - QTextStream out(&f2); - QString hc=hiscall; - QString hc1=""; - QString hc2=""; - QString s; - do { - s=in.readLine(); - hc1=hc2; - if(s.mid(0,2)=="//") { - out << s + "\n"; - } else { - int i1=s.indexOf(","); - hc2=s.mid(0,i1); - if(hc>hc1 && hchc1 && !m_call3Modified) - out << newEntry + "\n"; - if(m_call3Modified) { - QFile f0(m_appDir + "/CALL3.OLD"); - if(f0.exists()) f0.remove(); - QFile f1(m_appDir + "/CALL3.TXT"); - f1.rename(m_appDir + "/CALL3.OLD"); - f2.rename(m_appDir + "/CALL3.TXT"); - f2.close(); - } -} - -void MainWindow::msgtype(QString t, QLineEdit* tx) //msgtype() -{ -// if(t.length()<1) return 0; - char message[23]; - char msgsent[23]; - int len1=22; - int mode65=0; //mode65 ==> check message but don't make wave() - double samfac=1.0; - int nsendingsh=0; - int mwave; - t=t.toUpper(); - int i1=t.indexOf(" OOO"); - QByteArray s=t.toUpper().toLocal8Bit(); - ba2msg(s,message); - gen65_(message,&mode65,&samfac,&nsendingsh,msgsent,iwave,&mwave,len1,len1); - - QPalette p(tx->palette()); - if(nsendingsh==1) { - p.setColor(QPalette::Base,"#66ffff"); - } else if(nsendingsh==-1) { - p.setColor(QPalette::Base,"#ffccff"); - } else { - p.setColor(QPalette::Base,Qt::white); - } - tx->setPalette(p); - int len=t.length(); - if(nsendingsh==-1) { - len=qMin(len,13); - if(i1>10) { - tx->setText(t.mid(0,len).toUpper() + " OOO"); - } else { - tx->setText(t.mid(0,len).toUpper()); - } - } else { - tx->setText(t); - } -} - -void MainWindow::on_tx1_editingFinished() //tx1 edited -{ - QString t=ui->tx1->text(); - msgtype(t, ui->tx1); -} - -void MainWindow::on_tx2_editingFinished() //tx2 edited -{ - QString t=ui->tx2->text(); - msgtype(t, ui->tx2); -} - -void MainWindow::on_tx3_editingFinished() //tx3 edited -{ - QString t=ui->tx3->text(); - msgtype(t, ui->tx3); -} - -void MainWindow::on_tx4_editingFinished() //tx4 edited -{ - QString t=ui->tx4->text(); - msgtype(t, ui->tx4); -} - -void MainWindow::on_tx5_editingFinished() //tx5 edited -{ - QString t=ui->tx5->text(); - msgtype(t, ui->tx5); -} - -void MainWindow::on_tx6_editingFinished() //tx6 edited -{ - QString t=ui->tx6->text(); - msgtype(t, ui->tx6); -} - -void MainWindow::on_setTxFreqButton_clicked() //Set Tx Freq -{ - m_setftx=1; - m_txFreq=g_pWideGraph->QSOfreq(); -} - -void MainWindow::on_dxCallEntry_textChanged(const QString &t) //dxCall changed -{ - m_hisCall=t.toUpper().trimmed(); - ui->dxCallEntry->setText(m_hisCall); -} - -void MainWindow::on_dxGridEntry_textChanged(const QString &t) //dxGrid changed -{ - int n=t.length(); - if(n!=4 and n!=6) return; - if(!t[0].isLetter() or !t[1].isLetter()) return; - if(!t[2].isDigit() or !t[3].isDigit()) return; - if(n==4) m_hisGrid=t.mid(0,2).toUpper() + t.mid(2,2); - if(n==6) m_hisGrid=t.mid(0,2).toUpper() + t.mid(2,2) + - t.mid(4,2).toLower(); - ui->dxGridEntry->setText(m_hisGrid); -} - -void MainWindow::on_genStdMsgsPushButton_clicked() //genStdMsgs button -{ - genStdMsgs(""); -} - -void MainWindow::on_logQSOButton_clicked() //Log QSO button -{ - int nMHz=int(datcom_.fcenter); - QDateTime t = QDateTime::currentDateTimeUtc(); - QString logEntry=t.date().toString("yyyy-MMM-dd,") + - t.time().toString("hh:mm,") + m_hisCall + "," + m_hisGrid + "," + - QString::number(nMHz) + ",JT65B\n"; - QFile f("wsjt.log"); - if(!f.open(QFile::Append)) { - msgBox("Cannot open file \"wsjt.log\"."); - return; - } - QTextStream out(&f); - out << logEntry; - f.close(); - m_worked[m_hisCall]=true; -} - -void MainWindow::on_actionErase_map65_rx_log_triggered() //Erase Rx log -{ - int ret = QMessageBox::warning(this, "Confirm Erase", - "Are you sure you want to erase file map65_rx.log ?", - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - if(ret==QMessageBox::Yes) { - m_map65RxLog |= 2; // Rewind map65_rx.log - } -} - -void MainWindow::on_actionErase_map65_tx_log_triggered() //Erase Tx log -{ - int ret = QMessageBox::warning(this, "Confirm Erase", - "Are you sure you want to erase file map65_tx.log ?", - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - if(ret==QMessageBox::Yes) { - QFile f("map65_tx.log"); - f.remove(); - } -} - -void MainWindow::on_actionJT65A_triggered() -{ - m_mode="JT65A"; - m_mode65=1; - g_pWideGraph->setMode65(m_mode65); - lab5->setText(m_mode); - ui->actionJT65A->setChecked(true); -} - -void MainWindow::on_actionJT65B_triggered() -{ - m_mode="JT65B"; - m_mode65=2; - g_pWideGraph->setMode65(m_mode65); - lab5->setText(m_mode); - ui->actionJT65B->setChecked(true); -} - -void MainWindow::on_actionJT65C_triggered() -{ - m_mode="JT65C"; - m_mode65=4; - g_pWideGraph->setMode65(m_mode65); - lab5->setText(m_mode); - ui->actionJT65C->setChecked(true); -} - -void MainWindow::on_NBcheckBox_toggled(bool checked) -{ - m_NB=checked; - ui->NBslider->setEnabled(m_NB); -} - -void MainWindow::on_NBslider_valueChanged(int n) -{ - m_NBslider=n; -} - -void MainWindow::on_actionAdjust_IQ_Calibration_triggered() -{ - m_adjustIQ=1; -} - -void MainWindow::on_actionApply_IQ_Calibration_triggered() -{ - m_applyIQcal= 1-m_applyIQcal; -} - -void MainWindow::on_actionFUNcube_Dongle_triggered() -{ - proc_qthid.start(QDir::toNativeSeparators(m_appDir + "/qthid")); -} +//-------------------------------------------------------------- MainWindow +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "devsetup.h" +#include "plotter.h" +#include "about.h" +#include "astro.h" +#include "widegraph.h" +#include "messages.h" +#include "bandmap.h" +#include "sleep.h" +#include + +#define NFFT 32768 + +short int iwave[60*11025]; //Wave file for Tx audio +int nwave; //Length of Tx waveform +bool btxok; //True if OK to transmit +double outputLatency; //Latency in seconds +qint16 id[4*60*96000]; + + +Astro* g_pAstro = NULL; +WideGraph* g_pWideGraph = NULL; +Messages* g_pMessages = NULL; + +BandMap* g_pBandMap = NULL; +QSharedMemory mem_m65("mem_m65"); + +QString rev="$Rev$"; +QString Program_Title_Version=" MAP65 v2.3.0, r" + rev.mid(6,3) + + " by K1JT"; + +extern const int RxDataFrequency = 96000; +extern const int TxDataFrequency = 11025; + +//-------------------------------------------------- MainWindow constructor +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + on_EraseButton_clicked(); + ui->labUTC->setStyleSheet( \ + "QLabel { background-color : black; color : yellow; }"); + ui->labTol1->setStyleSheet( \ + "QLabel { background-color : white; color : black; }"); + ui->labTol1->setFrameStyle(QFrame::Panel | QFrame::Sunken); + ui->dxStationGroupBox->setStyleSheet("QFrame{border: 5px groove red}"); + + QActionGroup* paletteGroup = new QActionGroup(this); + ui->actionCuteSDR->setActionGroup(paletteGroup); + ui->actionLinrad->setActionGroup(paletteGroup); + ui->actionAFMHot->setActionGroup(paletteGroup); + ui->actionBlue->setActionGroup(paletteGroup); + + QActionGroup* modeGroup = new QActionGroup(this); + ui->actionJT65A->setActionGroup(modeGroup); + ui->actionJT65B->setActionGroup(modeGroup); + ui->actionJT65C->setActionGroup(modeGroup); + + QActionGroup* saveGroup = new QActionGroup(this); + ui->actionSave_all->setActionGroup(saveGroup); + ui->actionNone->setActionGroup(saveGroup); + + QActionGroup* DepthGroup = new QActionGroup(this); + ui->actionNo_Deep_Search->setActionGroup(DepthGroup); + ui->actionNormal_Deep_Search->setActionGroup(DepthGroup); + ui->actionAggressive_Deep_Search->setActionGroup(DepthGroup); + + QButtonGroup* txMsgButtonGroup = new QButtonGroup; + txMsgButtonGroup->addButton(ui->txrb1,1); + txMsgButtonGroup->addButton(ui->txrb2,2); + txMsgButtonGroup->addButton(ui->txrb3,3); + txMsgButtonGroup->addButton(ui->txrb4,4); + txMsgButtonGroup->addButton(ui->txrb5,5); + txMsgButtonGroup->addButton(ui->txrb6,6); + connect(txMsgButtonGroup,SIGNAL(buttonClicked(int)),SLOT(set_ntx(int))); + connect(ui->decodedTextBrowser,SIGNAL(selectCallsign(bool)),this, + SLOT(selectCall2(bool))); + + setWindowTitle(Program_Title_Version); + + connect(&soundInThread, SIGNAL(readyForFFT(int)), + this, SLOT(dataSink(int))); + connect(&soundInThread, SIGNAL(error(QString)), this, + SLOT(showSoundInError(QString))); + connect(&soundInThread, SIGNAL(status(QString)), this, + SLOT(showStatusMessage(QString))); + createStatusBar(); + + connect(&proc_m65, SIGNAL(readyReadStandardOutput()), + this, SLOT(readFromStdout())); + + connect(&proc_m65, SIGNAL(error(QProcess::ProcessError)), + this, SLOT(m65_error())); + + connect(&proc_m65, SIGNAL(readyReadStandardError()), + this, SLOT(readFromStderr())); + + QTimer *guiTimer = new QTimer(this); + connect(guiTimer, SIGNAL(timeout()), this, SLOT(guiUpdate())); + guiTimer->start(100); //Don't change the 100 ms! + + m_auto=false; + m_waterfallAvg = 1; + m_network = true; + m_txFirst=false; + m_txMute=false; + btxok=false; + m_restart=false; + m_transmitting=false; + m_killAll=false; + m_widebandDecode=false; + m_ntx=1; + m_myCall="K1JT"; + m_myGrid="FN20qi"; + m_appDir = QApplication::applicationDirPath(); + m_saveDir="/users/joe/map65/install/save"; + m_azelDir="/users/joe/map65/install/"; + m_txFreq=125; + m_setftx=0; + m_loopall=false; + m_startAnother=false; + m_saveAll=false; + m_onlyEME=false; + m_sec0=-1; + m_hsym0=-1; + m_palette="CuteSDR"; + m_map65RxLog=1; //Write Date and Time to all65.txt + m_nutc0=9999; + m_kb8rq=false; + m_NB=false; + m_mode="JT65B"; + m_mode65=2; + m_fs96000=true; + m_udpPort=50004; + m_adjustIQ=0; + m_applyIQcal=0; + m_colors="000066ff0000ffff00969696646464"; + + ui->xThermo->setFillBrush(Qt::green); + ui->yThermo->setFillBrush(Qt::magenta); + +#ifdef WIN32 + while(true) { + int iret=killbyname("m65.exe"); + if(iret == 603) break; + if(iret != 0) msgBox("KillByName return code: " + + QString::number(iret)); + } +#endif + + if(!mem_m65.attach()) { + if (!mem_m65.create(sizeof(datcom_))) { + msgBox("Unable to create shared memory segment."); + } + } + char *to = (char*)mem_m65.data(); + int size=sizeof(datcom_); + if(datcom_.newdat==0) { + int noffset = 4*4*5760000 + 4*4*322*32768 + 4*4*32768; + to += noffset; + size -= noffset; + } + memset(to,0,size); //Zero all decoding params in shared memory + + PaError paerr=Pa_Initialize(); //Initialize Portaudio + if(paerr!=paNoError) { + msgBox("Unable to initialize PortAudio."); + } + readSettings(); //Restore user's setup params + QFile lockFile(m_appDir + "/.lock"); //Create .lock so m65 will wait + lockFile.open(QIODevice::ReadWrite); + QFile quitFile(m_appDir + "/.lock"); + quitFile.remove(); + proc_m65.start(QDir::toNativeSeparators(m_appDir + "/m65 -s")); + + m_pbdecoding_style1="QPushButton{background-color: cyan; \ + border-style: outset; border-width: 1px; border-radius: 5px; \ + border-color: black; min-width: 5em; padding: 3px;}"; + m_pbmonitor_style="QPushButton{background-color: #00ff00; \ + border-style: outset; border-width: 1px; border-radius: 5px; \ + border-color: black; min-width: 5em; padding: 3px;}"; + m_pbAutoOn_style="QPushButton{background-color: red; \ + border-style: outset; border-width: 1px; border-radius: 5px; \ + border-color: black; min-width: 5em; padding: 3px;}"; + + genStdMsgs(""); + + on_actionAstro_Data_triggered(); //Create the other windows + on_actionWide_Waterfall_triggered(); + on_actionMessages_triggered(); + on_actionBand_Map_triggered(); + g_pMessages->setColors(m_colors); + g_pBandMap->setColors(m_colors); + g_pAstro->setFontSize(m_astroFont); + if(m_mode=="JT65A") on_actionJT65A_triggered(); + if(m_mode=="JT65B") on_actionJT65B_triggered(); + if(m_mode=="JT65C") on_actionJT65C_triggered(); + + future1 = new QFuture; + watcher1 = new QFutureWatcher; + connect(watcher1, SIGNAL(finished()),this,SLOT(diskDat())); + + future2 = new QFuture; + watcher2 = new QFutureWatcher; + connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished())); + +// Assign input device and start input thread + soundInThread.setInputDevice(m_paInDevice); + if(m_fs96000) soundInThread.setRate(96000.0); + if(!m_fs96000) soundInThread.setRate(95238.1); + soundInThread.setBufSize(10*7056); + soundInThread.setNetwork(m_network); + soundInThread.setPort(m_udpPort); + if(!m_xpol) soundInThread.setNrx(1); + if(m_xpol) soundInThread.setNrx(2); + soundInThread.start(QThread::HighestPriority); + + // Assign output device and start output thread + soundOutThread.setOutputDevice(m_paOutDevice); +// soundOutThread.start(QThread::HighPriority); + + m_monitoring=true; // Start with Monitoring ON + soundInThread.setMonitoring(m_monitoring); + m_diskData=false; + m_tol=500; + g_pWideGraph->setTol(m_tol); + g_pWideGraph->setFcal(m_fCal); + if(m_fs96000) g_pWideGraph->setFsample(96000); + if(!m_fs96000) g_pWideGraph->setFsample(95238); + g_pWideGraph->m_mult570=m_mult570; + g_pWideGraph->m_cal570=m_cal570; + if(m_initIQplus) g_pWideGraph->initIQplus(); + +// Create "m_worked", a dictionary of all calls in wsjt.log + QFile f("wsjt.log"); + f.open(QIODevice::ReadOnly); + QTextStream in(&f); + QString line,t,callsign; + for(int i=0; i<99999; i++) { + line=in.readLine(); + if(line.length()<=0) break; + t=line.mid(18,12); + callsign=t.mid(0,t.indexOf(",")); + m_worked[callsign]=true; + } + f.close(); + + if(ui->actionLinrad->isChecked()) on_actionLinrad_triggered(); + if(ui->actionCuteSDR->isChecked()) on_actionCuteSDR_triggered(); + if(ui->actionAFMHot->isChecked()) on_actionAFMHot_triggered(); + if(ui->actionBlue->isChecked()) on_actionBlue_triggered(); + // End of MainWindow constructor +} + + //--------------------------------------------------- MainWindow destructor +MainWindow::~MainWindow() +{ + writeSettings(); + if (soundInThread.isRunning()) { + soundInThread.quit(); + soundInThread.wait(3000); + } + if (soundOutThread.isRunning()) { + soundOutThread.quitExecution=true; + soundOutThread.wait(3000); + } + if(!m_decoderBusy) { + QFile lockFile(m_appDir + "/.lock"); + lockFile.remove(); + } + delete ui; +} + +//-------------------------------------------------------- writeSettings() +void MainWindow::writeSettings() +{ + QString inifile = m_appDir + "/map65.ini"; + QSettings settings(inifile, QSettings::IniFormat); + + settings.beginGroup("MainWindow"); + settings.setValue("geometry", saveGeometry()); + settings.setValue("MRUdir", m_path); + settings.setValue("TxFirst",m_txFirst); + settings.setValue("DXcall",ui->dxCallEntry->text()); + settings.setValue("DXgrid",ui->dxGridEntry->text()); + + if(g_pAstro->isVisible()) { + m_astroGeom = g_pAstro->geometry(); + settings.setValue("AstroGeom",m_astroGeom); + } + + if(g_pWideGraph->isVisible()) { + m_wideGraphGeom = g_pWideGraph->geometry(); + settings.setValue("WideGraphGeom",m_wideGraphGeom); + } + if(g_pMessages->isVisible()) { + m_messagesGeom = g_pMessages->geometry(); + settings.setValue("MessagesGeom",m_messagesGeom); + } + if(g_pBandMap->isVisible()) { + m_bandMapGeom = g_pBandMap->geometry(); + settings.setValue("BandMapGeom",m_bandMapGeom); + } + settings.endGroup(); + + settings.beginGroup("Common"); + settings.setValue("MyCall",m_myCall); + settings.setValue("MyGrid",m_myGrid); + settings.setValue("IDint",m_idInt); + settings.setValue("PTTport",m_pttPort); + settings.setValue("AstroFont",m_astroFont); + settings.setValue("Xpol",m_xpol); + settings.setValue("XpolX",m_xpolx); + settings.setValue("SaveDir",m_saveDir); + settings.setValue("AzElDir",m_azelDir); + settings.setValue("DXCCpfx",m_dxccPfx); + settings.setValue("Timeout",m_timeout); + settings.setValue("IQamp",m_IQamp); + settings.setValue("IQphase",m_IQphase); + settings.setValue("ApplyIQcal",m_applyIQcal); + settings.setValue("dPhi",m_dPhi); + settings.setValue("Fcal",m_fCal); + settings.setValue("Fadd",m_fAdd); + settings.setValue("NetworkInput", m_network); + settings.setValue("FSam96000", m_fs96000); + settings.setValue("SoundInIndex",m_nDevIn); + settings.setValue("paInDevice",m_paInDevice); + settings.setValue("SoundOutIndex",m_nDevOut); + settings.setValue("paOutDevice",m_paOutDevice); + settings.setValue("IQswap",m_IQswap); + settings.setValue("Plus10dB",m_10db); + settings.setValue("InitIQplus",m_initIQplus); + settings.setValue("UDPport",m_udpPort); + settings.setValue("PaletteCuteSDR",ui->actionCuteSDR->isChecked()); + settings.setValue("PaletteLinrad",ui->actionLinrad->isChecked()); + settings.setValue("PaletteAFMHot",ui->actionAFMHot->isChecked()); + settings.setValue("PaletteBlue",ui->actionBlue->isChecked()); + settings.setValue("Mode",m_mode); + settings.setValue("SaveNone",ui->actionNone->isChecked()); + settings.setValue("SaveAll",ui->actionSave_all->isChecked()); + settings.setValue("NDepth",m_ndepth); + settings.setValue("NEME",m_onlyEME); + settings.setValue("KB8RQ",m_kb8rq); + settings.setValue("NB",m_NB); + settings.setValue("NBslider",m_NBslider); + settings.setValue("GainX",(double)m_gainx); + settings.setValue("GainY",(double)m_gainy); + settings.setValue("PhaseX",(double)m_phasex); + settings.setValue("PhaseY",(double)m_phasey); + settings.setValue("Mult570",m_mult570); + settings.setValue("Cal570",m_cal570); + settings.setValue("Colors",m_colors); + settings.endGroup(); +} + +//---------------------------------------------------------- readSettings() +void MainWindow::readSettings() +{ + QString inifile = m_appDir + "/map65.ini"; + QSettings settings(inifile, QSettings::IniFormat); + settings.beginGroup("MainWindow"); + restoreGeometry(settings.value("geometry").toByteArray()); + ui->dxCallEntry->setText(settings.value("DXcall","").toString()); + ui->dxGridEntry->setText(settings.value("DXgrid","").toString()); + + m_astroGeom = settings.value("AstroGeom", QRect(71,390,227,403)).toRect(); + + m_wideGraphGeom = settings.value("WideGraphGeom", \ + QRect(45,30,1023,340)).toRect(); + m_messagesGeom = settings.value("MessagesGeom", \ + QRect(800,400,381,400)).toRect(); + m_bandMapGeom = settings.value("BandMapGeom", \ + QRect(280,400,142,400)).toRect(); + m_path = settings.value("MRUdir", m_appDir + "/save").toString(); + m_txFirst = settings.value("TxFirst",false).toBool(); + ui->txFirstCheckBox->setChecked(m_txFirst); + settings.endGroup(); + + settings.beginGroup("Common"); + m_myCall=settings.value("MyCall","").toString(); + m_myGrid=settings.value("MyGrid","").toString(); + m_idInt=settings.value("IDint",0).toInt(); + m_pttPort=settings.value("PTTport",0).toInt(); + m_astroFont=settings.value("AstroFont",20).toInt(); + m_xpol=settings.value("Xpol",false).toBool(); + ui->actionFind_Delta_Phi->setEnabled(m_xpol); + m_xpolx=settings.value("XpolX",false).toBool(); + m_saveDir=settings.value("SaveDir",m_appDir + "/save").toString(); + m_azelDir=settings.value("AzElDir",m_appDir).toString(); + m_dxccPfx=settings.value("DXCCpfx","").toString(); + m_timeout=settings.value("Timeout",20).toInt(); + m_IQamp=settings.value("IQamp",1.0000).toDouble(); + m_IQphase=settings.value("IQphase",0.0).toDouble(); + m_applyIQcal=settings.value("ApplyIQcal",0).toInt(); + ui->actionApply_IQ_Calibration->setChecked(m_applyIQcal!=0); + m_dPhi=settings.value("dPhi",0).toInt(); + m_fCal=settings.value("Fcal",0).toInt(); + m_fAdd=settings.value("FAdd",0).toDouble(); + soundInThread.setFadd(m_fAdd); + m_network = settings.value("NetworkInput",true).toBool(); + m_fs96000 = settings.value("FSam96000",true).toBool(); + m_nDevIn = settings.value("SoundInIndex", 0).toInt(); + m_paInDevice = settings.value("paInDevice",0).toInt(); + m_nDevOut = settings.value("SoundOutIndex", 0).toInt(); + m_paOutDevice = settings.value("paOutDevice",0).toInt(); + m_IQswap = settings.value("IQswap",false).toBool(); + m_10db = settings.value("Plus10dB",false).toBool(); + m_initIQplus = settings.value("InitIQplus",false).toBool(); + m_udpPort = settings.value("UDPport",50004).toInt(); + soundInThread.setSwapIQ(m_IQswap); + soundInThread.set10db(m_10db); + soundInThread.setPort(m_udpPort); + ui->actionCuteSDR->setChecked(settings.value( + "PaletteCuteSDR",true).toBool()); + ui->actionLinrad->setChecked(settings.value( + "PaletteLinrad",false).toBool()); + ui->actionAFMHot->setChecked(settings.value( + "PaletteAFMHot",false).toBool()); + ui->actionBlue->setChecked(settings.value( + "PaletteBlue",false).toBool()); + m_mode=settings.value("Mode","JT65B").toString(); + ui->actionNone->setChecked(settings.value("SaveNone",true).toBool()); + ui->actionSave_all->setChecked(settings.value("SaveAll",false).toBool()); + m_saveAll=ui->actionSave_all->isChecked(); + m_ndepth=settings.value("NDepth",0).toInt(); + m_onlyEME=settings.value("NEME",false).toBool(); + ui->actionOnly_EME_calls->setChecked(m_onlyEME); + m_kb8rq=settings.value("KB8RQ",false).toBool(); + ui->actionF4_sets_Tx6->setChecked(m_kb8rq); + m_NB=settings.value("NB",false).toBool(); + ui->NBcheckBox->setChecked(m_NB); + m_NBslider=settings.value("NBslider",40).toInt(); + ui->NBslider->setValue(m_NBslider); + m_gainx=settings.value("GainX",1.0).toFloat(); + m_gainy=settings.value("GainY",1.0).toFloat(); + m_phasex=settings.value("PhaseX",0.0).toFloat(); + m_phasey=settings.value("PhaseY",0.0).toFloat(); + m_mult570=settings.value("Mult570",2).toInt(); + m_cal570=settings.value("Cal570",0.0).toDouble(); + m_colors=settings.value("Colors","000066ff0000ffff00969696646464").toString(); + settings.endGroup(); + + if(!ui->actionLinrad->isChecked() && !ui->actionCuteSDR->isChecked() && + !ui->actionAFMHot->isChecked() && !ui->actionBlue->isChecked()) { + on_actionLinrad_triggered(); + ui->actionLinrad->setChecked(true); + } + if(m_ndepth==0) ui->actionNo_Deep_Search->setChecked(true); + if(m_ndepth==1) ui->actionNormal_Deep_Search->setChecked(true); + if(m_ndepth==2) ui->actionAggressive_Deep_Search->setChecked(true); +} + +//-------------------------------------------------------------- dataSink() +void MainWindow::dataSink(int k) +{ + static float s[NFFT],splot[NFFT]; + static int n=0; + static int ihsym=0; + static int nzap=0; + static int n60z=0; + static int nkhz; + static int nfsample=96000; + static int nxpol=0; + static float fgreen; + static int ndiskdat; + static int nb; + static int nadj=0; + static float px=0.0,py=0.0; + static uchar lstrong[1024]; + static float rejectx; + static float rejecty; + static float slimit; + + + if(m_diskData) { + ndiskdat=1; + datcom_.ndiskdat=1; + } else { + ndiskdat=0; + datcom_.ndiskdat=0; + } +// Get x and y power, polarized spectrum, nkhz, and ihsym + nb=0; + if(m_NB) nb=1; + nfsample=96000; + if(!m_fs96000) nfsample=95238; + nxpol=0; + if(m_xpol) nxpol=1; + fgreen=(float)g_pWideGraph->fGreen(); + nadj++; + if(m_adjustIQ==0) nadj=0; + symspec_(&k, &nxpol, &ndiskdat, &nb, &m_NBslider, &m_dPhi, &nfsample, + &fgreen, &m_adjustIQ, &m_applyIQcal, &m_gainx, &m_gainy, &m_phasex, + &m_phasey, &rejectx, &rejecty, &px, &py, s, &nkhz, + &ihsym, &nzap, &slimit, lstrong); + QString t; + m_pctZap=nzap/178.3; + if(m_xpol) t.sprintf(" Rx noise: %5.1f %5.1f %5.1f %% ",px,py,m_pctZap); + if(!m_xpol) t.sprintf(" Rx noise: %5.1f %5.1f %% ",px,m_pctZap); + lab4->setText(t); + ui->xThermo->setValue((double)px); //Update the bargraphs + ui->yThermo->setValue((double)py); + if(m_monitoring || m_diskData) { + g_pWideGraph->dataSink2(s,nkhz,ihsym,m_diskData,lstrong); + } + + if(nadj == 10) { + if(m_xpol) { + t.sprintf("Amp: %6.4f %6.4f Phase: %6.4f %6.4f", + m_gainx,m_gainy,m_phasex,m_phasey); + } else { + t.sprintf("Amp: %6.4f Phase: %6.4f",m_gainx,m_phasex); + } + ui->decodedTextBrowser->append(t); + m_adjustIQ=0; + } + + //Average over specified number of spectra + if (n==0) { + for (int i=0; i=m_waterfallAvg) { + for (int i=0; isetFuture(*future2); + } + } + soundInThread.m_dataSinkBusy=false; +} + +void MainWindow::showSoundInError(const QString& errorMsg) + {QMessageBox::critical(this, tr("Error in SoundIn"), errorMsg);} + +void MainWindow::showStatusMessage(const QString& statusMsg) + {statusBar()->showMessage(statusMsg);} + +void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog +{ + DevSetup dlg(this); + dlg.m_myCall=m_myCall; + dlg.m_myGrid=m_myGrid; + dlg.m_idInt=m_idInt; + dlg.m_pttPort=m_pttPort; + dlg.m_astroFont=m_astroFont; + dlg.m_xpol=m_xpol; + dlg.m_xpolx=m_xpolx; + dlg.m_saveDir=m_saveDir; + dlg.m_azelDir=m_azelDir; + dlg.m_dxccPfx=m_dxccPfx; + dlg.m_timeout=m_timeout; + dlg.m_dPhi=m_dPhi; + dlg.m_fCal=m_fCal; + dlg.m_fAdd=m_fAdd; + dlg.m_network=m_network; + dlg.m_fs96000=m_fs96000; + dlg.m_nDevIn=m_nDevIn; + dlg.m_nDevOut=m_nDevOut; + dlg.m_udpPort=m_udpPort; + dlg.m_IQswap=m_IQswap; + dlg.m_10db=m_10db; + dlg.m_initIQplus=m_initIQplus; + dlg.m_cal570=m_cal570; + dlg.m_mult570=m_mult570; + dlg.m_colors=m_colors; + + dlg.initDlg(); + if(dlg.exec() == QDialog::Accepted) { + m_myCall=dlg.m_myCall; + m_myGrid=dlg.m_myGrid; + m_idInt=dlg.m_idInt; + m_pttPort=dlg.m_pttPort; + m_astroFont=dlg.m_astroFont; + if(g_pAstro->isVisible()) g_pAstro->setFontSize(m_astroFont); + m_xpol=dlg.m_xpol; + ui->actionFind_Delta_Phi->setEnabled(m_xpol); + m_xpolx=dlg.m_xpolx; + m_saveDir=dlg.m_saveDir; + m_azelDir=dlg.m_azelDir; + m_dxccPfx=dlg.m_dxccPfx; + m_timeout=dlg.m_timeout; + m_dPhi=dlg.m_dPhi; + m_fCal=dlg.m_fCal; + m_fAdd=dlg.m_fAdd; + g_pWideGraph->setFcal(m_fCal); + m_fs96000=dlg.m_fs96000; + m_network=dlg.m_network; + m_nDevIn=dlg.m_nDevIn; + m_paInDevice=dlg.m_paInDevice; + m_nDevOut=dlg.m_nDevOut; + m_paOutDevice=dlg.m_paOutDevice; + m_udpPort=dlg.m_udpPort; + m_IQswap=dlg.m_IQswap; + m_10db=dlg.m_10db; + m_initIQplus=dlg.m_initIQplus; + m_colors=dlg.m_colors; + g_pMessages->setColors(m_colors); + g_pBandMap->setColors(m_colors); + m_cal570=dlg.m_cal570; + m_mult570=dlg.m_mult570; + g_pWideGraph->m_mult570=m_mult570; + g_pWideGraph->m_cal570=m_cal570; + soundInThread.setSwapIQ(m_IQswap); + soundInThread.set10db(m_10db); + + if(dlg.m_restartSoundIn) { + soundInThread.quit(); + soundInThread.wait(1000); + soundInThread.setNetwork(m_network); + if(m_fs96000) soundInThread.setRate(96000.0); + if(!m_fs96000) soundInThread.setRate(95238.1); + soundInThread.setFadd(m_fAdd); + if(!m_xpol) soundInThread.setNrx(1); + if(m_xpol) soundInThread.setNrx(2); + soundInThread.setInputDevice(m_paInDevice); + soundInThread.start(QThread::HighestPriority); + } + + if(dlg.m_restartSoundOut) { + soundOutThread.quitExecution=true; + soundOutThread.wait(1000); + soundOutThread.setOutputDevice(m_paOutDevice); +// soundOutThread.start(QThread::HighPriority); + } + } +} + +void MainWindow::on_monitorButton_clicked() //Monitor +{ + m_monitoring=true; + soundInThread.setMonitoring(true); + m_diskData=false; +} +void MainWindow::on_actionLinrad_triggered() //Linrad palette +{ + if(g_pWideGraph != NULL) g_pWideGraph->setPalette("Linrad"); +} + +void MainWindow::on_actionCuteSDR_triggered() //CuteSDR palette +{ + if(g_pWideGraph != NULL) g_pWideGraph->setPalette("CuteSDR"); +} + +void MainWindow::on_actionAFMHot_triggered() +{ + if(g_pWideGraph != NULL) g_pWideGraph->setPalette("AFMHot"); +} + +void MainWindow::on_actionBlue_triggered() +{ + if(g_pWideGraph != NULL) g_pWideGraph->setPalette("Blue"); +} + +void MainWindow::on_actionAbout_triggered() //Display "About" +{ + CAboutDlg dlg(this,Program_Title_Version); + dlg.exec(); +} + +void MainWindow::on_autoButton_clicked() //Auto +{ + m_auto = !m_auto; + if(m_auto) { + ui->autoButton->setStyleSheet(m_pbAutoOn_style); + ui->autoButton->setText("Auto is ON"); + } else { + btxok=false; + ui->autoButton->setStyleSheet(""); + ui->autoButton->setText("Auto is OFF"); + on_monitorButton_clicked(); + } +} + +void MainWindow::on_stopTxButton_clicked() //Stop Tx +{ + if(m_auto) on_autoButton_clicked(); + btxok=false; +} + +void MainWindow::keyPressEvent( QKeyEvent *e ) //keyPressEvent +{ + switch(e->key()) + { + case Qt::Key_F3: + m_txMute=!m_txMute; + break; + case Qt::Key_F4: + ui->dxCallEntry->setText(""); + ui->dxGridEntry->setText(""); + if(m_kb8rq) { + m_ntx=6; + ui->txrb6->setChecked(true); + } + case Qt::Key_F6: + if(e->modifiers() & Qt::ShiftModifier) { + on_actionDecode_remaining_files_in_directory_triggered(); + } + break; + case Qt::Key_F11: + if(e->modifiers() & Qt::ShiftModifier) { + } else { + int n0=g_pWideGraph->DF(); + int n=(n0 + 10000) % 5; + if(n==0) n=5; + g_pWideGraph->setDF(n0-n); + } + break; + case Qt::Key_F12: + if(e->modifiers() & Qt::ShiftModifier) { + } else { + int n0=g_pWideGraph->DF(); + int n=(n0 + 10000) % 5; + if(n==0) n=5; + g_pWideGraph->setDF(n0+n); + } + break; + case Qt::Key_G: + if(e->modifiers() & Qt::AltModifier) { + genStdMsgs(""); + break; + } + case Qt::Key_L: + if(e->modifiers() & Qt::ControlModifier) { + lookup(); + genStdMsgs(""); + break; + } + } +} + +void MainWindow::bumpDF(int n) //bumpDF() +{ + if(n==11) { + int n0=g_pWideGraph->DF(); + int n=(n0 + 10000) % 5; + if(n==0) n=5; + g_pWideGraph->setDF(n0-n); + } + if(n==12) { + int n0=g_pWideGraph->DF(); + int n=(n0 + 10000) % 5; + if(n==0) n=5; + g_pWideGraph->setDF(n0+n); + } +} + +bool MainWindow::eventFilter(QObject *object, QEvent *event) //eventFilter() +{ + if (event->type() == QEvent::KeyPress) { + //Use the event in parent using its keyPressEvent() + QKeyEvent *keyEvent = static_cast(event); + MainWindow::keyPressEvent(keyEvent); + return QObject::eventFilter(object, event); + } + return QObject::eventFilter(object, event); +} + +void MainWindow::createStatusBar() //createStatusBar +{ + lab1 = new QLabel("Receiving"); + lab1->setAlignment(Qt::AlignHCenter); + lab1->setMinimumSize(QSize(80,10)); + lab1->setStyleSheet("QLabel{background-color: #00ff00}"); + lab1->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addWidget(lab1); + + lab2 = new QLabel("QSO freq: 125"); + lab2->setAlignment(Qt::AlignHCenter); + lab2->setMinimumSize(QSize(90,10)); + lab2->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addWidget(lab2); + + lab3 = new QLabel("QSO DF: 0"); + lab3->setAlignment(Qt::AlignHCenter); + lab3->setMinimumSize(QSize(80,10)); + lab3->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addWidget(lab3); + + lab4 = new QLabel(""); + lab4->setAlignment(Qt::AlignHCenter); + lab4->setMinimumSize(QSize(80,10)); + lab4->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addWidget(lab4); + + lab5 = new QLabel(""); + lab5->setAlignment(Qt::AlignHCenter); + lab5->setMinimumSize(QSize(50,10)); + lab5->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addWidget(lab5); +} + +void MainWindow::on_tolSpinBox_valueChanged(int i) //tolSpinBox +{ + static int ntol[] = {10,20,50,100,200,500,1000}; + m_tol=ntol[i]; + g_pWideGraph->setTol(m_tol); + ui->labTol1->setText(QString::number(ntol[i])); +} + +void MainWindow::on_actionExit_triggered() //Exit() +{ + OnExit(); +} + +void MainWindow::closeEvent(QCloseEvent*) +{ + OnExit(); +} + +void MainWindow::OnExit() +{ + g_pWideGraph->saveSettings(); + m_killAll=true; + mem_m65.detach(); + QFile quitFile(m_appDir + "/.quit"); + quitFile.open(QIODevice::ReadWrite); + QFile lockFile(m_appDir + "/.lock"); + lockFile.remove(); // Allow m65 to terminate + bool b=proc_m65.waitForFinished(1000); + if(!b) proc_m65.kill(); + quitFile.remove(); + qApp->exit(0); // Exit the event loop +} + +void MainWindow::on_stopButton_clicked() //stopButton +{ + m_monitoring=false; + soundInThread.setMonitoring(m_monitoring); + m_loopall=false; +} + +void MainWindow::msgBox(QString t) //msgBox +{ + msgBox0.setText(t); + msgBox0.exec(); +} + +void MainWindow::stub() //stub() +{ + msgBox("Not yet implemented."); +} + +void MainWindow::on_actionOnline_Users_Guide_triggered() //Display manual +{ + QDesktopServices::openUrl(QUrl( + "http://www.physics.princeton.edu/pulsar/K1JT/MAP65_Beta_Release.pdf", + QUrl::TolerantMode)); +} + +void MainWindow::on_actionAstro_Data_triggered() //Display Astro +{ + if(g_pAstro==NULL) { + g_pAstro = new Astro(0); + g_pAstro->setWindowTitle("Astronomical Data"); + Qt::WindowFlags flags = Qt::Dialog | Qt::WindowCloseButtonHint | + Qt::WindowMinimizeButtonHint; + g_pAstro->setWindowFlags(flags); + g_pAstro->setGeometry(m_astroGeom); + } + g_pAstro->show(); +} + +void MainWindow::on_actionWide_Waterfall_triggered() //Display Waterfalls +{ + if(g_pWideGraph==NULL) { + g_pWideGraph = new WideGraph(0); + g_pWideGraph->setWindowTitle("Wide Graph"); + g_pWideGraph->setGeometry(m_wideGraphGeom); + Qt::WindowFlags flags = Qt::WindowCloseButtonHint | + Qt::WindowMinimizeButtonHint; + g_pWideGraph->setWindowFlags(flags); + connect(g_pWideGraph, SIGNAL(freezeDecode2(int)),this, + SLOT(freezeDecode(int))); + connect(g_pWideGraph, SIGNAL(f11f12(int)),this, + SLOT(bumpDF(int))); + } + g_pWideGraph->show(); +} + +void MainWindow::on_actionBand_Map_triggered() //Display BandMap +{ + if(g_pBandMap==NULL) { + g_pBandMap = new BandMap(0); + g_pBandMap->setWindowTitle("Band Map"); + Qt::WindowFlags flags = Qt::Dialog | Qt::WindowCloseButtonHint | + Qt::WindowMinimizeButtonHint; + g_pBandMap->setWindowFlags(flags); + g_pBandMap->setGeometry(m_bandMapGeom); + } + g_pBandMap->show(); +} + +void MainWindow::on_actionMessages_triggered() //Display Messages +{ + if(g_pMessages==NULL) { + g_pMessages = new Messages(0); + g_pMessages->setWindowTitle("Messages"); + Qt::WindowFlags flags = Qt::Dialog | Qt::WindowCloseButtonHint | + Qt::WindowMinimizeButtonHint; + g_pMessages->setWindowFlags(flags); + g_pMessages->setGeometry(m_messagesGeom); + connect(g_pMessages, SIGNAL(click2OnCallsign(QString, QString)),this, + SLOT(doubleClickOnMessages(QString, QString))); + } + g_pMessages->show(); +} + +void MainWindow::on_actionOpen_triggered() //Open File +{ + m_monitoring=false; + soundInThread.setMonitoring(m_monitoring); + QString fname; + if(m_xpol) { + fname=QFileDialog::getOpenFileName(this, "Open File", m_path, + "MAP65 Files (*.tf2)"); + } else { + fname=QFileDialog::getOpenFileName(this, "Open File", m_path, + "MAP65 Files (*.iq)"); + } + if(fname != "") { + m_path=fname; + int i; + i=fname.indexOf(".iq") - 11; + if(m_xpol) i=fname.indexOf(".tf2") - 11; + if(i>=0) { + lab1->setStyleSheet("QLabel{background-color: #66ff66}"); + lab1->setText(" " + fname.mid(i,15) + " "); + } + on_stopButton_clicked(); + m_diskData=true; + int dbDgrd=0; + if(m_myCall=="K1JT" and m_idInt<0) dbDgrd=m_idInt; + *future1 = QtConcurrent::run(getfile, fname, m_xpol, dbDgrd); + watcher1->setFuture(*future1); + } +} + +void MainWindow::on_actionOpen_next_in_directory_triggered() //Open Next +{ + int i,len; + QFileInfo fi(m_path); + QStringList list; + list= fi.dir().entryList().filter(".iq"); + len=14; + if(m_xpol) { + list= fi.dir().entryList().filter(".tf2"); + len=15; + } + for (i = 0; i < list.size()-1; ++i) { + if(i==list.size()-2) m_loopall=false; + if(list.at(i)==m_path.right(len)) { + int n=m_path.length(); + QString fname=m_path.replace(n-len,len,list.at(i+1)); + m_path=fname; + int i; + i=fname.indexOf(".iq") - 11; + if(m_xpol) i=fname.indexOf(".tf2") - 11; + if(i>=0) { + lab1->setStyleSheet("QLabel{background-color: #66ff66}"); + lab1->setText(" " + fname.mid(i,len) + " "); + } + m_diskData=true; + int dbDgrd=0; + if(m_myCall=="K1JT" and m_idInt<0) dbDgrd=m_idInt; + *future1 = QtConcurrent::run(getfile, fname, m_xpol, dbDgrd); + watcher1->setFuture(*future1); + return; + } + } +} + //Open all remaining files +void MainWindow::on_actionDecode_remaining_files_in_directory_triggered() +{ + m_loopall=true; + on_actionOpen_next_in_directory_triggered(); +} + +void MainWindow::diskDat() //diskDat() +{ + double hsym; + //These may be redundant?? + m_diskData=true; + datcom_.newdat=1; + + if(m_fs96000) hsym=2048.0*96000.0/11025.0; //Samples per JT65 half-symbol + if(!m_fs96000) hsym=2048.0*95238.1/11025.0; + for(int i=0; i<281; i++) { // Do the half-symbol FFTs + int k = i*hsym + 2048.5; + dataSink(k); + if(i%10 == 0) qApp->processEvents(); //Keep the GUI responsive + } +} + +void MainWindow::diskWriteFinished() //diskWriteFinished +{ +// qDebug() << "diskWriteFinished"; +} + //Delete ../save/*.tf2 +void MainWindow::on_actionDelete_all_tf2_files_in_SaveDir_triggered() +{ + int i; + QString fname; + int ret = QMessageBox::warning(this, "Confirm Delete", + "Are you sure you want to delete all *.tf2 and *.iq files in\n" + + QDir::toNativeSeparators(m_saveDir) + " ?", + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + if(ret==QMessageBox::Yes) { + QDir dir(m_saveDir); + QStringList files=dir.entryList(QDir::Files); + QList::iterator f; + for(f=files.begin(); f!=files.end(); ++f) { + fname=*f; + i=(fname.indexOf(".tf2")); + if(i==11) dir.remove(fname); + i=(fname.indexOf(".iq")); + if(i==11) dir.remove(fname); + } + } +} + //Clear BandMap and Messages windows +void MainWindow::on_actionErase_Band_Map_and_Messages_triggered() +{ + g_pBandMap->setText(""); + g_pMessages->setText(""); + m_map65RxLog |= 4; +} + +void MainWindow::on_actionFind_Delta_Phi_triggered() //Find dPhi +{ + m_map65RxLog |= 8; + on_DecodeButton_clicked(); +} + +void MainWindow::on_actionF4_sets_Tx6_triggered() //F4 sets Tx6 +{ + m_kb8rq = !m_kb8rq; +} + +void MainWindow::on_actionOnly_EME_calls_triggered() //EME calls only +{ + m_onlyEME = ui->actionOnly_EME_calls->isChecked(); +} + +void MainWindow::on_actionNo_shorthands_if_Tx1_triggered() +{ + stub(); +} + +void MainWindow::on_actionNo_Deep_Search_triggered() //No Deep Search +{ + m_ndepth=0; +} + +void MainWindow::on_actionNormal_Deep_Search_triggered() //Normal DS +{ + m_ndepth=1; +} + +void MainWindow::on_actionAggressive_Deep_Search_triggered() //Aggressive DS +{ + m_ndepth=2; +} + +void MainWindow::on_actionNone_triggered() //Save None +{ + m_saveAll=false; +} + +// ### Implement "Save Last" here? ### + +void MainWindow::on_actionSave_all_triggered() //Save All +{ + m_saveAll=true; +} + //Display list of keyboard shortcuts +void MainWindow::on_actionKeyboard_shortcuts_triggered() +{ + stub(); +} + //Display list of mouse commands +void MainWindow::on_actionSpecial_mouse_commands_triggered() +{ + stub(); +} + //Diaplay list of Add-On pfx/sfx +void MainWindow::on_actionAvailable_suffixes_and_add_on_prefixes_triggered() +{ + stub(); +} + +void MainWindow::on_DecodeButton_clicked() //Decode request +{ + int n=m_sec0%60; + if(m_monitoring and n>47 and (n<52 or m_decoderBusy)) return; + if(!m_decoderBusy) { + datcom_.newdat=0; + datcom_.nagain=1; + decode(); + } +} + +void MainWindow::freezeDecode(int n) //freezeDecode() +{ + if(n==2) { + ui->tolSpinBox->setValue(5); + datcom_.ntol=m_tol; + datcom_.mousedf=0; + } else { + ui->tolSpinBox->setValue(3); + datcom_.ntol=m_tol; + } + if(!m_decoderBusy) { + datcom_.nagain=1; + datcom_.newdat=0; + decode(); + } +} + +void MainWindow::decode() //decode() +{ + ui->DecodeButton->setStyleSheet(m_pbdecoding_style1); + if(datcom_.nagain==0 && (!m_diskData)) { + qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; + int imin=ms/60000; + int ihr=imin/60; + imin=imin % 60; + datcom_.nutc=100*ihr + imin; + } + + datcom_.idphi=m_dPhi; + datcom_.mousedf=g_pWideGraph->DF(); + datcom_.mousefqso=g_pWideGraph->QSOfreq(); + datcom_.ndepth=m_ndepth; + datcom_.ndiskdat=0; + if(m_diskData) datcom_.ndiskdat=1; + datcom_.neme=0; + if(ui->actionOnly_EME_calls->isChecked()) datcom_.neme=1; + + int ispan=int(g_pWideGraph->fSpan()); + if(ispan%2 == 1) ispan++; + int ifc=int(1000.0*(datcom_.fcenter - int(datcom_.fcenter))+0.5); + int nfa=g_pWideGraph->nStartFreq(); + int nfb=nfa+ispan; + int nfshift=nfa + ispan/2 - ifc; + + datcom_.nfa=nfa; + datcom_.nfb=nfb; + datcom_.nfcal=m_fCal; + datcom_.nfshift=nfshift; + datcom_.mcall3=0; + if(m_call3Modified) datcom_.mcall3=1; + datcom_.ntimeout=m_timeout; + datcom_.ntol=m_tol; + datcom_.nxant=0; + if(m_xpolx) datcom_.nxant=1; + if(datcom_.nutc < m_nutc0) m_map65RxLog |= 1; //Date and Time to all65.txt + m_nutc0=datcom_.nutc; + datcom_.map65RxLog=m_map65RxLog; + datcom_.nfsample=96000; + if(!m_fs96000) datcom_.nfsample=95238; + datcom_.nxpol=0; + if(m_xpol) datcom_.nxpol=1; + datcom_.mode65=m_mode65; + + QString mcall=(m_myCall+" ").mid(0,12); + QString mgrid=(m_myGrid+" ").mid(0,6); + QString hcall=(ui->dxCallEntry->text()+" ").mid(0,12); + QString hgrid=(ui->dxGridEntry->text()+" ").mid(0,6); + + strncpy(datcom_.mycall, mcall.toAscii(), 12); + strncpy(datcom_.mygrid, mgrid.toAscii(), 6); + strncpy(datcom_.hiscall, hcall.toAscii(), 12); + strncpy(datcom_.hisgrid, hgrid.toAscii(), 6); + strncpy(datcom_.datetime, m_dateTime.toAscii(), 20); + + //newdat=1 ==> this is new data, must do the big FFT + //nagain=1 ==> decode only at fQSO +/- Tol + + char *to = (char*)mem_m65.data(); + char *from = (char*) datcom_.d4; + int size=sizeof(datcom_); + if(datcom_.newdat==0) { + int noffset = 4*4*5760000 + 4*4*322*32768 + 4*4*32768; + to += noffset; + from += noffset; + size -= noffset; + } + memcpy(to, from, qMin(mem_m65.size(), size)); + datcom_.nagain=0; + datcom_.ndiskdat=0; + m_call3Modified=false; + + QFile lockFile(m_appDir + "/.lock"); // Allow m65 to start + lockFile.remove(); + + decodeBusy(true); +} + +void MainWindow::m65_error() //m65_error +{ + if(!m_killAll) { + msgBox("Error starting or running\n" + m_appDir + "/m65 -s"); + exit(1); + } +} + +void MainWindow::readFromStderr() //readFromStderr +{ + QByteArray t=proc_m65.readAllStandardError(); + msgBox(t); +} + + +void MainWindow::readFromStdout() //readFromStdout +{ + while(proc_m65.canReadLine()) + { + QByteArray t=proc_m65.readLine(); + if(t.indexOf("") >= 0) { + if(m_widebandDecode) { + g_pMessages->setText(m_messagesText); + g_pBandMap->setText(m_bandmapText); + m_widebandDecode=false; + } + QFile lockFile(m_appDir + "/.lock"); + lockFile.open(QIODevice::ReadWrite); + ui->DecodeButton->setStyleSheet(""); + decodeBusy(false); + m_map65RxLog=0; + m_startAnother=m_loopall; + return; + } + + if(t.indexOf("!") >= 0) { + int n=t.length(); + if(n>=30) ui->decodedTextBrowser->append(t.mid(1,n-3)); + if(n<30) ui->decodedTextBrowser->append(t.mid(1,n-3)); + n=ui->decodedTextBrowser->verticalScrollBar()->maximum(); + ui->decodedTextBrowser->verticalScrollBar()->setValue(n); + m_messagesText=""; + m_bandmapText=""; + } + + if(t.indexOf("@") >= 0) { + m_messagesText += t.mid(1); + m_widebandDecode=true; + } + + if(t.indexOf("&") >= 0) { + QString q(t); + QString callsign=q.mid(5); + callsign=callsign.mid(0,callsign.indexOf(" ")); + if(callsign.length()>2) { + if(m_worked[callsign]) { + q=q.mid(1,4) + " " + q.mid(5); + } else { + q=q.mid(1,4) + " *" + q.mid(5); + } + m_bandmapText += q; + } + } + } +} + +void MainWindow::on_EraseButton_clicked() //Erase +{ + ui->decodedTextBrowser->clear(); +} + +void MainWindow::decodeBusy(bool b) //decodeBusy() +{ + m_decoderBusy=b; + ui->DecodeButton->setEnabled(!b); + ui->actionOpen->setEnabled(!b); + ui->actionOpen_next_in_directory->setEnabled(!b); + ui->actionDecode_remaining_files_in_directory->setEnabled(!b); +} + +//------------------------------------------------------------- //guiUpdate() +void MainWindow::guiUpdate() +{ + static int iptt0=0; + static int iptt=0; + static bool btxok0=false; + static int nc0=1; + static int nc1=1; + static char msgsent[23]; + static int nsendingsh=0; + int khsym=0; + + double tx1=0.0; + double tx2=126.0*4096.0/11025.0 + 1.8; //### depend on TxDelay? ### + + if(!m_txFirst) { + tx1 += 60.0; + tx2 += 60.0; + } + qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; + int nsec=ms/1000; + double tsec=0.001*ms; + double t120=fmod(tsec,120.0); + bool bTxTime = t120 >= tx1 && t120 < tx2; + + if(m_auto) { + if(bTxTime and iptt==0 and !m_txMute) { + int itx=1; + int ierr = ptt_(&m_pttPort,&itx,&iptt); // Raise PTT + if(ierr != 0) { + on_stopTxButton_clicked(); + char s[18]; + sprintf(s,"Cannot open COM%d",m_pttPort); + msgBox(s); + } + if(!soundOutThread.isRunning()) { + soundOutThread.start(QThread::HighPriority); + } + } + if(!bTxTime || m_txMute) { + btxok=false; + } + } + +// Calculate Tx waveform when needed + if((iptt==1 && iptt0==0) || m_restart) { + char message[23]; + QByteArray ba; + if(m_ntx == 1) ba=ui->tx1->text().toLocal8Bit(); + if(m_ntx == 2) ba=ui->tx2->text().toLocal8Bit(); + if(m_ntx == 3) ba=ui->tx3->text().toLocal8Bit(); + if(m_ntx == 4) ba=ui->tx4->text().toLocal8Bit(); + if(m_ntx == 5) ba=ui->tx5->text().toLocal8Bit(); + if(m_ntx == 6) ba=ui->tx6->text().toLocal8Bit(); + + ba2msg(ba,message); + int len1=22; + int mode65=m_mode65; + double samfac=1.0; + + gen65_(message,&mode65,&samfac,&nsendingsh,msgsent,iwave,&nwave,len1,len1); + msgsent[22]=0; + + if(m_restart) { + QFile f("map65_tx.log"); + f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append); + QTextStream out(&f); + out << QDateTime::currentDateTimeUtc().toString("yyyy-MMM-dd hh:mm") + << " Tx message: " << QString::fromAscii(msgsent) << endl; + f.close(); + } + + m_restart=false; + } + +// If PTT was just raised, start a countdown for raising TxOK: + if(iptt==1 && iptt0==0) nc1=-9; // TxDelay = 0.8 s + if(nc1 <= 0) nc1++; + if(nc1 == 0) { + ui->xThermo->setValue(0.0); //Set the Thermos to zero + ui->yThermo->setValue(0.0); + m_monitoring=false; + soundInThread.setMonitoring(false); + btxok=true; + m_transmitting=true; + + QFile f("map65_tx.log"); + f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append); + QTextStream out(&f); + out << QDateTime::currentDateTimeUtc().toString("yyyy-MMM-dd hh:mm") + << " Tx message: " << QString::fromAscii(msgsent) << endl; + f.close(); + } + +// If btxok was just lowered, start a countdown for lowering PTT + if(!btxok && btxok0 && iptt==1) nc0=-11; //RxDelay = 1.0 s + if(nc0 <= 0) nc0++; + if(nc0 == 0) { + int itx=0; + ptt_(&m_pttPort,&itx,&iptt); // Lower PTT + if(!m_txMute) soundOutThread.quitExecution=true; + m_transmitting=false; + if(m_auto) { + m_monitoring=true; + soundInThread.setMonitoring(m_monitoring); + } + } + + if(iptt == 0 && !btxok) { + // sending="" + // nsendingsh=0 + } + + if(m_monitoring) { + ui->monitorButton->setStyleSheet(m_pbmonitor_style); + } else { + ui->monitorButton->setStyleSheet(""); + } + + lab2->setText("QSO Freq: " + QString::number(g_pWideGraph->QSOfreq())); + lab3->setText("QSO DF: " + QString::number(g_pWideGraph->DF())); + + if(m_startAnother) { + m_startAnother=false; + on_actionOpen_next_in_directory_triggered(); + } + + if(nsec != m_sec0) { //Once per second + soundInThread.setForceCenterFreqMHz(g_pWideGraph->m_dForceCenterFreq); + soundInThread.setForceCenterFreqBool(g_pWideGraph->m_bForceCenterFreq); + + if(m_pctZap>30.0 and !m_transmitting) { + lab4->setStyleSheet("QLabel{background-color: #ff0000}"); + } else { + lab4->setStyleSheet(""); + } + + if(m_transmitting) { + if(nsendingsh==1) { + lab1->setStyleSheet("QLabel{background-color: #66ffff}"); + } else if(nsendingsh==-1) { + lab1->setStyleSheet("QLabel{background-color: #ffccff}"); + } else { + lab1->setStyleSheet("QLabel{background-color: #ffff33}"); + } + char s[37]; + sprintf(s,"Tx: %s",msgsent); + lab1->setText(s); + } else if(m_monitoring) { + lab1->setStyleSheet("QLabel{background-color: #00ff00}"); + m_nrx=soundInThread.nrx(); + khsym=soundInThread.mhsym(); + QString t; + if(m_network) { + if(m_nrx==-1) t="F1"; + if(m_nrx==1) t="I1"; + if(m_nrx==-2) t="F2"; + if(m_nrx==+2) t="I2"; + } else { + if(m_nrx==1) t="S1"; + if(m_nrx==2) t="S2"; + } + if((abs(m_nrx)==1 and m_xpol) or (abs(m_nrx)==2 and !m_xpol)) + lab1->setStyleSheet("QLabel{background-color: #ff1493}"); + if(khsym==m_hsym0) { + t="Nil"; + lab1->setStyleSheet("QLabel{background-color: #ffc0cb}"); + } + lab1->setText("Receiving " + t); + } else if (!m_diskData) { + lab1->setStyleSheet(""); + lab1->setText(""); + } + + QDateTime t = QDateTime::currentDateTimeUtc(); + int fQSO=g_pWideGraph->QSOfreq(); + g_pAstro->astroUpdate(t, m_myGrid, m_hisGrid, fQSO, m_setftx, + m_txFreq, m_azelDir); + m_setftx=0; + QString utc = " " + t.time().toString() + " "; + ui->labUTC->setText(utc); + if((!m_monitoring and !m_diskData) or (khsym==m_hsym0)) { + ui->xThermo->setValue(0.0); // Set Rx levels to 0 + ui->yThermo->setValue(0.0); + lab4->setText(" Rx noise: 0.0 0.0 0.0% "); + } + m_hsym0=khsym; + m_sec0=nsec; + } + iptt0=iptt; + btxok0=btxok; +} + +void MainWindow::ba2msg(QByteArray ba, char message[]) //ba2msg() +{ + bool eom; + eom=false; + for(int i=0;i<22; i++) { + if((int)ba[i] == 0) eom=true; + if(eom) { + message[i]=32; + } else { + message[i]=ba[i]; + } + } + message[22]=0; +} + +void MainWindow::on_txFirstCheckBox_stateChanged(int nstate) //TxFirst +{ + m_txFirst = (nstate==2); +} + +void MainWindow::set_ntx(int n) //set_ntx() +{ + m_ntx=n; +} + +void MainWindow::on_txb1_clicked() //txb1 +{ + m_ntx=1; + ui->txrb1->setChecked(true); + m_restart=true; +} + +void MainWindow::on_txb2_clicked() //txb2 +{ + m_ntx=2; + ui->txrb2->setChecked(true); + m_restart=true; +} + +void MainWindow::on_txb3_clicked() //txb3 +{ + m_ntx=3; + ui->txrb3->setChecked(true); + m_restart=true; +} + +void MainWindow::on_txb4_clicked() //txb4 +{ + m_ntx=4; + ui->txrb4->setChecked(true); + m_restart=true; +} + +void MainWindow::on_txb5_clicked() //txb5 +{ + m_ntx=5; + ui->txrb5->setChecked(true); + m_restart=true; +} + +void MainWindow::on_txb6_clicked() //txb6 +{ + m_ntx=6; + ui->txrb6->setChecked(true); + m_restart=true; +} + +void MainWindow::selectCall2(bool ctrl) //selectCall2 +{ + QString t = ui->decodedTextBrowser->toPlainText(); //Full contents + int i=ui->decodedTextBrowser->textCursor().position(); + int i0=t.lastIndexOf(" ",i); + int i1=t.indexOf(" ",i); + QString hiscall=t.mid(i0+1,i1-i0-1); + if(hiscall!="") { + if(hiscall.length() < 13) doubleClickOnCall(hiscall, ctrl); + } +} + //doubleClickOnCall +void MainWindow::doubleClickOnCall(QString hiscall, bool ctrl) +{ + if(m_worked[hiscall]) { + msgBox("Possible dupe: " + hiscall + " already in log."); + } + ui->dxCallEntry->setText(hiscall); + QString t = ui->decodedTextBrowser->toPlainText(); //Full contents + int i2=ui->decodedTextBrowser->textCursor().position(); + QString t1 = t.mid(0,i2); //contents up to text cursor + int i1=t1.lastIndexOf("\n") + 1; + QString t2 = t1.mid(i1,i2-i1); //selected line + int n = 60*t2.mid(13,2).toInt() + t2.mid(15,2).toInt(); + m_txFirst = ((n%2) == 1); + ui->txFirstCheckBox->setChecked(m_txFirst); + QString rpt=""; + if(ctrl) rpt=t2.mid(23,3); + lookup(); + genStdMsgs(rpt); + if(t2.indexOf(m_myCall)>0) { + m_ntx=2; + ui->txrb2->setChecked(true); + } else { + m_ntx=1; + ui->txrb1->setChecked(true); + } +} + //doubleClickOnMessages +void MainWindow::doubleClickOnMessages(QString hiscall, QString t2) +{ + if(m_worked[hiscall]) { + msgBox("Possible dupe: " + hiscall + " already in log."); + } + ui->dxCallEntry->setText(hiscall); + int n = 60*t2.mid(13,2).toInt() + t2.mid(15,2).toInt(); + m_txFirst = ((n%2) == 1); + ui->txFirstCheckBox->setChecked(m_txFirst); + lookup(); + genStdMsgs(""); + if(t2.indexOf(m_myCall)>0) { + m_ntx=2; + ui->txrb2->setChecked(true); + } else { + m_ntx=1; + ui->txrb1->setChecked(true); + } +} + +void MainWindow::genStdMsgs(QString rpt) //genStdMsgs() +{ + QString hiscall=ui->dxCallEntry->text().toUpper().trimmed(); + ui->dxCallEntry->setText(hiscall); + QString t0=hiscall + " " + m_myCall + " "; + QString t=t0 + m_myGrid.mid(0,4); + msgtype(t, ui->tx1); + if(rpt == "") { + t=t+" OOO"; + msgtype(t, ui->tx2); + msgtype("RO", ui->tx3); + msgtype("RRR", ui->tx4); + msgtype("73", ui->tx5); + } else { + t=t0 + rpt; + msgtype(t, ui->tx2); + t=t0 + "R" + rpt; + msgtype(t, ui->tx3); + t=t0 + "RRR"; + msgtype(t, ui->tx4); + t=t0 + "73"; + msgtype(t, ui->tx5); + } + t="CQ " + m_myCall + " " + m_myGrid.mid(0,4); + msgtype(t, ui->tx6); + m_ntx=1; + ui->txrb1->setChecked(true); +} + +void MainWindow::lookup() //lookup() +{ + QString hiscall=ui->dxCallEntry->text().toUpper().trimmed(); + ui->dxCallEntry->setText(hiscall); + QString call3File = m_appDir + "/CALL3.TXT"; + QFile f(call3File); + if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) { + msgBox("Cannot open " + call3File); + return; + } + char c[132]; + qint64 n=0; + for(int i=0; i<999999; i++) { + n=f.readLine(c,sizeof(c)); + if(n <= 0) { + ui->dxGridEntry->setText(""); + break; + } + QString t=QString(c); + if(t.indexOf(hiscall)==0) { + int i1=t.indexOf(","); + QString hisgrid=t.mid(i1+1,6); + i1=hisgrid.indexOf(","); + if(i1>0) { + hisgrid=hisgrid.mid(0,4); + } else { + hisgrid=hisgrid.mid(0,4) + hisgrid.mid(4,2).toLower(); + } + ui->dxGridEntry->setText(hisgrid); + break; + } + } + f.close(); +} + +void MainWindow::on_lookupButton_clicked() //Lookup button +{ + lookup(); +} + +void MainWindow::on_addButton_clicked() //Add button +{ + if(ui->dxGridEntry->text()=="") { + msgBox("Please enter a valid grid locator."); + return; + } + m_call3Modified=false; + QString hiscall=ui->dxCallEntry->text().toUpper().trimmed(); + QString hisgrid=ui->dxGridEntry->text().trimmed(); + QString newEntry=hiscall + "," + hisgrid; + + int ret = QMessageBox::warning(this, "Add", + newEntry + "\n" + "Is this station known to be active on EME?", + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + if(ret==QMessageBox::Yes) { + newEntry += ",EME,,"; + } else { + newEntry += ",,,"; + } + QString call3File = m_appDir + "/CALL3.TXT"; + QFile f1(call3File); + if(!f1.open(QIODevice::ReadOnly | QIODevice::Text)) { + msgBox("Cannot open " + call3File); + return; + } + QString tmpFile = m_appDir + "/CALL3.TMP"; + QFile f2(tmpFile); + if(!f2.open(QIODevice::WriteOnly | QIODevice::Text)) { + msgBox("Cannot open " + tmpFile); + return; + } + QTextStream in(&f1); + QTextStream out(&f2); + QString hc=hiscall; + QString hc1=""; + QString hc2=""; + QString s; + do { + s=in.readLine(); + hc1=hc2; + if(s.mid(0,2)=="//") { + out << s + "\n"; + } else { + int i1=s.indexOf(","); + hc2=s.mid(0,i1); + if(hc>hc1 && hchc1 && !m_call3Modified) + out << newEntry + "\n"; + if(m_call3Modified) { + QFile f0(m_appDir + "/CALL3.OLD"); + if(f0.exists()) f0.remove(); + QFile f1(m_appDir + "/CALL3.TXT"); + f1.rename(m_appDir + "/CALL3.OLD"); + f2.rename(m_appDir + "/CALL3.TXT"); + f2.close(); + } +} + +void MainWindow::msgtype(QString t, QLineEdit* tx) //msgtype() +{ +// if(t.length()<1) return 0; + char message[23]; + char msgsent[23]; + int len1=22; + int mode65=0; //mode65 ==> check message but don't make wave() + double samfac=1.0; + int nsendingsh=0; + int mwave; + t=t.toUpper(); + int i1=t.indexOf(" OOO"); + QByteArray s=t.toUpper().toLocal8Bit(); + ba2msg(s,message); + gen65_(message,&mode65,&samfac,&nsendingsh,msgsent,iwave,&mwave,len1,len1); + + QPalette p(tx->palette()); + if(nsendingsh==1) { + p.setColor(QPalette::Base,"#66ffff"); + } else if(nsendingsh==-1) { + p.setColor(QPalette::Base,"#ffccff"); + } else { + p.setColor(QPalette::Base,Qt::white); + } + tx->setPalette(p); + int len=t.length(); + if(nsendingsh==-1) { + len=qMin(len,13); + if(i1>10) { + tx->setText(t.mid(0,len).toUpper() + " OOO"); + } else { + tx->setText(t.mid(0,len).toUpper()); + } + } else { + tx->setText(t); + } +} + +void MainWindow::on_tx1_editingFinished() //tx1 edited +{ + QString t=ui->tx1->text(); + msgtype(t, ui->tx1); +} + +void MainWindow::on_tx2_editingFinished() //tx2 edited +{ + QString t=ui->tx2->text(); + msgtype(t, ui->tx2); +} + +void MainWindow::on_tx3_editingFinished() //tx3 edited +{ + QString t=ui->tx3->text(); + msgtype(t, ui->tx3); +} + +void MainWindow::on_tx4_editingFinished() //tx4 edited +{ + QString t=ui->tx4->text(); + msgtype(t, ui->tx4); +} + +void MainWindow::on_tx5_editingFinished() //tx5 edited +{ + QString t=ui->tx5->text(); + msgtype(t, ui->tx5); +} + +void MainWindow::on_tx6_editingFinished() //tx6 edited +{ + QString t=ui->tx6->text(); + msgtype(t, ui->tx6); +} + +void MainWindow::on_setTxFreqButton_clicked() //Set Tx Freq +{ + m_setftx=1; + m_txFreq=g_pWideGraph->QSOfreq(); +} + +void MainWindow::on_dxCallEntry_textChanged(const QString &t) //dxCall changed +{ + m_hisCall=t.toUpper().trimmed(); + ui->dxCallEntry->setText(m_hisCall); +} + +void MainWindow::on_dxGridEntry_textChanged(const QString &t) //dxGrid changed +{ + int n=t.length(); + if(n!=4 and n!=6) return; + if(!t[0].isLetter() or !t[1].isLetter()) return; + if(!t[2].isDigit() or !t[3].isDigit()) return; + if(n==4) m_hisGrid=t.mid(0,2).toUpper() + t.mid(2,2); + if(n==6) m_hisGrid=t.mid(0,2).toUpper() + t.mid(2,2) + + t.mid(4,2).toLower(); + ui->dxGridEntry->setText(m_hisGrid); +} + +void MainWindow::on_genStdMsgsPushButton_clicked() //genStdMsgs button +{ + genStdMsgs(""); +} + +void MainWindow::on_logQSOButton_clicked() //Log QSO button +{ + int nMHz=int(datcom_.fcenter); + QDateTime t = QDateTime::currentDateTimeUtc(); + QString logEntry=t.date().toString("yyyy-MMM-dd,") + + t.time().toString("hh:mm,") + m_hisCall + "," + m_hisGrid + "," + + QString::number(nMHz) + ",JT65B\n"; + QFile f("wsjt.log"); + if(!f.open(QFile::Append)) { + msgBox("Cannot open file \"wsjt.log\"."); + return; + } + QTextStream out(&f); + out << logEntry; + f.close(); + m_worked[m_hisCall]=true; +} + +void MainWindow::on_actionErase_map65_rx_log_triggered() //Erase Rx log +{ + int ret = QMessageBox::warning(this, "Confirm Erase", + "Are you sure you want to erase file map65_rx.log ?", + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + if(ret==QMessageBox::Yes) { + m_map65RxLog |= 2; // Rewind map65_rx.log + } +} + +void MainWindow::on_actionErase_map65_tx_log_triggered() //Erase Tx log +{ + int ret = QMessageBox::warning(this, "Confirm Erase", + "Are you sure you want to erase file map65_tx.log ?", + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + if(ret==QMessageBox::Yes) { + QFile f("map65_tx.log"); + f.remove(); + } +} + +void MainWindow::on_actionJT65A_triggered() +{ + m_mode="JT65A"; + m_mode65=1; + g_pWideGraph->setMode65(m_mode65); + lab5->setText(m_mode); + ui->actionJT65A->setChecked(true); +} + +void MainWindow::on_actionJT65B_triggered() +{ + m_mode="JT65B"; + m_mode65=2; + g_pWideGraph->setMode65(m_mode65); + lab5->setText(m_mode); + ui->actionJT65B->setChecked(true); +} + +void MainWindow::on_actionJT65C_triggered() +{ + m_mode="JT65C"; + m_mode65=4; + g_pWideGraph->setMode65(m_mode65); + lab5->setText(m_mode); + ui->actionJT65C->setChecked(true); +} + +void MainWindow::on_NBcheckBox_toggled(bool checked) +{ + m_NB=checked; + ui->NBslider->setEnabled(m_NB); +} + +void MainWindow::on_NBslider_valueChanged(int n) +{ + m_NBslider=n; +} + +void MainWindow::on_actionAdjust_IQ_Calibration_triggered() +{ + m_adjustIQ=1; +} + +void MainWindow::on_actionApply_IQ_Calibration_triggered() +{ + m_applyIQcal= 1-m_applyIQcal; +} + +void MainWindow::on_actionFUNcube_Dongle_triggered() +{ + proc_qthid.start(QDir::toNativeSeparators(m_appDir + "/qthid")); +} diff --git a/mainwindow.h b/mainwindow.h index 482bed51b..c6de2b120 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -1,274 +1,274 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H -#include -#include -#include -#include -#include -#include "soundin.h" -#include "soundout.h" -#include "commons.h" -#include "sleep.h" - -#define NFFT 32768 -#define NSMAX 5760000 - -//--------------------------------------------------------------- MainWindow -namespace Ui { - class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - bool m_network; - -public slots: - void showSoundInError(const QString& errorMsg); - void showStatusMessage(const QString& statusMsg); - void dataSink(int k); - void diskDat(); - void diskWriteFinished(); - void freezeDecode(int n); - void readFromStdout(); - void readFromStderr(); - void m65_error(); - void guiUpdate(); - void doubleClickOnCall(QString hiscall, bool ctrl); - void doubleClickOnMessages(QString hiscall, QString t2); - -protected: - virtual void keyPressEvent( QKeyEvent *e ); - void closeEvent(QCloseEvent*); - virtual bool eventFilter(QObject *object, QEvent *event); - -private slots: - void on_tx1_editingFinished(); - void on_tx2_editingFinished(); - void on_tx3_editingFinished(); - void on_tx4_editingFinished(); - void on_tx5_editingFinished(); - void on_tx6_editingFinished(); - void on_actionDeviceSetup_triggered(); - void on_monitorButton_clicked(); - void on_actionExit_triggered(); - void on_actionAbout_triggered(); - void OnExit(); - void on_actionLinrad_triggered(); - void on_actionCuteSDR_triggered(); - void on_autoButton_clicked(); - void on_stopTxButton_clicked(); - void on_tolSpinBox_valueChanged(int arg1); - void on_actionAstro_Data_triggered(); - void on_stopButton_clicked(); - void on_actionOnline_Users_Guide_triggered(); - void on_actionWide_Waterfall_triggered(); - void on_actionBand_Map_triggered(); - void on_actionMessages_triggered(); - void on_actionOpen_triggered(); - void on_actionOpen_next_in_directory_triggered(); - void on_actionDecode_remaining_files_in_directory_triggered(); - void on_actionDelete_all_tf2_files_in_SaveDir_triggered(); - void on_actionErase_Band_Map_and_Messages_triggered(); - void on_actionFind_Delta_Phi_triggered(); - void on_actionF4_sets_Tx6_triggered(); - void on_actionOnly_EME_calls_triggered(); - void on_actionNo_shorthands_if_Tx1_triggered(); - void on_actionNo_Deep_Search_triggered(); - void on_actionNormal_Deep_Search_triggered(); - void on_actionAggressive_Deep_Search_triggered(); - void on_actionNone_triggered(); - void on_actionSave_all_triggered(); - void on_actionKeyboard_shortcuts_triggered(); - void on_actionSpecial_mouse_commands_triggered(); - void on_actionAvailable_suffixes_and_add_on_prefixes_triggered(); - void on_DecodeButton_clicked(); - void decode(); - void decodeBusy(bool b); - void on_EraseButton_clicked(); - void on_txb1_clicked(); - void on_txFirstCheckBox_stateChanged(int arg1); - void set_ntx(int n); - void on_txb2_clicked(); - void on_txb3_clicked(); - void on_txb4_clicked(); - void on_txb5_clicked(); - void on_txb6_clicked(); - void on_lookupButton_clicked(); - void on_addButton_clicked(); - void on_setTxFreqButton_clicked(); - void on_dxCallEntry_textChanged(const QString &arg1); - void on_dxGridEntry_textChanged(const QString &arg1); - void selectCall2(bool ctrl); - void on_genStdMsgsPushButton_clicked(); - void bumpDF(int n); - void on_logQSOButton_clicked(); - void on_actionErase_map65_rx_log_triggered(); - void on_actionErase_map65_tx_log_triggered(); - void on_NBcheckBox_toggled(bool checked); - void on_actionJT65A_triggered(); - void on_actionJT65B_triggered(); - void on_actionJT65C_triggered(); - void on_NBslider_valueChanged(int value); - void on_actionAdjust_IQ_Calibration_triggered(); - void on_actionApply_IQ_Calibration_triggered(); - - void on_actionAFMHot_triggered(); - - void on_actionBlue_triggered(); - - void on_actionFUNcube_Dongle_triggered(); - -private: - Ui::MainWindow *ui; - qint32 m_nDevIn; - qint32 m_nDevOut; - qint32 m_idInt; - qint32 m_waterfallAvg; - qint32 m_DF; - qint32 m_tol; - qint32 m_QSOfreq0; - qint32 m_ntx; - qint32 m_pttPort; - qint32 m_astroFont; - qint32 m_timeout; - qint32 m_dPhi; - qint32 m_fCal; - qint32 m_txFreq; - qint32 m_setftx; - qint32 m_ndepth; - qint32 m_sec0; - qint32 m_map65RxLog; - qint32 m_nutc0; - qint32 m_mode65; - qint32 m_nrx; - qint32 m_hsym0; - qint32 m_paInDevice; - qint32 m_paOutDevice; - qint32 m_udpPort; - qint32 m_NBslider; - qint32 m_adjustIQ; - qint32 m_applyIQcal; - qint32 m_mult570; - - double m_fAdd; - double m_IQamp; - double m_IQphase; - double m_cal570; - - bool m_monitoring; - bool m_transmitting; - bool m_diskData; - bool m_loopall; - bool m_decoderBusy; - bool m_txFirst; - bool m_auto; - bool m_txMute; - bool m_restart; - bool m_killAll; - bool m_xpol; - bool m_xpolx; - bool m_call3Modified; - bool m_startAnother; - bool m_saveAll; - bool m_onlyEME; - bool m_widebandDecode; - bool m_kb8rq; - bool m_NB; - bool m_fs96000; - bool m_IQswap; - bool m_10db; - bool m_initIQplus; - - float m_gainx; - float m_gainy; - float m_phasex; - float m_phasey; - float m_pctZap; - - QRect m_astroGeom; - QRect m_wideGraphGeom; - QRect m_messagesGeom; - QRect m_bandMapGeom; - - QLabel* lab1; // labels in status bar - QLabel* lab2; - QLabel* lab3; - QLabel* lab4; - QLabel* lab5; - QLabel* lab6; - - QMessageBox msgBox0; - - QFuture* future1; - QFuture* future2; - QFutureWatcher* watcher1; - QFutureWatcher* watcher2; - - QProcess proc_m65; - QProcess proc_qthid; - - QString m_path; - QString m_pbdecoding_style1; - QString m_pbmonitor_style; - QString m_pbAutoOn_style; - QString m_messagesText; - QString m_bandmapText; - QString m_myCall; - QString m_myGrid; - QString m_hisCall; - QString m_hisGrid; - QString m_appDir; - QString m_saveDir; - QString m_azelDir; - QString m_dxccPfx; - QString m_palette; - QString m_dateTime; - QString m_mode; - QString m_colors; - - QHash m_worked; - - SoundInThread soundInThread; //Instantiate the audio threads - SoundOutThread soundOutThread; - -//---------------------------------------------------- private functions - void readSettings(); - void writeSettings(); - void createStatusBar(); - void updateStatusBar(); - void msgBox(QString t); - void genStdMsgs(QString rpt); - void lookup(); - void ba2msg(QByteArray ba, char* message); - void msgtype(QString t, QLineEdit* tx); - void stub(); -}; - -extern void getfile(QString fname, bool xpol, int idInt); -extern void savetf2(QString fname, bool xpol); -extern int killbyname(const char* progName); -extern void getDev(int* numDevices,char hostAPI_DeviceName[][50], - int minChan[], int maxChan[], - int minSpeed[], int maxSpeed[]); - -extern "C" { -//----------------------------------------------------- C and Fortran routines - void symspec_(int* k, int* nxpol, int* ndiskdat, int* nb, int* m_NBslider, - int* idphi, int* nfsample, float* fgreen, int* iqadjust, - int* iqapply, float* gainx, float* gainy, float* phasex, - float* phasey, float* rejectx, float* rejecty, float* px, - float* py, float s[], int* nkhz, int* nhsym, int* nzap, - float* slimit, uchar lstrong[]); - - void gen65_(char* msg, int* mode65, double* samfac, int* nsendingsh, - char* msgsent, short iwave[], int* nwave, int len1, int len2); - - int ptt_(int* nport, int* itx, int* iptt); - } - -#endif // MAINWINDOW_H +#ifndef MAINWINDOW_H +#define MAINWINDOW_H +#include +#include +#include +#include +#include +#include "soundin.h" +#include "soundout.h" +#include "commons.h" +#include "sleep.h" + +#define NFFT 32768 +#define NSMAX 5760000 + +//--------------------------------------------------------------- MainWindow +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + bool m_network; + +public slots: + void showSoundInError(const QString& errorMsg); + void showStatusMessage(const QString& statusMsg); + void dataSink(int k); + void diskDat(); + void diskWriteFinished(); + void freezeDecode(int n); + void readFromStdout(); + void readFromStderr(); + void m65_error(); + void guiUpdate(); + void doubleClickOnCall(QString hiscall, bool ctrl); + void doubleClickOnMessages(QString hiscall, QString t2); + +protected: + virtual void keyPressEvent( QKeyEvent *e ); + void closeEvent(QCloseEvent*); + virtual bool eventFilter(QObject *object, QEvent *event); + +private slots: + void on_tx1_editingFinished(); + void on_tx2_editingFinished(); + void on_tx3_editingFinished(); + void on_tx4_editingFinished(); + void on_tx5_editingFinished(); + void on_tx6_editingFinished(); + void on_actionDeviceSetup_triggered(); + void on_monitorButton_clicked(); + void on_actionExit_triggered(); + void on_actionAbout_triggered(); + void OnExit(); + void on_actionLinrad_triggered(); + void on_actionCuteSDR_triggered(); + void on_autoButton_clicked(); + void on_stopTxButton_clicked(); + void on_tolSpinBox_valueChanged(int arg1); + void on_actionAstro_Data_triggered(); + void on_stopButton_clicked(); + void on_actionOnline_Users_Guide_triggered(); + void on_actionWide_Waterfall_triggered(); + void on_actionBand_Map_triggered(); + void on_actionMessages_triggered(); + void on_actionOpen_triggered(); + void on_actionOpen_next_in_directory_triggered(); + void on_actionDecode_remaining_files_in_directory_triggered(); + void on_actionDelete_all_tf2_files_in_SaveDir_triggered(); + void on_actionErase_Band_Map_and_Messages_triggered(); + void on_actionFind_Delta_Phi_triggered(); + void on_actionF4_sets_Tx6_triggered(); + void on_actionOnly_EME_calls_triggered(); + void on_actionNo_shorthands_if_Tx1_triggered(); + void on_actionNo_Deep_Search_triggered(); + void on_actionNormal_Deep_Search_triggered(); + void on_actionAggressive_Deep_Search_triggered(); + void on_actionNone_triggered(); + void on_actionSave_all_triggered(); + void on_actionKeyboard_shortcuts_triggered(); + void on_actionSpecial_mouse_commands_triggered(); + void on_actionAvailable_suffixes_and_add_on_prefixes_triggered(); + void on_DecodeButton_clicked(); + void decode(); + void decodeBusy(bool b); + void on_EraseButton_clicked(); + void on_txb1_clicked(); + void on_txFirstCheckBox_stateChanged(int arg1); + void set_ntx(int n); + void on_txb2_clicked(); + void on_txb3_clicked(); + void on_txb4_clicked(); + void on_txb5_clicked(); + void on_txb6_clicked(); + void on_lookupButton_clicked(); + void on_addButton_clicked(); + void on_setTxFreqButton_clicked(); + void on_dxCallEntry_textChanged(const QString &arg1); + void on_dxGridEntry_textChanged(const QString &arg1); + void selectCall2(bool ctrl); + void on_genStdMsgsPushButton_clicked(); + void bumpDF(int n); + void on_logQSOButton_clicked(); + void on_actionErase_map65_rx_log_triggered(); + void on_actionErase_map65_tx_log_triggered(); + void on_NBcheckBox_toggled(bool checked); + void on_actionJT65A_triggered(); + void on_actionJT65B_triggered(); + void on_actionJT65C_triggered(); + void on_NBslider_valueChanged(int value); + void on_actionAdjust_IQ_Calibration_triggered(); + void on_actionApply_IQ_Calibration_triggered(); + + void on_actionAFMHot_triggered(); + + void on_actionBlue_triggered(); + + void on_actionFUNcube_Dongle_triggered(); + +private: + Ui::MainWindow *ui; + qint32 m_nDevIn; + qint32 m_nDevOut; + qint32 m_idInt; + qint32 m_waterfallAvg; + qint32 m_DF; + qint32 m_tol; + qint32 m_QSOfreq0; + qint32 m_ntx; + qint32 m_pttPort; + qint32 m_astroFont; + qint32 m_timeout; + qint32 m_dPhi; + qint32 m_fCal; + qint32 m_txFreq; + qint32 m_setftx; + qint32 m_ndepth; + qint32 m_sec0; + qint32 m_map65RxLog; + qint32 m_nutc0; + qint32 m_mode65; + qint32 m_nrx; + qint32 m_hsym0; + qint32 m_paInDevice; + qint32 m_paOutDevice; + qint32 m_udpPort; + qint32 m_NBslider; + qint32 m_adjustIQ; + qint32 m_applyIQcal; + qint32 m_mult570; + + double m_fAdd; + double m_IQamp; + double m_IQphase; + double m_cal570; + + bool m_monitoring; + bool m_transmitting; + bool m_diskData; + bool m_loopall; + bool m_decoderBusy; + bool m_txFirst; + bool m_auto; + bool m_txMute; + bool m_restart; + bool m_killAll; + bool m_xpol; + bool m_xpolx; + bool m_call3Modified; + bool m_startAnother; + bool m_saveAll; + bool m_onlyEME; + bool m_widebandDecode; + bool m_kb8rq; + bool m_NB; + bool m_fs96000; + bool m_IQswap; + bool m_10db; + bool m_initIQplus; + + float m_gainx; + float m_gainy; + float m_phasex; + float m_phasey; + float m_pctZap; + + QRect m_astroGeom; + QRect m_wideGraphGeom; + QRect m_messagesGeom; + QRect m_bandMapGeom; + + QLabel* lab1; // labels in status bar + QLabel* lab2; + QLabel* lab3; + QLabel* lab4; + QLabel* lab5; + QLabel* lab6; + + QMessageBox msgBox0; + + QFuture* future1; + QFuture* future2; + QFutureWatcher* watcher1; + QFutureWatcher* watcher2; + + QProcess proc_m65; + QProcess proc_qthid; + + QString m_path; + QString m_pbdecoding_style1; + QString m_pbmonitor_style; + QString m_pbAutoOn_style; + QString m_messagesText; + QString m_bandmapText; + QString m_myCall; + QString m_myGrid; + QString m_hisCall; + QString m_hisGrid; + QString m_appDir; + QString m_saveDir; + QString m_azelDir; + QString m_dxccPfx; + QString m_palette; + QString m_dateTime; + QString m_mode; + QString m_colors; + + QHash m_worked; + + SoundInThread soundInThread; //Instantiate the audio threads + SoundOutThread soundOutThread; + +//---------------------------------------------------- private functions + void readSettings(); + void writeSettings(); + void createStatusBar(); + void updateStatusBar(); + void msgBox(QString t); + void genStdMsgs(QString rpt); + void lookup(); + void ba2msg(QByteArray ba, char* message); + void msgtype(QString t, QLineEdit* tx); + void stub(); +}; + +extern void getfile(QString fname, bool xpol, int idInt); +extern void savetf2(QString fname, bool xpol); +extern int killbyname(const char* progName); +extern void getDev(int* numDevices,char hostAPI_DeviceName[][50], + int minChan[], int maxChan[], + int minSpeed[], int maxSpeed[]); + +extern "C" { +//----------------------------------------------------- C and Fortran routines + void symspec_(int* k, int* nxpol, int* ndiskdat, int* nb, int* m_NBslider, + int* idphi, int* nfsample, float* fgreen, int* iqadjust, + int* iqapply, float* gainx, float* gainy, float* phasex, + float* phasey, float* rejectx, float* rejecty, float* px, + float* py, float s[], int* nkhz, int* nhsym, int* nzap, + float* slimit, uchar lstrong[]); + + void gen65_(char* msg, int* mode65, double* samfac, int* nsendingsh, + char* msgsent, short iwave[], int* nwave, int len1, int len2); + + int ptt_(int* nport, int* itx, int* iptt); + } + +#endif // MAINWINDOW_H diff --git a/map65.pro b/map65.pro index a3ad06aac..c948f7b8f 100644 --- a/map65.pro +++ b/map65.pro @@ -1,77 +1,77 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2011-07-07T08:39:24 -# -#------------------------------------------------- - -QT += core gui network -CONFIG += qwt thread -#CONFIG += console - -TARGET = map65 -VERSION = 2.3.0 -TEMPLATE = app - -win32 { -DEFINES = WIN32 -DESTDIR = ../map65_install -F90 = g95 -g95.output = ${QMAKE_FILE_BASE}.o -g95.commands = $$F90 -c -O2 -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} -g95.input = F90_SOURCES -QMAKE_EXTRA_COMPILERS += g95 -} - -unix { -DEFINES = UNIX -DESTDIR = ../map65_install -F90 = gfortran -gfortran.output = ${QMAKE_FILE_BASE}.o -gfortran.commands = $$F90 -c -O2 -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} -gfortran.input = F90_SOURCES -QMAKE_EXTRA_COMPILERS += gfortran -} - -SOURCES += main.cpp mainwindow.cpp plotter.cpp about.cpp \ - soundin.cpp soundout.cpp devsetup.cpp \ - widegraph.cpp getfile.cpp messages.cpp bandmap.cpp \ - astro.cpp displaytext.cpp getdev.cpp - -win32 { -SOURCES += killbyname.cpp set570.cpp -} - -HEADERS += mainwindow.h plotter.h soundin.h soundout.h \ - about.h devsetup.h widegraph.h getfile.h messages.h \ - bandmap.h commons.h sleep.h astro.h displaytext.h \ - -DEFINES += __cplusplus - -FORMS += mainwindow.ui about.ui devsetup.ui widegraph.ui \ - messages.ui bandmap.ui astro.ui - -RC_FILE = map65.rc - -unix { -INCLUDEPATH += $$quote(/usr/include/qwt-qt4) -LIBS += -lfftw3f /usr/lib/libgfortran.so.3 -LIBS += ../map65/libm65/libm65.a -LIBS += /usr/lib/libqwt-qt4.so -LIBS += -lportaudio -#LIBS +- -lusb -} - -win32 { -INCLUDEPATH += c:/qwt-6.0.1/include -LIBS += ../map65/libm65/libm65.a -LIBS += ../map65/libfftw3f_win.a -LIBS += ../QtSupport/palir-02.dll -LIBS += libwsock32 -LIBS += C:/MinGW/lib/libf95.a -CONFIG(release) { - LIBS += C:/qwt-6.0.1/lib/qwt.dll -} else { - LIBS += C:/qwt-6.0.1/lib/qwtd.dll -} -LIBS += -lusb -} +#------------------------------------------------- +# +# Project created by QtCreator 2011-07-07T08:39:24 +# +#------------------------------------------------- + +QT += core gui network +CONFIG += qwt thread +#CONFIG += console + +TARGET = map65 +VERSION = 2.3.0 +TEMPLATE = app + +win32 { +DEFINES = WIN32 +DESTDIR = ../map65_install +F90 = g95 +g95.output = ${QMAKE_FILE_BASE}.o +g95.commands = $$F90 -c -O2 -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} +g95.input = F90_SOURCES +QMAKE_EXTRA_COMPILERS += g95 +} + +unix { +DEFINES = UNIX +DESTDIR = ../map65_install +F90 = gfortran +gfortran.output = ${QMAKE_FILE_BASE}.o +gfortran.commands = $$F90 -c -O2 -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} +gfortran.input = F90_SOURCES +QMAKE_EXTRA_COMPILERS += gfortran +} + +SOURCES += main.cpp mainwindow.cpp plotter.cpp about.cpp \ + soundin.cpp soundout.cpp devsetup.cpp \ + widegraph.cpp getfile.cpp messages.cpp bandmap.cpp \ + astro.cpp displaytext.cpp getdev.cpp + +win32 { +SOURCES += killbyname.cpp set570.cpp +} + +HEADERS += mainwindow.h plotter.h soundin.h soundout.h \ + about.h devsetup.h widegraph.h getfile.h messages.h \ + bandmap.h commons.h sleep.h astro.h displaytext.h \ + +DEFINES += __cplusplus + +FORMS += mainwindow.ui about.ui devsetup.ui widegraph.ui \ + messages.ui bandmap.ui astro.ui + +RC_FILE = map65.rc + +unix { +INCLUDEPATH += $$quote(/usr/include/qwt-qt4) +LIBS += -lfftw3f /usr/lib/libgfortran.so.3 +LIBS += ../map65/libm65/libm65.a +LIBS += /usr/lib/libqwt-qt4.so +LIBS += -lportaudio +#LIBS +- -lusb +} + +win32 { +INCLUDEPATH += c:/qwt-6.0.1/include +LIBS += ../map65/libm65/libm65.a +LIBS += ../map65/libfftw3f_win.a +LIBS += ../QtSupport/palir-02.dll +LIBS += libwsock32 +LIBS += C:/MinGW/lib/libf95.a +CONFIG(release) { + LIBS += C:/qwt-6.0.1/lib/qwt.dll +} else { + LIBS += C:/qwt-6.0.1/lib/qwtd.dll +} +LIBS += -lusb +} diff --git a/messages.cpp b/messages.cpp index 5d0302886..738df2191 100644 --- a/messages.cpp +++ b/messages.cpp @@ -1,81 +1,81 @@ -#include "messages.h" -#include "ui_messages.h" -#include "mainwindow.h" - -Messages::Messages(QWidget *parent) : - QDialog(parent), - ui(new Ui::Messages) -{ - ui->setupUi(this); - ui->messagesTextBrowser->setStyleSheet( \ - "QTextBrowser { background-color : #000066; color : red; }"); - ui->messagesTextBrowser->clear(); - m_cqOnly=false; - connect(ui->messagesTextBrowser,SIGNAL(selectCallsign(bool)),this, - SLOT(selectCallsign2(bool))); -} - -Messages::~Messages() -{ - delete ui; -} - -void Messages::setText(QString t) -{ - QString cfreq,cfreq0; - m_t=t; - - QString s="QTextBrowser{background-color: "+m_colorBackground+"}"; - ui->messagesTextBrowser->setStyleSheet(s); - - ui->messagesTextBrowser->clear(); - QStringList lines = t.split( "\n", QString::SkipEmptyParts ); - foreach( QString line, lines ) { - QString t1=line.mid(0,48); - if(m_cqOnly and t1.indexOf(" CQ ") < 0) continue; - int n=line.mid(48,2).toInt(); - if(n==0) ui->messagesTextBrowser->setTextColor(m_color0); - if(n==1) ui->messagesTextBrowser->setTextColor(m_color1); - if(n==2) ui->messagesTextBrowser->setTextColor(m_color2); - if(n>=3) ui->messagesTextBrowser->setTextColor(m_color3); - cfreq=t1.mid(0,3); - if(cfreq == cfreq0) { - t1=" " + t1.mid(3,-1); - } - cfreq0=cfreq; - ui->messagesTextBrowser->append(t1); - } -} - -void Messages::selectCallsign2(bool ctrl) -{ - QString t = ui->messagesTextBrowser->toPlainText(); //Full contents - int i=ui->messagesTextBrowser->textCursor().position(); - int i0=t.lastIndexOf(" ",i); - int i1=t.indexOf(" ",i); - QString hiscall=t.mid(i0+1,i1-i0-1); - if(hiscall!="") { - if(hiscall.length() < 13) { - QString t1 = t.mid(0,i); //contents up to text cursor - int i1=t1.lastIndexOf("\n") + 1; - QString t2 = t1.mid(i1,i-i1); //selected line - emit click2OnCallsign(hiscall,t2); - } - } -} - -void Messages::on_checkBox_stateChanged(int n) -{ - m_cqOnly = (n!=0); - setText(m_t); -} - -void Messages::setColors(QString t) -{ - m_colorBackground = "#"+t.mid(0,6); - m_color0 = "#"+t.mid(6,6); - m_color1 = "#"+t.mid(12,6); - m_color2 = "#"+t.mid(18,6); - m_color3 = "#"+t.mid(24,6); - setText(m_t); -} +#include "messages.h" +#include "ui_messages.h" +#include "mainwindow.h" + +Messages::Messages(QWidget *parent) : + QDialog(parent), + ui(new Ui::Messages) +{ + ui->setupUi(this); + ui->messagesTextBrowser->setStyleSheet( \ + "QTextBrowser { background-color : #000066; color : red; }"); + ui->messagesTextBrowser->clear(); + m_cqOnly=false; + connect(ui->messagesTextBrowser,SIGNAL(selectCallsign(bool)),this, + SLOT(selectCallsign2(bool))); +} + +Messages::~Messages() +{ + delete ui; +} + +void Messages::setText(QString t) +{ + QString cfreq,cfreq0; + m_t=t; + + QString s="QTextBrowser{background-color: "+m_colorBackground+"}"; + ui->messagesTextBrowser->setStyleSheet(s); + + ui->messagesTextBrowser->clear(); + QStringList lines = t.split( "\n", QString::SkipEmptyParts ); + foreach( QString line, lines ) { + QString t1=line.mid(0,48); + if(m_cqOnly and t1.indexOf(" CQ ") < 0) continue; + int n=line.mid(48,2).toInt(); + if(n==0) ui->messagesTextBrowser->setTextColor(m_color0); + if(n==1) ui->messagesTextBrowser->setTextColor(m_color1); + if(n==2) ui->messagesTextBrowser->setTextColor(m_color2); + if(n>=3) ui->messagesTextBrowser->setTextColor(m_color3); + cfreq=t1.mid(0,3); + if(cfreq == cfreq0) { + t1=" " + t1.mid(3,-1); + } + cfreq0=cfreq; + ui->messagesTextBrowser->append(t1); + } +} + +void Messages::selectCallsign2(bool ctrl) +{ + QString t = ui->messagesTextBrowser->toPlainText(); //Full contents + int i=ui->messagesTextBrowser->textCursor().position(); + int i0=t.lastIndexOf(" ",i); + int i1=t.indexOf(" ",i); + QString hiscall=t.mid(i0+1,i1-i0-1); + if(hiscall!="") { + if(hiscall.length() < 13) { + QString t1 = t.mid(0,i); //contents up to text cursor + int i1=t1.lastIndexOf("\n") + 1; + QString t2 = t1.mid(i1,i-i1); //selected line + emit click2OnCallsign(hiscall,t2); + } + } +} + +void Messages::on_checkBox_stateChanged(int n) +{ + m_cqOnly = (n!=0); + setText(m_t); +} + +void Messages::setColors(QString t) +{ + m_colorBackground = "#"+t.mid(0,6); + m_color0 = "#"+t.mid(6,6); + m_color1 = "#"+t.mid(12,6); + m_color2 = "#"+t.mid(18,6); + m_color3 = "#"+t.mid(24,6); + setText(m_t); +} diff --git a/messages.h b/messages.h index 7bf30ab8b..b264cdb39 100644 --- a/messages.h +++ b/messages.h @@ -1,40 +1,40 @@ -#ifndef MESSAGES_H -#define MESSAGES_H - -#include - -namespace Ui { - class Messages; -} - -class Messages : public QDialog -{ - Q_OBJECT - -public: - explicit Messages(QWidget *parent = 0); - void setText(QString t); - void setColors(QString t); - - ~Messages(); - -signals: - void click2OnCallsign(QString hiscall, QString t2); - -private slots: - void selectCallsign2(bool ctrl); - void on_checkBox_stateChanged(int arg1); - -private: - Ui::Messages *ui; - QString m_t; - QString m_colorBackground; - QString m_color0; - QString m_color1; - QString m_color2; - QString m_color3; - - bool m_cqOnly; -}; - -#endif // MESSAGES_H +#ifndef MESSAGES_H +#define MESSAGES_H + +#include + +namespace Ui { + class Messages; +} + +class Messages : public QDialog +{ + Q_OBJECT + +public: + explicit Messages(QWidget *parent = 0); + void setText(QString t); + void setColors(QString t); + + ~Messages(); + +signals: + void click2OnCallsign(QString hiscall, QString t2); + +private slots: + void selectCallsign2(bool ctrl); + void on_checkBox_stateChanged(int arg1); + +private: + Ui::Messages *ui; + QString m_t; + QString m_colorBackground; + QString m_color0; + QString m_color1; + QString m_color2; + QString m_color3; + + bool m_cqOnly; +}; + +#endif // MESSAGES_H diff --git a/paInputDevice.c b/paInputDevice.c index 940cdc03d..641bd859d 100644 --- a/paInputDevice.c +++ b/paInputDevice.c @@ -1,56 +1,56 @@ -#include -#include -#include - -void paInputDevice(int id, char* hostAPI_DeviceName, int* minChan, - int* maxChan, int* minSpeed, int* maxSpeed) -{ - int i, j, k; - char pa_device_name[128]; - char pa_device_hostapi[128]; - double pa_device_max_speed; - double pa_device_min_speed; - int pa_device_max_bytes; - int pa_device_min_bytes; - int pa_device_max_channels; - int pa_device_min_channels; - char p2[50]; - char *p,*p1; - static int iret, numDevices, valid_dev_cnt; - - iret=pa_get_device_info (id, - &pa_device_name, - &pa_device_hostapi, - &pa_device_max_speed, - &pa_device_min_speed, - &pa_device_max_bytes, - &pa_device_min_bytes, - &pa_device_max_channels, - &pa_device_min_channels); - - if (iret >= 0 ) { - valid_dev_cnt++; - - p1=""; - p=strstr(pa_device_hostapi,"MME"); - if(p!=NULL) p1="MME"; - p=strstr(pa_device_hostapi,"Direct"); - if(p!=NULL) p1="DirectX"; - p=strstr(pa_device_hostapi,"WASAPI"); - if(p!=NULL) p1="WASAPI"; - p=strstr(pa_device_hostapi,"ASIO"); - if(p!=NULL) p1="ASIO"; - p=strstr(pa_device_hostapi,"WDM-KS"); - if(p!=NULL) p1="WDM-KS"; - - sprintf(p2,"%-8s %-39s",p1,pa_device_name); - for(i=0; i<50; i++) { - hostAPI_DeviceName[i]=p2[i]; - if(p2[i]==0) break; - } - *minChan=pa_device_min_channels; - *maxChan=pa_device_max_channels; - *minSpeed=(int)pa_device_min_speed; - *maxSpeed=(int)pa_device_max_speed; - } -} +#include +#include +#include + +void paInputDevice(int id, char* hostAPI_DeviceName, int* minChan, + int* maxChan, int* minSpeed, int* maxSpeed) +{ + int i, j, k; + char pa_device_name[128]; + char pa_device_hostapi[128]; + double pa_device_max_speed; + double pa_device_min_speed; + int pa_device_max_bytes; + int pa_device_min_bytes; + int pa_device_max_channels; + int pa_device_min_channels; + char p2[50]; + char *p,*p1; + static int iret, numDevices, valid_dev_cnt; + + iret=pa_get_device_info (id, + &pa_device_name, + &pa_device_hostapi, + &pa_device_max_speed, + &pa_device_min_speed, + &pa_device_max_bytes, + &pa_device_min_bytes, + &pa_device_max_channels, + &pa_device_min_channels); + + if (iret >= 0 ) { + valid_dev_cnt++; + + p1=""; + p=strstr(pa_device_hostapi,"MME"); + if(p!=NULL) p1="MME"; + p=strstr(pa_device_hostapi,"Direct"); + if(p!=NULL) p1="DirectX"; + p=strstr(pa_device_hostapi,"WASAPI"); + if(p!=NULL) p1="WASAPI"; + p=strstr(pa_device_hostapi,"ASIO"); + if(p!=NULL) p1="ASIO"; + p=strstr(pa_device_hostapi,"WDM-KS"); + if(p!=NULL) p1="WDM-KS"; + + sprintf(p2,"%-8s %-39s",p1,pa_device_name); + for(i=0; i<50; i++) { + hostAPI_DeviceName[i]=p2[i]; + if(p2[i]==0) break; + } + *minChan=pa_device_min_channels; + *maxChan=pa_device_max_channels; + *minSpeed=(int)pa_device_min_speed; + *maxSpeed=(int)pa_device_max_speed; + } +} diff --git a/pa_get_device_info.c b/pa_get_device_info.c index e9cdf4737..ac6bc9ffc 100644 --- a/pa_get_device_info.c +++ b/pa_get_device_info.c @@ -1,172 +1,172 @@ -#include -#include - -#define MAX_LATENCY 20 - -PaStream *in_stream; -//------------------------------------------------------- pa_get_device_info -int pa_get_device_info (int n, - void *pa_device_name, - void *pa_device_hostapi, - double *pa_device_max_speed, - double *pa_device_min_speed, - int *pa_device_max_bytes, - int *pa_device_min_bytes, - int *pa_device_max_channels, - int *pa_device_min_channels ) -{ - - (void) n ; - (void) pa_device_name; - (void) pa_device_hostapi; - (void) pa_device_max_speed; - (void) pa_device_min_speed; - (void) pa_device_max_bytes; - (void) pa_device_min_bytes; - (void) pa_device_max_channels; - (void) pa_device_min_channels; - const PaDeviceInfo *deviceInfo; - PaError pa_err; - PaStreamParameters inputParameters; - int i,j, speed_warning; - int minBytes, maxBytes; - double maxStandardSampleRate; - double minStandardSampleRate; - int minInputChannels; - int maxInputChannels; - -// negative terminated list - static double standardSampleRates[] = {8000.0, 9600.0, - 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, - 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1}; -// ******************************************************* - - - *pa_device_max_speed=0; - *pa_device_min_speed=0; - *pa_device_max_bytes=0; - *pa_device_min_bytes=0; - *pa_device_max_channels=0; - *pa_device_min_channels=0; - minInputChannels=0; - if(n >= Pa_GetDeviceCount() ) return -1; - deviceInfo = Pa_GetDeviceInfo(n); - if (deviceInfo->maxInputChannels==0) return -1; - sprintf((char*)(pa_device_name),"%s",deviceInfo->name); - sprintf((char*)(pa_device_hostapi),"%s", - Pa_GetHostApiInfo( deviceInfo->hostApi )->name); - speed_warning=0; - -// bypass bug in Juli@ ASIO driver: -// this driver hangs after a Pa_IsFormatSupported call - i = strncmp(deviceInfo->name, "ASIO 2.0 - ESI Juli@", 19); - if (i == 0) { - minStandardSampleRate=44100; - maxStandardSampleRate=192000; - minBytes=1; - maxBytes=4; - maxInputChannels= deviceInfo->maxInputChannels; - minInputChannels= 1; - goto end_pa_get_device_info; - } - -// Investigate device capabilities. -// Check min and max samplerates with 16 bit data. - maxStandardSampleRate=0; - minStandardSampleRate=0; - inputParameters.device = n; - inputParameters.channelCount = deviceInfo->maxInputChannels; - inputParameters.sampleFormat = paInt16; - inputParameters.suggestedLatency = 0; - inputParameters.hostApiSpecificStreamInfo = NULL; - -// ************************************************************************ -//filter for portaudio Windows hostapi's with non experts. -//only allow ASIO or WASAPI or WDM-KS - i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, "ASIO", 4); - if (i==0 ) goto end_filter_hostapi; - i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, - "Windows WASAPI", 14); - if (i==0 ) goto end_filter_hostapi; - i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, - "Windows WDM-KS", 14); - if (i==0 ) goto end_filter_hostapi; - speed_warning=1; -end_filter_hostapi:; - -// ************************************************************************ - i=0; - while(standardSampleRates[i] > 0 && minStandardSampleRate==0) { - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - standardSampleRates[i] ); - if(pa_err == paDeviceUnavailable) return -1; - if(pa_err == paInvalidDevice) return -1; - if(pa_err == paFormatIsSupported ) { - minStandardSampleRate=standardSampleRates[i]; - } - i++; - } - if(minStandardSampleRate == 0) return -1; - j=i; - while(standardSampleRates[i] > 0 ) i++; - i--; - while(i >= j && maxStandardSampleRate==0) { - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - standardSampleRates[i] ); - if(pa_err == paDeviceUnavailable) return -1; - if(pa_err == paInvalidDevice) return -1; - if( pa_err == paFormatIsSupported ) { - maxStandardSampleRate=standardSampleRates[i]; - } - i--; - } - -// check if min SampleRate = max SampleRate - if(maxStandardSampleRate==0 && (minStandardSampleRate != 0)) { - maxStandardSampleRate= minStandardSampleRate; - } - -// check min and max bytes - minBytes=2; - maxBytes=2; - inputParameters.sampleFormat = paUInt8; - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - maxStandardSampleRate ); - if( pa_err == paFormatIsSupported ) { - minBytes=1; - } - inputParameters.sampleFormat = paInt32; - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - maxStandardSampleRate ); - if( pa_err == paFormatIsSupported ) { - maxBytes=4; - } - -// check min channel count - maxInputChannels= deviceInfo->maxInputChannels; - inputParameters.channelCount = 1; - inputParameters.sampleFormat = paInt16; - pa_err=paFormatIsSupported+32000; - while(pa_err != paFormatIsSupported && - ( inputParameters.channelCount < (maxInputChannels+1)) ) { - pa_err=Pa_IsFormatSupported(&inputParameters, NULL, - maxStandardSampleRate ); - inputParameters.channelCount++; - } - if( pa_err == paFormatIsSupported ) { - minInputChannels=inputParameters.channelCount-1; - } else { - return -1; - } - -end_pa_get_device_info:; - - *pa_device_max_speed=maxStandardSampleRate; - *pa_device_min_speed=minStandardSampleRate; - *pa_device_max_bytes=maxBytes; - *pa_device_min_bytes=minBytes; - *pa_device_max_channels= maxInputChannels; - *pa_device_min_channels= minInputChannels; - - return speed_warning; -} +#include +#include + +#define MAX_LATENCY 20 + +PaStream *in_stream; +//------------------------------------------------------- pa_get_device_info +int pa_get_device_info (int n, + void *pa_device_name, + void *pa_device_hostapi, + double *pa_device_max_speed, + double *pa_device_min_speed, + int *pa_device_max_bytes, + int *pa_device_min_bytes, + int *pa_device_max_channels, + int *pa_device_min_channels ) +{ + + (void) n ; + (void) pa_device_name; + (void) pa_device_hostapi; + (void) pa_device_max_speed; + (void) pa_device_min_speed; + (void) pa_device_max_bytes; + (void) pa_device_min_bytes; + (void) pa_device_max_channels; + (void) pa_device_min_channels; + const PaDeviceInfo *deviceInfo; + PaError pa_err; + PaStreamParameters inputParameters; + int i,j, speed_warning; + int minBytes, maxBytes; + double maxStandardSampleRate; + double minStandardSampleRate; + int minInputChannels; + int maxInputChannels; + +// negative terminated list + static double standardSampleRates[] = {8000.0, 9600.0, + 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, + 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1}; +// ******************************************************* + + + *pa_device_max_speed=0; + *pa_device_min_speed=0; + *pa_device_max_bytes=0; + *pa_device_min_bytes=0; + *pa_device_max_channels=0; + *pa_device_min_channels=0; + minInputChannels=0; + if(n >= Pa_GetDeviceCount() ) return -1; + deviceInfo = Pa_GetDeviceInfo(n); + if (deviceInfo->maxInputChannels==0) return -1; + sprintf((char*)(pa_device_name),"%s",deviceInfo->name); + sprintf((char*)(pa_device_hostapi),"%s", + Pa_GetHostApiInfo( deviceInfo->hostApi )->name); + speed_warning=0; + +// bypass bug in Juli@ ASIO driver: +// this driver hangs after a Pa_IsFormatSupported call + i = strncmp(deviceInfo->name, "ASIO 2.0 - ESI Juli@", 19); + if (i == 0) { + minStandardSampleRate=44100; + maxStandardSampleRate=192000; + minBytes=1; + maxBytes=4; + maxInputChannels= deviceInfo->maxInputChannels; + minInputChannels= 1; + goto end_pa_get_device_info; + } + +// Investigate device capabilities. +// Check min and max samplerates with 16 bit data. + maxStandardSampleRate=0; + minStandardSampleRate=0; + inputParameters.device = n; + inputParameters.channelCount = deviceInfo->maxInputChannels; + inputParameters.sampleFormat = paInt16; + inputParameters.suggestedLatency = 0; + inputParameters.hostApiSpecificStreamInfo = NULL; + +// ************************************************************************ +//filter for portaudio Windows hostapi's with non experts. +//only allow ASIO or WASAPI or WDM-KS + i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, "ASIO", 4); + if (i==0 ) goto end_filter_hostapi; + i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, + "Windows WASAPI", 14); + if (i==0 ) goto end_filter_hostapi; + i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, + "Windows WDM-KS", 14); + if (i==0 ) goto end_filter_hostapi; + speed_warning=1; +end_filter_hostapi:; + +// ************************************************************************ + i=0; + while(standardSampleRates[i] > 0 && minStandardSampleRate==0) { + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + standardSampleRates[i] ); + if(pa_err == paDeviceUnavailable) return -1; + if(pa_err == paInvalidDevice) return -1; + if(pa_err == paFormatIsSupported ) { + minStandardSampleRate=standardSampleRates[i]; + } + i++; + } + if(minStandardSampleRate == 0) return -1; + j=i; + while(standardSampleRates[i] > 0 ) i++; + i--; + while(i >= j && maxStandardSampleRate==0) { + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + standardSampleRates[i] ); + if(pa_err == paDeviceUnavailable) return -1; + if(pa_err == paInvalidDevice) return -1; + if( pa_err == paFormatIsSupported ) { + maxStandardSampleRate=standardSampleRates[i]; + } + i--; + } + +// check if min SampleRate = max SampleRate + if(maxStandardSampleRate==0 && (minStandardSampleRate != 0)) { + maxStandardSampleRate= minStandardSampleRate; + } + +// check min and max bytes + minBytes=2; + maxBytes=2; + inputParameters.sampleFormat = paUInt8; + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + maxStandardSampleRate ); + if( pa_err == paFormatIsSupported ) { + minBytes=1; + } + inputParameters.sampleFormat = paInt32; + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + maxStandardSampleRate ); + if( pa_err == paFormatIsSupported ) { + maxBytes=4; + } + +// check min channel count + maxInputChannels= deviceInfo->maxInputChannels; + inputParameters.channelCount = 1; + inputParameters.sampleFormat = paInt16; + pa_err=paFormatIsSupported+32000; + while(pa_err != paFormatIsSupported && + ( inputParameters.channelCount < (maxInputChannels+1)) ) { + pa_err=Pa_IsFormatSupported(&inputParameters, NULL, + maxStandardSampleRate ); + inputParameters.channelCount++; + } + if( pa_err == paFormatIsSupported ) { + minInputChannels=inputParameters.channelCount-1; + } else { + return -1; + } + +end_pa_get_device_info:; + + *pa_device_max_speed=maxStandardSampleRate; + *pa_device_min_speed=minStandardSampleRate; + *pa_device_max_bytes=maxBytes; + *pa_device_min_bytes=minBytes; + *pa_device_max_channels= maxInputChannels; + *pa_device_min_channels= minInputChannels; + + return speed_warning; +} diff --git a/plotter.cpp b/plotter.cpp index ddfe9e764..b56080b76 100644 --- a/plotter.cpp +++ b/plotter.cpp @@ -1,711 +1,711 @@ -#include "plotter.h" -#include -#include - -#define MAX_SCREENSIZE 2048 - - -CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor - QFrame(parent) -{ - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - setFocusPolicy(Qt::StrongFocus); - setAttribute(Qt::WA_PaintOnScreen,false); - setAutoFillBackground(false); - setAttribute(Qt::WA_OpaquePaintEvent, false); - setAttribute(Qt::WA_NoSystemBackground, true); - - m_StartFreq = 100; - m_nSpan=65; //Units: kHz - m_fSpan=(float)m_nSpan; - m_hdivs = HORZ_DIVS; - m_FreqUnits = 1; - m_Running = false; - m_paintEventBusy=false; - m_WaterfallPixmap = QPixmap(0,0); - m_ZoomWaterfallPixmap = QPixmap(0,0); - m_2DPixmap = QPixmap(0,0); - m_ScalePixmap = QPixmap(0,0); - m_ZoomScalePixmap = QPixmap(0,0); - m_Size = QSize(0,0); - m_fQSO = 125; - m_line = 0; - m_fSample = 96000; - m_paintAllZoom = false; -} - -CPlotter::~CPlotter() { } // Destructor - -QSize CPlotter::minimumSizeHint() const -{ - return QSize(50, 50); -} - -QSize CPlotter::sizeHint() const -{ - return QSize(180, 180); -} - -void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent() -{ - if(!size().isValid()) return; - if( m_Size != size() ) { - //if changed, resize pixmaps to new screensize - m_Size = size(); - int w = m_Size.width(); - int h = (m_Size.height()-60)/2; - m_WaterfallPixmap = QPixmap(w,h); - m_ZoomWaterfallPixmap = QPixmap(w,h); - m_2DPixmap = QPixmap(w,h); - m_WaterfallPixmap.fill(Qt::black); - m_ZoomWaterfallPixmap.fill(Qt::black); - m_2DPixmap.fill(Qt::black); - memset(m_zwf,0,32768*h); - m_ScalePixmap = QPixmap(w,30); - m_ZoomScalePixmap = QPixmap(w,30); //(no change on resize...) - m_ScalePixmap.fill(Qt::white); - m_ZoomScalePixmap.fill(Qt::yellow); - } - SetCenterFreq(-1); - DrawOverlay(); -} - -void CPlotter::paintEvent(QPaintEvent *) // paintEvent() -{ - static int x00=-99; - int ihr,imin; - - if(m_paintEventBusy) return; - m_paintEventBusy=true; - QPainter painter(this); - int w = m_Size.width(); - int h = (m_Size.height()-60)/2; - painter.drawPixmap(0,0,m_ScalePixmap); - painter.drawPixmap(0,30,m_WaterfallPixmap); - if(m_2Dspec) { - painter.drawPixmap(0,h+30,m_ScalePixmap); - painter.drawPixmap(0,h+60,m_2DPixmap); - m_paintEventBusy=false; - return; - } - - painter.drawPixmap(0,h+30,m_ZoomScalePixmap); - painter.drawPixmap(0,h+60,m_ZoomWaterfallPixmap); - - QRect target(0,h+30,w,30); // (x,y,width,height) - QRect source(0,0,w,30); - painter.drawPixmap(target,m_ZoomScalePixmap,source); - - float df=m_fSample/32768.0; - int x0=16384 + (0.001*(m_ZoomStartFreq+m_fCal)+m_fQSO-m_nkhz+1.27046) * \ - 1000.0/df + 0.5; - - QPainter painter2(&m_ZoomWaterfallPixmap); - for(int i=0; i254) y1=254; - if (s[i]>1.e29) y1=255; - m_hist1[y1]++; - painter1.setPen(m_ColorTbl[y1]); - painter1.drawPoint(i,0); - if(m_2Dspec) { - int y2 = gain*(y + 34 -m_plotZero); - if (y2<0) y2=0; - if (y2>254) y2=254; - if (s[i]>1.e29) y2=255; - if(strong != strong0 or i==w-1) { - painter2D.drawPolyline(LineBuf,j); - j=0; - strong0=strong; - if(strong0) painter2D.setPen(Qt::red); - if(!strong0) painter2D.setPen(Qt::green); - } - LineBuf[j].setX(i); - LineBuf[j].setY(h-y2); - j++; - } - } - - for(i=0; i<32768; i++) { - y = 10.0*log10(splot[i]); - int y1 = 5.0*gain*(y + 30 - m_plotZero); - if (y1<0) y1=0; - if (y1>254) y1=254; - if (splot[i]>1.e29) y1=255; - m_hist2[y1]++; - m_zwf[i]=y1; - } - - if(s[0]>1.0e29) m_line=0; - m_line++; - if(m_line == 15) { - UTCstr(); - painter1.setPen(m_ColorTbl[255]); - painter1.drawText(5,10,m_sutc); - } - update(); //trigger a new paintEvent -} - -void CPlotter::UTCstr() -{ - int ihr,imin; - if(datcom_.ndiskdat != 0) { - ihr=datcom_.nutc/100; - imin=datcom_.nutc%100; - } else { - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - imin=ms/60000; - ihr=imin/60; - imin=imin % 60; - } - sprintf(m_sutc,"%2.2d:%2.2d",ihr,imin); -} - -void CPlotter::DrawOverlay() //DrawOverlay() -{ - if(m_WaterfallPixmap.isNull()) return; - int w = m_WaterfallPixmap.width(); - int x,y; - float pixperdiv; - - QRect rect0; - QPainter painter0(&m_ScalePixmap); - painter0.initFrom(this); - - //create Font to use for scales - QFont Font("Arial"); - Font.setPointSize(12); - QFontMetrics metrics(Font); - Font.setWeight(QFont::Normal); - painter0.setFont(Font); - painter0.setPen(Qt::black); - - m_binsPerPixel = m_nSpan * 32768.0/(w*0.001*m_fSample) + 0.5; - double FreqPerDiv=5.0; - double df = m_binsPerPixel*0.001*m_fSample/32768.0; - m_hdivs = w*df/FreqPerDiv + 0.9999; - m_fSpan = w*df; - m_ScalePixmap.fill(Qt::white); - painter0.drawRect(0, 0, w, 30); - - //draw tick marks on wideband (upper) scale - pixperdiv = FreqPerDiv/df; - for( int i=1; i0 and x0 100) { - m_FreqUnits = 1; - FreqPerDiv = 200; - int w = m_WaterfallPixmap.width(); - float df=m_fSample/32768.0; - StartFreq = -w*df/2; - int n=StartFreq/FreqPerDiv; - StartFreq=n*200; - m_ZoomStartFreq = (int)StartFreq; - } - int numfractdigits = (int)log10((double)m_FreqUnits); - - if(1 == m_FreqUnits) { - //if units is Hz then just output integer freq - for(int i=0; i<=m_hdivs; i++) { - freq = StartFreq/(float)m_FreqUnits; - m_HDivText[i].setNum((int)freq); - StartFreq += FreqPerDiv; - } - return; - } - //here if is fractional frequency values - //so create max sized text based on frequency units - for(int i=0; i<=m_hdivs; i++) { - freq = StartFreq/(float)m_FreqUnits; - m_HDivText[i].setNum(freq,'f', numfractdigits); - StartFreq += FreqPerDiv; - } - //now find the division text with the longest non-zero digit - //to the right of the decimal point. - int max = 0; - for(i=0; i<=m_hdivs; i++) { - int dp = m_HDivText[i].indexOf('.'); - int l = m_HDivText[i].length()-1; - for(j=l; j>dp; j--) { - if(m_HDivText[i][j] != '0') - break; - } - if( (j-dp) > max) - max = j-dp; - } - //truncate all strings to maximum fractional length - StartFreq = m_CenterFreq - 0.5*m_fSpan; - for( i=0; i<=m_hdivs; i++) { - freq = (float)StartFreq/(float)m_FreqUnits; - m_HDivText[i].setNum(freq,'f', max); - StartFreq += FreqPerDiv; - } -} - -int CPlotter::XfromFreq(float f) //XfromFreq() -{ - float w = m_WaterfallPixmap.width(); - int x = (int) w * (f - m_StartFreq)/m_fSpan; - if(x<0 ) return 0; - if(x>(int)w) return m_WaterfallPixmap.width(); - return x; -} - -float CPlotter::FreqfromX(int x) //FreqfromX() -{ - float w = m_WaterfallPixmap.width(); - float f =m_CenterFreq - 0.5*m_fSpan + m_fSpan * x/w; - return f; -} - -void CPlotter::SetRunningState(bool running) //SetRunningState() -{ - m_Running = running; -} - -void CPlotter::setPlotZero(int plotZero) //setPlotZero() -{ - m_plotZero=plotZero; -} - -int CPlotter::getPlotZero() //getPlotZero() -{ - return m_plotZero; -} - -void CPlotter::setPlotGain(int plotGain) //setPlotGain() -{ - m_plotGain=plotGain; -} - -int CPlotter::getPlotGain() //getPlotGain() -{ - return m_plotGain; -} - -void CPlotter::SetCenterFreq(int f) //setCenterFreq() -{ -// f is the integer kHz portion of cfreq, from Linrad packets - if(f<0) f=m_nkhz; - int ns = (f+m_FreqOffset-0.5*m_fSpan)/5.0 + 0.5; - double fs = 5*ns; - m_CenterFreq = fs + 0.5*m_fSpan; -} - -qint64 CPlotter::centerFreq() //centerFreq() -{ - return m_CenterFreq; -} - -void CPlotter::SetStartFreq(quint64 f) //SetStartFreq() -{ - m_StartFreq=f; -// resizeEvent(NULL); - DrawOverlay(); -} - -qint64 CPlotter::startFreq() //startFreq() -{ - return m_StartFreq; -} - -void CPlotter::SetFreqOffset(quint64 f) //SetFreqOffset() -{ - m_FreqOffset=f; - DrawOverlay(); -} - -qint64 CPlotter::freqOffset() {return m_FreqOffset;} //freqOffset() -int CPlotter::plotWidth(){return m_WaterfallPixmap.width();} -void CPlotter::UpdateOverlay() {DrawOverlay();} -void CPlotter::setDataFromDisk(bool b) {m_dataFromDisk=b;} - -void CPlotter::setTol(int n) //setTol() -{ - m_tol=n; - DrawOverlay(); -} - -void CPlotter::setBinsPerPixel(int n) {m_binsPerPixel = n;} //set nbpp - -int CPlotter::binsPerPixel(){return m_binsPerPixel;} //get nbpp - -void CPlotter::setFQSO(int x, bool bf) //setFQSO() -{ - if(bf) { - m_fQSO=x; // x is freq in kHz - } else { - if(x<0) x=0; // x is pixel number - if(x>m_Size.width()) x=m_Size.width(); - m_fQSO = int(FreqfromX(x)+0.5); - m_xClick=x; - } - DrawOverlay(); - update(); -} - -void CPlotter::setFcal(int n) //setFcal() -{ - m_fCal=n; -} - -void CPlotter::setNkhz(int n) //setNkhz() -{ - m_nkhz=n; -} - -int CPlotter::fQSO() {return m_fQSO;} //get fQSO - -int CPlotter::DF() {return m_DF;} // get DF - -void CPlotter::mousePressEvent(QMouseEvent *event) //mousePressEvent -{ - int h = (m_Size.height()-60)/2; - int x=event->x(); - int y=event->y(); - if(y < h+30) { - setFQSO(x,false); // Wideband waterfall - } else { - m_DF=int(m_ZoomStartFreq + x*m_fSample/32768.0); // Zoomed waterfall - DrawOverlay(); - update(); - } -} - -void CPlotter::mouseDoubleClickEvent(QMouseEvent *event) //mouse2click -{ - int h = (m_Size.height()-60)/2; - int x=event->x(); - int y=event->y(); - if(y < h+30) { - m_DF=0; - setFQSO(x,false); - emit freezeDecode1(2); //### ??? - } else { - float f = m_ZoomStartFreq + x*m_fSample/32768.0; - m_DF=int(f); - emit freezeDecode1(1); - DrawOverlay(); - } -} - -int CPlotter::autoZero() //autoZero() -{ - m_z1=0; - m_z2=0; - int sum1=0; - for(int i=0; i<256; i++) { - sum1 += m_hist1[i]; - if(sum1 > m_Size.width()/2) { - m_z1=i; - break; - } - } - int sum2=0; - for(int i=0; i<256; i++) { - sum2 += m_hist2[i]; - if(sum2 > 16384) { - m_z2=i; - break; - } - } - double gain = pow(10.0,0.05*(m_plotGain+7)); -// double dz1 = (m_z1-38)/(5.0*gain); - double dz2 = (m_z2-28)/(5.0*gain); - if(m_z2 < 255) m_plotZero = int(m_plotZero + dz2 + 0.5); - return m_plotZero; -} - -void CPlotter::setNSpan(int n) //setNSpan() -{ - m_nSpan=n; -} - -void CPlotter::setPalette(QString palette) //setPalette() -{ - if(palette=="Linrad") { - float twopi=6.2831853; - float r,g,b,phi,x; - for(int i=0; i<256; i++) { - r=0.0; - if(i>105 and i<=198) { - phi=(twopi/4.0) * (i-105.0)/(198.0-105.0); - r=sin(phi); - } else if(i>=198) { - r=1.0; - } - - g=0.0; - if(i>35 and i<198) { - phi=(twopi/4.0) * (i-35.0)/(122.5-35.0); - g=0.625*sin(phi); - } else if(i>=198) { - x=(i-186.0); - g=-0.014 + 0.0144*x -0.00007*x*x +0.000002*x*x*x; - if(g>1.0) g=1.0; - } - - b=0.0; - if(i<=117) { - phi=(twopi/2.0) * i/117.0; - b=0.4531*sin(phi); - } else if(i>186) { - x=(i-186.0); - b=-0.014 + 0.0144*x -0.00007*x*x +0.000002*x*x*x; - if(b>1.0) b=1.0; - } - m_ColorTbl[i].setRgb(int(255.0*r),int(255.0*g),int(255.0*b)); - } - m_ColorTbl[255].setRgb(255,255,100); - - } - - if(palette=="CuteSDR") { - for( int i=0; i<256; i++) { - if( (i<43) ) - m_ColorTbl[i].setRgb( 0,0, 255*(i)/43); - if( (i>=43) && (i<87) ) - m_ColorTbl[i].setRgb( 0, 255*(i-43)/43, 255 ); - if( (i>=87) && (i<120) ) - m_ColorTbl[i].setRgb( 0,255, 255-(255*(i-87)/32)); - if( (i>=120) && (i<154) ) - m_ColorTbl[i].setRgb( (255*(i-120)/33), 255, 0); - if( (i>=154) && (i<217) ) - m_ColorTbl[i].setRgb( 255, 255 - (255*(i-154)/62), 0); - if( (i>=217) ) - m_ColorTbl[i].setRgb( 255, 0, 128*(i-217)/38); - } - m_ColorTbl[255].setRgb(255,255,100); - } - - if(palette=="Blue") { - FILE* fp=fopen("blue.dat","r"); - int n,r,g,b; - float xr,xg,xb; - for(int i=0; i<256; i++) { - fscanf(fp,"%d%f%f%f",&n,&xr,&xg,&xb); - r=255.0*xr + 0.5; - g=255.0*xg + 0.5; - b=255.0*xb + 0.5; - m_ColorTbl[i].setRgb(r,g,b); - } - } - - if(palette=="AFMHot") { - FILE* fp=fopen("afmhot.dat","r"); - int n,r,g,b; - float xr,xg,xb; - for(int i=0; i<256; i++) { - fscanf(fp,"%d%f%f%f",&n,&xr,&xg,&xb); - r=255.0*xr + 0.5; - g=255.0*xg + 0.5; - b=255.0*xb + 0.5; - m_ColorTbl[i].setRgb(r,g,b); - } - } - -} - -void CPlotter::setFsample(int n) -{ - m_fSample=n; -} - -void CPlotter::setMode65(int n) -{ - m_mode65=n; - DrawOverlay(); //Redraw scales and ticks - update(); //trigger a new paintEvent -} - -void CPlotter::set2Dspec(bool b) -{ - m_2Dspec=b; - m_paintAllZoom=!b; - DrawOverlay(); //Redraw scales and ticks - update(); //trigger a new paintEvent} -} - -double CPlotter::fGreen() -{ - return m_fGreen; -} +#include "plotter.h" +#include +#include + +#define MAX_SCREENSIZE 2048 + + +CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor + QFrame(parent) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setFocusPolicy(Qt::StrongFocus); + setAttribute(Qt::WA_PaintOnScreen,false); + setAutoFillBackground(false); + setAttribute(Qt::WA_OpaquePaintEvent, false); + setAttribute(Qt::WA_NoSystemBackground, true); + + m_StartFreq = 100; + m_nSpan=65; //Units: kHz + m_fSpan=(float)m_nSpan; + m_hdivs = HORZ_DIVS; + m_FreqUnits = 1; + m_Running = false; + m_paintEventBusy=false; + m_WaterfallPixmap = QPixmap(0,0); + m_ZoomWaterfallPixmap = QPixmap(0,0); + m_2DPixmap = QPixmap(0,0); + m_ScalePixmap = QPixmap(0,0); + m_ZoomScalePixmap = QPixmap(0,0); + m_Size = QSize(0,0); + m_fQSO = 125; + m_line = 0; + m_fSample = 96000; + m_paintAllZoom = false; +} + +CPlotter::~CPlotter() { } // Destructor + +QSize CPlotter::minimumSizeHint() const +{ + return QSize(50, 50); +} + +QSize CPlotter::sizeHint() const +{ + return QSize(180, 180); +} + +void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent() +{ + if(!size().isValid()) return; + if( m_Size != size() ) { + //if changed, resize pixmaps to new screensize + m_Size = size(); + int w = m_Size.width(); + int h = (m_Size.height()-60)/2; + m_WaterfallPixmap = QPixmap(w,h); + m_ZoomWaterfallPixmap = QPixmap(w,h); + m_2DPixmap = QPixmap(w,h); + m_WaterfallPixmap.fill(Qt::black); + m_ZoomWaterfallPixmap.fill(Qt::black); + m_2DPixmap.fill(Qt::black); + memset(m_zwf,0,32768*h); + m_ScalePixmap = QPixmap(w,30); + m_ZoomScalePixmap = QPixmap(w,30); //(no change on resize...) + m_ScalePixmap.fill(Qt::white); + m_ZoomScalePixmap.fill(Qt::yellow); + } + SetCenterFreq(-1); + DrawOverlay(); +} + +void CPlotter::paintEvent(QPaintEvent *) // paintEvent() +{ + static int x00=-99; + int ihr,imin; + + if(m_paintEventBusy) return; + m_paintEventBusy=true; + QPainter painter(this); + int w = m_Size.width(); + int h = (m_Size.height()-60)/2; + painter.drawPixmap(0,0,m_ScalePixmap); + painter.drawPixmap(0,30,m_WaterfallPixmap); + if(m_2Dspec) { + painter.drawPixmap(0,h+30,m_ScalePixmap); + painter.drawPixmap(0,h+60,m_2DPixmap); + m_paintEventBusy=false; + return; + } + + painter.drawPixmap(0,h+30,m_ZoomScalePixmap); + painter.drawPixmap(0,h+60,m_ZoomWaterfallPixmap); + + QRect target(0,h+30,w,30); // (x,y,width,height) + QRect source(0,0,w,30); + painter.drawPixmap(target,m_ZoomScalePixmap,source); + + float df=m_fSample/32768.0; + int x0=16384 + (0.001*(m_ZoomStartFreq+m_fCal)+m_fQSO-m_nkhz+1.27046) * \ + 1000.0/df + 0.5; + + QPainter painter2(&m_ZoomWaterfallPixmap); + for(int i=0; i254) y1=254; + if (s[i]>1.e29) y1=255; + m_hist1[y1]++; + painter1.setPen(m_ColorTbl[y1]); + painter1.drawPoint(i,0); + if(m_2Dspec) { + int y2 = gain*(y + 34 -m_plotZero); + if (y2<0) y2=0; + if (y2>254) y2=254; + if (s[i]>1.e29) y2=255; + if(strong != strong0 or i==w-1) { + painter2D.drawPolyline(LineBuf,j); + j=0; + strong0=strong; + if(strong0) painter2D.setPen(Qt::red); + if(!strong0) painter2D.setPen(Qt::green); + } + LineBuf[j].setX(i); + LineBuf[j].setY(h-y2); + j++; + } + } + + for(i=0; i<32768; i++) { + y = 10.0*log10(splot[i]); + int y1 = 5.0*gain*(y + 30 - m_plotZero); + if (y1<0) y1=0; + if (y1>254) y1=254; + if (splot[i]>1.e29) y1=255; + m_hist2[y1]++; + m_zwf[i]=y1; + } + + if(s[0]>1.0e29) m_line=0; + m_line++; + if(m_line == 15) { + UTCstr(); + painter1.setPen(m_ColorTbl[255]); + painter1.drawText(5,10,m_sutc); + } + update(); //trigger a new paintEvent +} + +void CPlotter::UTCstr() +{ + int ihr,imin; + if(datcom_.ndiskdat != 0) { + ihr=datcom_.nutc/100; + imin=datcom_.nutc%100; + } else { + qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; + imin=ms/60000; + ihr=imin/60; + imin=imin % 60; + } + sprintf(m_sutc,"%2.2d:%2.2d",ihr,imin); +} + +void CPlotter::DrawOverlay() //DrawOverlay() +{ + if(m_WaterfallPixmap.isNull()) return; + int w = m_WaterfallPixmap.width(); + int x,y; + float pixperdiv; + + QRect rect0; + QPainter painter0(&m_ScalePixmap); + painter0.initFrom(this); + + //create Font to use for scales + QFont Font("Arial"); + Font.setPointSize(12); + QFontMetrics metrics(Font); + Font.setWeight(QFont::Normal); + painter0.setFont(Font); + painter0.setPen(Qt::black); + + m_binsPerPixel = m_nSpan * 32768.0/(w*0.001*m_fSample) + 0.5; + double FreqPerDiv=5.0; + double df = m_binsPerPixel*0.001*m_fSample/32768.0; + m_hdivs = w*df/FreqPerDiv + 0.9999; + m_fSpan = w*df; + m_ScalePixmap.fill(Qt::white); + painter0.drawRect(0, 0, w, 30); + + //draw tick marks on wideband (upper) scale + pixperdiv = FreqPerDiv/df; + for( int i=1; i0 and x0 100) { + m_FreqUnits = 1; + FreqPerDiv = 200; + int w = m_WaterfallPixmap.width(); + float df=m_fSample/32768.0; + StartFreq = -w*df/2; + int n=StartFreq/FreqPerDiv; + StartFreq=n*200; + m_ZoomStartFreq = (int)StartFreq; + } + int numfractdigits = (int)log10((double)m_FreqUnits); + + if(1 == m_FreqUnits) { + //if units is Hz then just output integer freq + for(int i=0; i<=m_hdivs; i++) { + freq = StartFreq/(float)m_FreqUnits; + m_HDivText[i].setNum((int)freq); + StartFreq += FreqPerDiv; + } + return; + } + //here if is fractional frequency values + //so create max sized text based on frequency units + for(int i=0; i<=m_hdivs; i++) { + freq = StartFreq/(float)m_FreqUnits; + m_HDivText[i].setNum(freq,'f', numfractdigits); + StartFreq += FreqPerDiv; + } + //now find the division text with the longest non-zero digit + //to the right of the decimal point. + int max = 0; + for(i=0; i<=m_hdivs; i++) { + int dp = m_HDivText[i].indexOf('.'); + int l = m_HDivText[i].length()-1; + for(j=l; j>dp; j--) { + if(m_HDivText[i][j] != '0') + break; + } + if( (j-dp) > max) + max = j-dp; + } + //truncate all strings to maximum fractional length + StartFreq = m_CenterFreq - 0.5*m_fSpan; + for( i=0; i<=m_hdivs; i++) { + freq = (float)StartFreq/(float)m_FreqUnits; + m_HDivText[i].setNum(freq,'f', max); + StartFreq += FreqPerDiv; + } +} + +int CPlotter::XfromFreq(float f) //XfromFreq() +{ + float w = m_WaterfallPixmap.width(); + int x = (int) w * (f - m_StartFreq)/m_fSpan; + if(x<0 ) return 0; + if(x>(int)w) return m_WaterfallPixmap.width(); + return x; +} + +float CPlotter::FreqfromX(int x) //FreqfromX() +{ + float w = m_WaterfallPixmap.width(); + float f =m_CenterFreq - 0.5*m_fSpan + m_fSpan * x/w; + return f; +} + +void CPlotter::SetRunningState(bool running) //SetRunningState() +{ + m_Running = running; +} + +void CPlotter::setPlotZero(int plotZero) //setPlotZero() +{ + m_plotZero=plotZero; +} + +int CPlotter::getPlotZero() //getPlotZero() +{ + return m_plotZero; +} + +void CPlotter::setPlotGain(int plotGain) //setPlotGain() +{ + m_plotGain=plotGain; +} + +int CPlotter::getPlotGain() //getPlotGain() +{ + return m_plotGain; +} + +void CPlotter::SetCenterFreq(int f) //setCenterFreq() +{ +// f is the integer kHz portion of cfreq, from Linrad packets + if(f<0) f=m_nkhz; + int ns = (f+m_FreqOffset-0.5*m_fSpan)/5.0 + 0.5; + double fs = 5*ns; + m_CenterFreq = fs + 0.5*m_fSpan; +} + +qint64 CPlotter::centerFreq() //centerFreq() +{ + return m_CenterFreq; +} + +void CPlotter::SetStartFreq(quint64 f) //SetStartFreq() +{ + m_StartFreq=f; +// resizeEvent(NULL); + DrawOverlay(); +} + +qint64 CPlotter::startFreq() //startFreq() +{ + return m_StartFreq; +} + +void CPlotter::SetFreqOffset(quint64 f) //SetFreqOffset() +{ + m_FreqOffset=f; + DrawOverlay(); +} + +qint64 CPlotter::freqOffset() {return m_FreqOffset;} //freqOffset() +int CPlotter::plotWidth(){return m_WaterfallPixmap.width();} +void CPlotter::UpdateOverlay() {DrawOverlay();} +void CPlotter::setDataFromDisk(bool b) {m_dataFromDisk=b;} + +void CPlotter::setTol(int n) //setTol() +{ + m_tol=n; + DrawOverlay(); +} + +void CPlotter::setBinsPerPixel(int n) {m_binsPerPixel = n;} //set nbpp + +int CPlotter::binsPerPixel(){return m_binsPerPixel;} //get nbpp + +void CPlotter::setFQSO(int x, bool bf) //setFQSO() +{ + if(bf) { + m_fQSO=x; // x is freq in kHz + } else { + if(x<0) x=0; // x is pixel number + if(x>m_Size.width()) x=m_Size.width(); + m_fQSO = int(FreqfromX(x)+0.5); + m_xClick=x; + } + DrawOverlay(); + update(); +} + +void CPlotter::setFcal(int n) //setFcal() +{ + m_fCal=n; +} + +void CPlotter::setNkhz(int n) //setNkhz() +{ + m_nkhz=n; +} + +int CPlotter::fQSO() {return m_fQSO;} //get fQSO + +int CPlotter::DF() {return m_DF;} // get DF + +void CPlotter::mousePressEvent(QMouseEvent *event) //mousePressEvent +{ + int h = (m_Size.height()-60)/2; + int x=event->x(); + int y=event->y(); + if(y < h+30) { + setFQSO(x,false); // Wideband waterfall + } else { + m_DF=int(m_ZoomStartFreq + x*m_fSample/32768.0); // Zoomed waterfall + DrawOverlay(); + update(); + } +} + +void CPlotter::mouseDoubleClickEvent(QMouseEvent *event) //mouse2click +{ + int h = (m_Size.height()-60)/2; + int x=event->x(); + int y=event->y(); + if(y < h+30) { + m_DF=0; + setFQSO(x,false); + emit freezeDecode1(2); //### ??? + } else { + float f = m_ZoomStartFreq + x*m_fSample/32768.0; + m_DF=int(f); + emit freezeDecode1(1); + DrawOverlay(); + } +} + +int CPlotter::autoZero() //autoZero() +{ + m_z1=0; + m_z2=0; + int sum1=0; + for(int i=0; i<256; i++) { + sum1 += m_hist1[i]; + if(sum1 > m_Size.width()/2) { + m_z1=i; + break; + } + } + int sum2=0; + for(int i=0; i<256; i++) { + sum2 += m_hist2[i]; + if(sum2 > 16384) { + m_z2=i; + break; + } + } + double gain = pow(10.0,0.05*(m_plotGain+7)); +// double dz1 = (m_z1-38)/(5.0*gain); + double dz2 = (m_z2-28)/(5.0*gain); + if(m_z2 < 255) m_plotZero = int(m_plotZero + dz2 + 0.5); + return m_plotZero; +} + +void CPlotter::setNSpan(int n) //setNSpan() +{ + m_nSpan=n; +} + +void CPlotter::setPalette(QString palette) //setPalette() +{ + if(palette=="Linrad") { + float twopi=6.2831853; + float r,g,b,phi,x; + for(int i=0; i<256; i++) { + r=0.0; + if(i>105 and i<=198) { + phi=(twopi/4.0) * (i-105.0)/(198.0-105.0); + r=sin(phi); + } else if(i>=198) { + r=1.0; + } + + g=0.0; + if(i>35 and i<198) { + phi=(twopi/4.0) * (i-35.0)/(122.5-35.0); + g=0.625*sin(phi); + } else if(i>=198) { + x=(i-186.0); + g=-0.014 + 0.0144*x -0.00007*x*x +0.000002*x*x*x; + if(g>1.0) g=1.0; + } + + b=0.0; + if(i<=117) { + phi=(twopi/2.0) * i/117.0; + b=0.4531*sin(phi); + } else if(i>186) { + x=(i-186.0); + b=-0.014 + 0.0144*x -0.00007*x*x +0.000002*x*x*x; + if(b>1.0) b=1.0; + } + m_ColorTbl[i].setRgb(int(255.0*r),int(255.0*g),int(255.0*b)); + } + m_ColorTbl[255].setRgb(255,255,100); + + } + + if(palette=="CuteSDR") { + for( int i=0; i<256; i++) { + if( (i<43) ) + m_ColorTbl[i].setRgb( 0,0, 255*(i)/43); + if( (i>=43) && (i<87) ) + m_ColorTbl[i].setRgb( 0, 255*(i-43)/43, 255 ); + if( (i>=87) && (i<120) ) + m_ColorTbl[i].setRgb( 0,255, 255-(255*(i-87)/32)); + if( (i>=120) && (i<154) ) + m_ColorTbl[i].setRgb( (255*(i-120)/33), 255, 0); + if( (i>=154) && (i<217) ) + m_ColorTbl[i].setRgb( 255, 255 - (255*(i-154)/62), 0); + if( (i>=217) ) + m_ColorTbl[i].setRgb( 255, 0, 128*(i-217)/38); + } + m_ColorTbl[255].setRgb(255,255,100); + } + + if(palette=="Blue") { + FILE* fp=fopen("blue.dat","r"); + int n,r,g,b; + float xr,xg,xb; + for(int i=0; i<256; i++) { + fscanf(fp,"%d%f%f%f",&n,&xr,&xg,&xb); + r=255.0*xr + 0.5; + g=255.0*xg + 0.5; + b=255.0*xb + 0.5; + m_ColorTbl[i].setRgb(r,g,b); + } + } + + if(palette=="AFMHot") { + FILE* fp=fopen("afmhot.dat","r"); + int n,r,g,b; + float xr,xg,xb; + for(int i=0; i<256; i++) { + fscanf(fp,"%d%f%f%f",&n,&xr,&xg,&xb); + r=255.0*xr + 0.5; + g=255.0*xg + 0.5; + b=255.0*xb + 0.5; + m_ColorTbl[i].setRgb(r,g,b); + } + } + +} + +void CPlotter::setFsample(int n) +{ + m_fSample=n; +} + +void CPlotter::setMode65(int n) +{ + m_mode65=n; + DrawOverlay(); //Redraw scales and ticks + update(); //trigger a new paintEvent +} + +void CPlotter::set2Dspec(bool b) +{ + m_2Dspec=b; + m_paintAllZoom=!b; + DrawOverlay(); //Redraw scales and ticks + update(); //trigger a new paintEvent} +} + +double CPlotter::fGreen() +{ + return m_fGreen; +} diff --git a/plotter.h b/plotter.h index 2a4241571..4e3763a32 100644 --- a/plotter.h +++ b/plotter.h @@ -1,127 +1,127 @@ -/////////////////////////////////////////////////////////////////////////// -// Some code in this file and accompanying files is based on work by -// Moe Wheatley, AE4Y, released under the "Simplified BSD License". -// For more details see the accompanying file LICENSE_WHEATLEY.TXT -/////////////////////////////////////////////////////////////////////////// - -#ifndef PLOTTER_H -#define PLOTTER_H - -#include -#include -#include -#include -#include "commons.h" - -#define VERT_DIVS 7 //specify grid screen divisions -#define HORZ_DIVS 20 - -class CPlotter : public QFrame -{ - Q_OBJECT -public: - explicit CPlotter(QWidget *parent = 0); - ~CPlotter(); - - QSize minimumSizeHint() const; - QSize sizeHint() const; - QColor m_ColorTbl[256]; - int m_plotZero; - int m_plotGain; - float m_fSpan; - qint32 m_nSpan; - qint32 m_binsPerPixel; - qint32 m_fQSO; - qint32 m_DF; - qint32 m_tol; - qint32 m_fCal; - - void draw(float sw[], int i0, float splot[]); //Update the waterfalls - void SetRunningState(bool running); - void setPlotZero(int plotZero); - int getPlotZero(); - void setPlotGain(int plotGain); - int getPlotGain(); - void SetCenterFreq(int f); - qint64 centerFreq(); - void SetStartFreq(quint64 f); - qint64 startFreq(); - void SetFreqOffset(quint64 f); - qint64 freqOffset(); - int plotWidth(); - void setNSpan(int n); - void UpdateOverlay(); - void setDataFromDisk(bool b); - void setTol(int n); - void setBinsPerPixel(int n); - int binsPerPixel(); - void setFQSO(int n, bool bf); - void setFcal(int n); - void setNkhz(int n); - void DrawOverlay(); - int fQSO(); - int DF(); - int autoZero(); - void setPalette(QString palette); - void setFsample(int n); - void setMode65(int n); - void set2Dspec(bool b); - double fGreen(); - -signals: - void freezeDecode0(int n); - void freezeDecode1(int n); - -protected: - //re-implemented widget event handlers - void paintEvent(QPaintEvent *event); - void resizeEvent(QResizeEvent* event); - -private: - - void MakeFrequencyStrs(); - void UTCstr(); - int XfromFreq(float f); - float FreqfromX(int x); - qint64 RoundFreq(qint64 freq, int resolution); - - QPixmap m_WaterfallPixmap; - QPixmap m_ZoomWaterfallPixmap; - QPixmap m_2DPixmap; - unsigned char m_zwf[32768*400]; - QPixmap m_ScalePixmap; - QPixmap m_ZoomScalePixmap; - QSize m_Size; - QString m_Str; - QString m_HDivText[483]; - bool m_Running; - bool m_paintEventBusy; - bool m_2Dspec; - bool m_paintAllZoom; - double m_CenterFreq; - double m_fGreen; - qint64 m_StartFreq; - qint64 m_ZoomStartFreq; - qint64 m_FreqOffset; - qint32 m_dBStepSize; - qint32 m_FreqUnits; - qint32 m_hdivs; - bool m_dataFromDisk; - char m_sutc[5]; - qint32 m_line; - qint32 m_hist1[256]; - qint32 m_hist2[256]; - qint32 m_z1; - qint32 m_z2; - qint32 m_nkhz; - qint32 m_fSample; - qint32 m_mode65; - qint32 m_i0; - qint32 m_xClick; - -private slots: - void mousePressEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); -}; - -#endif // PLOTTER_H +/////////////////////////////////////////////////////////////////////////// +// Some code in this file and accompanying files is based on work by +// Moe Wheatley, AE4Y, released under the "Simplified BSD License". +// For more details see the accompanying file LICENSE_WHEATLEY.TXT +/////////////////////////////////////////////////////////////////////////// + +#ifndef PLOTTER_H +#define PLOTTER_H + +#include +#include +#include +#include +#include "commons.h" + +#define VERT_DIVS 7 //specify grid screen divisions +#define HORZ_DIVS 20 + +class CPlotter : public QFrame +{ + Q_OBJECT +public: + explicit CPlotter(QWidget *parent = 0); + ~CPlotter(); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + QColor m_ColorTbl[256]; + int m_plotZero; + int m_plotGain; + float m_fSpan; + qint32 m_nSpan; + qint32 m_binsPerPixel; + qint32 m_fQSO; + qint32 m_DF; + qint32 m_tol; + qint32 m_fCal; + + void draw(float sw[], int i0, float splot[]); //Update the waterfalls + void SetRunningState(bool running); + void setPlotZero(int plotZero); + int getPlotZero(); + void setPlotGain(int plotGain); + int getPlotGain(); + void SetCenterFreq(int f); + qint64 centerFreq(); + void SetStartFreq(quint64 f); + qint64 startFreq(); + void SetFreqOffset(quint64 f); + qint64 freqOffset(); + int plotWidth(); + void setNSpan(int n); + void UpdateOverlay(); + void setDataFromDisk(bool b); + void setTol(int n); + void setBinsPerPixel(int n); + int binsPerPixel(); + void setFQSO(int n, bool bf); + void setFcal(int n); + void setNkhz(int n); + void DrawOverlay(); + int fQSO(); + int DF(); + int autoZero(); + void setPalette(QString palette); + void setFsample(int n); + void setMode65(int n); + void set2Dspec(bool b); + double fGreen(); + +signals: + void freezeDecode0(int n); + void freezeDecode1(int n); + +protected: + //re-implemented widget event handlers + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent* event); + +private: + + void MakeFrequencyStrs(); + void UTCstr(); + int XfromFreq(float f); + float FreqfromX(int x); + qint64 RoundFreq(qint64 freq, int resolution); + + QPixmap m_WaterfallPixmap; + QPixmap m_ZoomWaterfallPixmap; + QPixmap m_2DPixmap; + unsigned char m_zwf[32768*400]; + QPixmap m_ScalePixmap; + QPixmap m_ZoomScalePixmap; + QSize m_Size; + QString m_Str; + QString m_HDivText[483]; + bool m_Running; + bool m_paintEventBusy; + bool m_2Dspec; + bool m_paintAllZoom; + double m_CenterFreq; + double m_fGreen; + qint64 m_StartFreq; + qint64 m_ZoomStartFreq; + qint64 m_FreqOffset; + qint32 m_dBStepSize; + qint32 m_FreqUnits; + qint32 m_hdivs; + bool m_dataFromDisk; + char m_sutc[5]; + qint32 m_line; + qint32 m_hist1[256]; + qint32 m_hist2[256]; + qint32 m_z1; + qint32 m_z2; + qint32 m_nkhz; + qint32 m_fSample; + qint32 m_mode65; + qint32 m_i0; + qint32 m_xClick; + +private slots: + void mousePressEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); +}; + +#endif // PLOTTER_H diff --git a/set570.cpp b/set570.cpp index 2a94bd2ae..0380963c3 100644 --- a/set570.cpp +++ b/set570.cpp @@ -1,275 +1,275 @@ - -/* Linux / Windows program to control the frequency of a si570 synthesizer - ON5GN 6 jan 2012 - Under Linux: - -use the linux version of function void si570_sleep(int us) - -compile with - gcc -Wall -o set_si570_freq set_si570_freq.c -lusb -lm - -run with sudo ./set_si570_freq - Under Windows: - -use the windows version of function void si570_sleep(int us) - -compile with mingw - C:\mingw\bin\mingw32-gcc -Wall -o set_si570_freq set_si570_freq.c -lusb -lm - -run with set_si570_freq.exe -*/ - -#include /* Standard input/output definitions */ -#include /* String function definitions */ -#include /* UNIX standard function definitions */ -#include -#include -#include - -#define USB_SUCCESS 0 -#define USB_ERROR_NOTFOUND 1 -#define USB_ERROR_ACCESS 2 -#define USB_ERROR_IO 3 -#define VENDOR_NAME "www.obdev.at" -#define PRODUCT_NAME "DG8SAQ-I2C" -#define USBDEV_SHARED_VENDOR 0x16C0 // VOTI VID -#define USBDEV_SHARED_PRODUCT 0x05DC // OBDEV PID - // Use obdev's generic shared VID/PID pair - // following the rules outlined in - // firmware/usbdrv/USBID-License.txt. -#define REQUEST_SET_FREQ_BY_VALUE 0x32 -#define MAX_USB_ERR_CNT 6 - -double freq_parm; -double delay_average; -int from_freq; -int to_freq; -int increment_freq; -int retval = -1; -int display_freq = -1; -int delay; -usb_dev_handle *global_si570usb_handle = NULL; - -// ********sleep functions*************** -//use this function under LINUX -/* -void si570_sleep(int us) -{ -usleep(us); -} -*/ - -//use this function under WINDOWS -void si570_sleep(int us) -{ - Sleep(us/1000); -} - -double round(double x) -{ - int i=x+0.5; - return (double)i; -} - -double current_time(void) //for delay measurements -{ - struct timeval t; - gettimeofday(&t,NULL); - return 0.000001*t.tv_usec+t.tv_sec; -} - -int usbGetStringAscii(usb_dev_handle *dev, int my_index, - int langid, char *buf, int buflen); -unsigned char Si570usbOpenDevice(usb_dev_handle **device, char *usbSerialID); -void setLongWord( int value, char * bytes); -int setFreqByValue(usb_dev_handle * handle, double frequency); -void sweepa_freq(void); -void sweepm_freq(void); - -int set570(double freq_MHz) -{ - char * my_usbSerialID = NULL; - -// MAIN MENU DIALOG - retval=Si570usbOpenDevice(&global_si570usb_handle, my_usbSerialID); - if (retval != 0) return -1; - -//SET FREQUENCY - if((freq_MHz < 3.45)|(freq_MHz > 866.0)) return -2; - retval=setFreqByValue(global_si570usb_handle,freq_MHz); - return 0; -} - -int usbGetStringAscii(usb_dev_handle *dev, int my_index, - int langid, char *buf, int buflen) -{ - char buffer[256]; - int rval, i; - if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, - (USB_DT_STRING << 8) + my_index, langid, buffer, - sizeof(buffer), 1000)) < 0) return rval; - if(buffer[1] != USB_DT_STRING) return 0; - if((unsigned char)buffer[0] < rval) rval = (unsigned char)buffer[0]; - rval /= 2; -// lossy conversion to ISO Latin1 - for(i=1;i buflen) break; // destination buffer overflow - buf[i-1] = buffer[2 * i]; - if(buffer[2 * i + 1] != 0) buf[i-1] = '?'; // outside of ISO Latin1 range - } - buf[i-1] = 0; - return i-1; -} - -unsigned char Si570usbOpenDevice(usb_dev_handle **device, char *usbSerialID) -{ - struct usb_bus *bus; - struct usb_device *dev; - usb_dev_handle *handle = NULL; - unsigned char errorCode = USB_ERROR_NOTFOUND; - char string[256]; - int len; - int vendor = USBDEV_SHARED_VENDOR; - char *vendorName = VENDOR_NAME; - int product = USBDEV_SHARED_PRODUCT; - char *productName = PRODUCT_NAME; - char serialNumberString[20]; - static int didUsbInit = 0; - - if(!didUsbInit) { - didUsbInit = 1; - usb_init(); - } - usb_find_busses(); - usb_find_devices(); - for(bus=usb_get_busses(); bus; bus=bus->next) { - for(dev=bus->devices; dev; dev=dev->next) { - if(dev->descriptor.idVendor == vendor && - dev->descriptor.idProduct == product) { - handle = usb_open(dev); // open the device in order to query strings - if(!handle) { - errorCode = USB_ERROR_ACCESS; - printf("si570.c: Warning: cannot open Si570-USB device:\n"); - printf("usb error message: %s\n",usb_strerror()); - continue; - } - if(vendorName == NULL && productName == NULL) { //name does not matter - break; - } - // now check whether the names match - len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string)); - if(len < 0) { - errorCode = USB_ERROR_IO; - printf("si570.c: Warning: cannot query manufacturer for Si570-USB device:\n"); - printf("usb error message: %s\n",usb_strerror()); - } else { - errorCode = USB_ERROR_NOTFOUND; - //fprintf(stderr, "seen device from vendor ->%s<-\n", string); - if(strcmp(string, vendorName) == 0){ - len = usbGetStringAscii(handle, dev->descriptor.iProduct, - 0x0409, string, sizeof(string)); - if(len < 0) { - errorCode = USB_ERROR_IO; - printf("si570.c: Warning: cannot query product for Si570-USB device: \n"); - printf("usb error message: %s\n",usb_strerror()); - } else { - errorCode = USB_ERROR_NOTFOUND; - // fprintf(stderr, "seen product ->%s<-\n", string); - if(strcmp(string, productName) == 0) { - len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, - 0x0409, serialNumberString, sizeof(serialNumberString)); - if (len < 0) { - errorCode = USB_ERROR_IO; - printf("si570.c: Warning: cannot query serial number for Si570-USB device: \n"); - printf("usb error message: %s\n",usb_strerror()); - } else { - errorCode = USB_ERROR_NOTFOUND; - if ((usbSerialID == NULL) || - (strcmp(serialNumberString, usbSerialID) == 0)) { -// printf("\nOpen Si570 USB device: OK\n"); -// printf("usbSerialID : %s\n",serialNumberString); - break; - } - } - } - } - } - } - usb_close(handle); - handle = NULL; - } - } - if(handle) break; - } - if(handle != NULL) { - errorCode = USB_SUCCESS; - *device = handle; - } - return errorCode; -} - -void setLongWord( int value, char * bytes) -{ - bytes[0] = value & 0xff; - bytes[1] = ((value & 0xff00) >> 8) & 0xff; - bytes[2] = ((value & 0xff0000) >> 16) & 0xff; - bytes[3] = ((value & 0xff000000) >> 24) & 0xff; -} - -int setFreqByValue(usb_dev_handle * handle, double frequency) -{ -// Windows Doc from PE0FKO: -// -// Command 0x32: -// ------------- -// Set the oscillator frequency by value. The frequency is formatted in MHz -// as 11.21 bits value. -// The "automatic band pass filter selection", "smooth tune", -// "one side calibration" and the "frequency subtract multiply" are all -// done in this function. (if enabled in the firmware) -// -// Default: None -// -// Parameters: -// requesttype: USB_ENDPOINT_OUT -// request: 0x32 -// value: 0 -// index: 0 -// bytes: pointer 32 bits integer -// size: 4 -// -// Code sample: -// uint32_t iFreq; -// double dFreq; -// -// dFreq = 30.123456; // MHz -// iFreq = (uint32_t)( dFreq * (1UL << 21) ) -// r = usbCtrlMsgOUT(0x32, 0, 0, (char *)&iFreq, sizeof(iFreq)); -// if (r < 0) Error -// - - char buffer[4]; - int i2cAddress = 0x55; - int request = REQUEST_SET_FREQ_BY_VALUE; - int value = 0x700 + i2cAddress; - int my_index = 0; - int retval; - int err_cnt; - - err_cnt =0; - set_again:; - setLongWord(round(frequency * 2097152.0), buffer); // 2097152=2^21 - retval=usb_control_msg( - handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, - request, - value, - my_index, - buffer, - sizeof(buffer), - 5000); - if (retval != 4) { - err_cnt ++; - if(err_cnt < MAX_USB_ERR_CNT) { - si570_sleep(1000); // delay 1000 microsec - goto set_again; - } else { - printf("Error when setting frequency, returncode=%i\n",retval); - printf("usb error message: %s\n", usb_strerror()); - } - } - return retval; -} + +/* Linux / Windows program to control the frequency of a si570 synthesizer + ON5GN 6 jan 2012 + Under Linux: + -use the linux version of function void si570_sleep(int us) + -compile with + gcc -Wall -o set_si570_freq set_si570_freq.c -lusb -lm + -run with sudo ./set_si570_freq + Under Windows: + -use the windows version of function void si570_sleep(int us) + -compile with mingw + C:\mingw\bin\mingw32-gcc -Wall -o set_si570_freq set_si570_freq.c -lusb -lm + -run with set_si570_freq.exe +*/ + +#include /* Standard input/output definitions */ +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include +#include +#include + +#define USB_SUCCESS 0 +#define USB_ERROR_NOTFOUND 1 +#define USB_ERROR_ACCESS 2 +#define USB_ERROR_IO 3 +#define VENDOR_NAME "www.obdev.at" +#define PRODUCT_NAME "DG8SAQ-I2C" +#define USBDEV_SHARED_VENDOR 0x16C0 // VOTI VID +#define USBDEV_SHARED_PRODUCT 0x05DC // OBDEV PID + // Use obdev's generic shared VID/PID pair + // following the rules outlined in + // firmware/usbdrv/USBID-License.txt. +#define REQUEST_SET_FREQ_BY_VALUE 0x32 +#define MAX_USB_ERR_CNT 6 + +double freq_parm; +double delay_average; +int from_freq; +int to_freq; +int increment_freq; +int retval = -1; +int display_freq = -1; +int delay; +usb_dev_handle *global_si570usb_handle = NULL; + +// ********sleep functions*************** +//use this function under LINUX +/* +void si570_sleep(int us) +{ +usleep(us); +} +*/ + +//use this function under WINDOWS +void si570_sleep(int us) +{ + Sleep(us/1000); +} + +double round(double x) +{ + int i=x+0.5; + return (double)i; +} + +double current_time(void) //for delay measurements +{ + struct timeval t; + gettimeofday(&t,NULL); + return 0.000001*t.tv_usec+t.tv_sec; +} + +int usbGetStringAscii(usb_dev_handle *dev, int my_index, + int langid, char *buf, int buflen); +unsigned char Si570usbOpenDevice(usb_dev_handle **device, char *usbSerialID); +void setLongWord( int value, char * bytes); +int setFreqByValue(usb_dev_handle * handle, double frequency); +void sweepa_freq(void); +void sweepm_freq(void); + +int set570(double freq_MHz) +{ + char * my_usbSerialID = NULL; + +// MAIN MENU DIALOG + retval=Si570usbOpenDevice(&global_si570usb_handle, my_usbSerialID); + if (retval != 0) return -1; + +//SET FREQUENCY + if((freq_MHz < 3.45)|(freq_MHz > 866.0)) return -2; + retval=setFreqByValue(global_si570usb_handle,freq_MHz); + return 0; +} + +int usbGetStringAscii(usb_dev_handle *dev, int my_index, + int langid, char *buf, int buflen) +{ + char buffer[256]; + int rval, i; + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, + (USB_DT_STRING << 8) + my_index, langid, buffer, + sizeof(buffer), 1000)) < 0) return rval; + if(buffer[1] != USB_DT_STRING) return 0; + if((unsigned char)buffer[0] < rval) rval = (unsigned char)buffer[0]; + rval /= 2; +// lossy conversion to ISO Latin1 + for(i=1;i buflen) break; // destination buffer overflow + buf[i-1] = buffer[2 * i]; + if(buffer[2 * i + 1] != 0) buf[i-1] = '?'; // outside of ISO Latin1 range + } + buf[i-1] = 0; + return i-1; +} + +unsigned char Si570usbOpenDevice(usb_dev_handle **device, char *usbSerialID) +{ + struct usb_bus *bus; + struct usb_device *dev; + usb_dev_handle *handle = NULL; + unsigned char errorCode = USB_ERROR_NOTFOUND; + char string[256]; + int len; + int vendor = USBDEV_SHARED_VENDOR; + char *vendorName = VENDOR_NAME; + int product = USBDEV_SHARED_PRODUCT; + char *productName = PRODUCT_NAME; + char serialNumberString[20]; + static int didUsbInit = 0; + + if(!didUsbInit) { + didUsbInit = 1; + usb_init(); + } + usb_find_busses(); + usb_find_devices(); + for(bus=usb_get_busses(); bus; bus=bus->next) { + for(dev=bus->devices; dev; dev=dev->next) { + if(dev->descriptor.idVendor == vendor && + dev->descriptor.idProduct == product) { + handle = usb_open(dev); // open the device in order to query strings + if(!handle) { + errorCode = USB_ERROR_ACCESS; + printf("si570.c: Warning: cannot open Si570-USB device:\n"); + printf("usb error message: %s\n",usb_strerror()); + continue; + } + if(vendorName == NULL && productName == NULL) { //name does not matter + break; + } + // now check whether the names match + len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string)); + if(len < 0) { + errorCode = USB_ERROR_IO; + printf("si570.c: Warning: cannot query manufacturer for Si570-USB device:\n"); + printf("usb error message: %s\n",usb_strerror()); + } else { + errorCode = USB_ERROR_NOTFOUND; + //fprintf(stderr, "seen device from vendor ->%s<-\n", string); + if(strcmp(string, vendorName) == 0){ + len = usbGetStringAscii(handle, dev->descriptor.iProduct, + 0x0409, string, sizeof(string)); + if(len < 0) { + errorCode = USB_ERROR_IO; + printf("si570.c: Warning: cannot query product for Si570-USB device: \n"); + printf("usb error message: %s\n",usb_strerror()); + } else { + errorCode = USB_ERROR_NOTFOUND; + // fprintf(stderr, "seen product ->%s<-\n", string); + if(strcmp(string, productName) == 0) { + len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, + 0x0409, serialNumberString, sizeof(serialNumberString)); + if (len < 0) { + errorCode = USB_ERROR_IO; + printf("si570.c: Warning: cannot query serial number for Si570-USB device: \n"); + printf("usb error message: %s\n",usb_strerror()); + } else { + errorCode = USB_ERROR_NOTFOUND; + if ((usbSerialID == NULL) || + (strcmp(serialNumberString, usbSerialID) == 0)) { +// printf("\nOpen Si570 USB device: OK\n"); +// printf("usbSerialID : %s\n",serialNumberString); + break; + } + } + } + } + } + } + usb_close(handle); + handle = NULL; + } + } + if(handle) break; + } + if(handle != NULL) { + errorCode = USB_SUCCESS; + *device = handle; + } + return errorCode; +} + +void setLongWord( int value, char * bytes) +{ + bytes[0] = value & 0xff; + bytes[1] = ((value & 0xff00) >> 8) & 0xff; + bytes[2] = ((value & 0xff0000) >> 16) & 0xff; + bytes[3] = ((value & 0xff000000) >> 24) & 0xff; +} + +int setFreqByValue(usb_dev_handle * handle, double frequency) +{ +// Windows Doc from PE0FKO: +// +// Command 0x32: +// ------------- +// Set the oscillator frequency by value. The frequency is formatted in MHz +// as 11.21 bits value. +// The "automatic band pass filter selection", "smooth tune", +// "one side calibration" and the "frequency subtract multiply" are all +// done in this function. (if enabled in the firmware) +// +// Default: None +// +// Parameters: +// requesttype: USB_ENDPOINT_OUT +// request: 0x32 +// value: 0 +// index: 0 +// bytes: pointer 32 bits integer +// size: 4 +// +// Code sample: +// uint32_t iFreq; +// double dFreq; +// +// dFreq = 30.123456; // MHz +// iFreq = (uint32_t)( dFreq * (1UL << 21) ) +// r = usbCtrlMsgOUT(0x32, 0, 0, (char *)&iFreq, sizeof(iFreq)); +// if (r < 0) Error +// + + char buffer[4]; + int i2cAddress = 0x55; + int request = REQUEST_SET_FREQ_BY_VALUE; + int value = 0x700 + i2cAddress; + int my_index = 0; + int retval; + int err_cnt; + + err_cnt =0; + set_again:; + setLongWord(round(frequency * 2097152.0), buffer); // 2097152=2^21 + retval=usb_control_msg( + handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, + request, + value, + my_index, + buffer, + sizeof(buffer), + 5000); + if (retval != 4) { + err_cnt ++; + if(err_cnt < MAX_USB_ERR_CNT) { + si570_sleep(1000); // delay 1000 microsec + goto set_again; + } else { + printf("Error when setting frequency, returncode=%i\n",retval); + printf("usb error message: %s\n", usb_strerror()); + } + } + return retval; +} diff --git a/sleep.h b/sleep.h index d566cce24..c11188c2a 100644 --- a/sleep.h +++ b/sleep.h @@ -1,16 +1,16 @@ -#ifndef SLEEP_H -#define SLEEP_H -#include - -class Sleep : public QThread -{ -public: - static void msleep(int ms) { - QThread::msleep(ms); - } - static int idealThreadCount() { - return QThread::idealThreadCount(); - } -}; - -#endif // SLEEP_H +#ifndef SLEEP_H +#define SLEEP_H +#include + +class Sleep : public QThread +{ +public: + static void msleep(int ms) { + QThread::msleep(ms); + } + static int idealThreadCount() { + return QThread::idealThreadCount(); + } +}; + +#endif // SLEEP_H diff --git a/soundin.cpp b/soundin.cpp index 3d704a60e..a6d4b24c6 100644 --- a/soundin.cpp +++ b/soundin.cpp @@ -1,403 +1,403 @@ -#include "soundin.h" -#include - -#define NFFT 32768 -#define FRAMES_PER_BUFFER 1024 - -extern "C" { -#include -extern struct { - double d8[2*60*96000]; //This is "common/datcom/..." in fortran - float ss[4*322*NFFT]; - float savg[4*NFFT]; - double fcenter; - int nutc; - int idphi; //Phase correction for Y pol'n, degrees - int mousedf; //User-selected DF - int mousefqso; //User-selected QSO freq (kHz) - int nagain; //1 ==> decode only at fQSO +/- Tol - int ndepth; //How much hinted decoding to do? - int ndiskdat; //1 ==> data read from *.tf2 or *.iq file - int neme; //Hinted decoding tries only for EME calls - int newdat; //1 ==> new data, must do long FFT - int nfa; //Low decode limit (kHz) - int nfb; //High decode limit (kHz) - int nfcal; //Frequency correction, for calibration (Hz) - int nfshift; //Shift of displayed center freq (kHz) - int mcall3; //1 ==> CALL3.TXT has been modified - int ntimeout; //Max for timeouts in Messages and BandMap - int ntol; //+/- decoding range around fQSO (Hz) - int nxant; //1 ==> add 45 deg to measured pol angle - int map65RxLog; //Flags to control log files - int nfsample; //Input sample rate - int nxpol; //1 if using xpol antennas, 0 otherwise - int mode65; //JT65 sub-mode: A=1, B=2, C=4 - char mycall[12]; - char mygrid[6]; - char hiscall[12]; - char hisgrid[6]; - char datetime[20]; -} datcom_; -} - -typedef struct -{ - int kin; //Parameters sent to/from the portaudio callback function - int nrx; - bool bzero; - bool iqswap; - bool b10db; -} paUserData; - -//--------------------------------------------------------------- a2dCallback -extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesToProcess, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) - -// This routine called by the PortAudio engine when samples are available. -// It may be called at interrupt level, so don't do anything -// that could mess up the system like calling malloc() or free(). - -{ - paUserData *udata=(paUserData*)userData; - (void) outputBuffer; //Prevent unused variable warnings. - (void) timeInfo; - (void) userData; - int nbytes,i,j; - float d4[4*FRAMES_PER_BUFFER]; - float d4a[4*FRAMES_PER_BUFFER]; - float tmp; - float fac; - - if( (statusFlags&paInputOverflow) != 0) { - qDebug() << "Input Overflow"; - } - if(udata->bzero) { //Start of a new minute - udata->kin=0; //Reset buffer pointer - udata->bzero=false; - } - - nbytes=udata->nrx*8*framesToProcess; //Bytes per frame - memcpy(d4,inputBuffer,nbytes); //Copy all samples to d4 - - fac=32767.0; - if(udata->b10db) fac=103618.35; - - if(udata->nrx==2) { - for(i=0; i<4*int(framesToProcess); i++) { //Negate odd-numbered frames - d4[i]=fac*d4[i]; - j=i/4; - if((j%2)==1) d4[i]=-d4[i]; - } - if(!udata->iqswap) { - for(i=0; ikin],d4,nbytes); //Copy from d4 to dd() - } else { - int k=0; - for(i=0; i<2*int(framesToProcess); i+=2) { //Negate odd-numbered frames - j=i/2; - if(j%2==0) { - d4a[k++]=fac*d4[i]; - d4a[k++]=fac*d4[i+1]; - } else { - d4a[k++]=-fac*d4[i]; - d4a[k++]=-fac*d4[i+1]; - } - d4a[k++]=0.0; - d4a[k++]=0.0; - } - if(!udata->iqswap) { - for(i=0; ikin],d4a,2*nbytes); //Copy from d4a to dd() - } - udata->kin += framesToProcess; - return paContinue; -} - -void SoundInThread::run() //SoundInThread::run() -{ - quitExecution = false; - - if (m_net) { -// qDebug() << "Start inputUDP()"; - inputUDP(); -// qDebug() << "Finished inputUDP()"; - return; - } - -//---------------------------------------------------- Soundcard Setup -// qDebug() << "Start souncard input"; - - PaError paerr; - PaStreamParameters inParam; - PaStream *inStream; - paUserData udata; - - udata.kin=0; //Buffer pointer - udata.bzero=false; //Flag to request reset of kin - udata.nrx=m_nrx; //Number of polarizations - udata.iqswap=m_IQswap; - udata.b10db=m_10db; - - inParam.device=m_nDevIn; //### Input Device Number ### - inParam.channelCount=2*m_nrx; //Number of analog channels - inParam.sampleFormat=paFloat32; //Get floats from Portaudio - inParam.suggestedLatency=0.05; - inParam.hostApiSpecificStreamInfo=NULL; - - paerr=Pa_IsFormatSupported(&inParam,NULL,96000.0); - if(paerr<0) { - emit error("PortAudio says requested soundcard format not supported."); -// return; - } - paerr=Pa_OpenStream(&inStream, //Input stream - &inParam, //Input parameters - NULL, //No output parameters - 96000.0, //Sample rate - FRAMES_PER_BUFFER, //Frames per buffer -// paClipOff+paDitherOff, //No clipping or dithering - paClipOff, //No clipping - a2dCallback, //Input callbeck routine - &udata); //userdata - - paerr=Pa_StartStream(inStream); - if(paerr<0) { - emit error("Failed to start audio input stream."); - return; - } -// const PaStreamInfo* p=Pa_GetStreamInfo(inStream); - - bool qe = quitExecution; - int n60z=99; - int k=0; - int nsec; - int n60; - int nBusy=0; - int nhsym0=0; - -//---------------------------------------------- Soundcard input loop - while (!qe) { - qe = quitExecution; - if (qe) break; - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - nsec = ms/1000; // Time according to this computer - n60 = nsec % 60; - -// Reset buffer pointer and symbol number at start of minute - if(n60 < n60z or !m_monitoring) { - nhsym0=0; - udata.bzero=true; - } - k=udata.kin; - udata.iqswap=m_IQswap; - udata.b10db=m_10db; - if(m_monitoring) { - if(m_bForceCenterFreq) { - datcom_.fcenter=m_dForceCenterFreq;\ - } else { - datcom_.fcenter=144.125; - } - m_hsym=(k-2048)*11025.0/(2048.0*m_rate); - if(m_hsym != nhsym0) { - if(m_dataSinkBusy) { - nBusy++; - } else { - m_dataSinkBusy=true; - emit readyForFFT(k); //Signal to compute new FFTs - } - nhsym0=m_hsym; - } - } - msleep(100); - n60z=n60; - } - Pa_StopStream(inStream); - Pa_CloseStream(inStream); -} - -void SoundInThread::setSwapIQ(bool b) -{ - m_IQswap=b; -} - -void SoundInThread::set10db(bool b) -{ - m_10db=b; -} -void SoundInThread::setPort(int n) //setPort() -{ - if (isRunning()) return; - this->m_udpPort=n; -} - -void SoundInThread::setInputDevice(int n) //setInputDevice() -{ - if (isRunning()) return; - this->m_nDevIn=n; -} - -void SoundInThread::setRate(double rate) //setRate() -{ - if (isRunning()) return; - this->m_rate = rate; -} - -void SoundInThread::setBufSize(unsigned n) //setBufSize() -{ - if (isRunning()) return; - this->bufSize = n; -} - -void SoundInThread::setFadd(double x) -{ - m_fAdd=x; -} - - -void SoundInThread::quit() //quit() -{ - quitExecution = true; -} - -void SoundInThread::setNetwork(bool b) //setNetwork() -{ - m_net = b; -} - -void SoundInThread::setMonitoring(bool b) //setMonitoring() -{ - m_monitoring = b; -} - -void SoundInThread::setForceCenterFreqBool(bool b) -{ - m_bForceCenterFreq=b; - -} - -void SoundInThread::setForceCenterFreqMHz(double d) -{ - m_dForceCenterFreq=d; -} - -void SoundInThread::setNrx(int n) //setNrx() -{ - m_nrx = n; -} - -int SoundInThread::nrx() -{ - return m_nrx; -} - -int SoundInThread::mhsym() -{ - return m_hsym; -} - -//--------------------------------------------------------------- inputUDP() -void SoundInThread::inputUDP() -{ - udpSocket = new QUdpSocket(); - if(!udpSocket->bind(m_udpPort,QUdpSocket::ShareAddress) ) - { - emit error(tr("UDP Socket bind failed.")); - return; - } - - // Set this socket's total buffer space for received UDP packets - int v=141600; - ::setsockopt(udpSocket->socketDescriptor(), SOL_SOCKET, SO_RCVBUF, - (char *)&v, sizeof(v)); - - bool qe = quitExecution; - struct linradBuffer { - double cfreq; - int msec; - float userfreq; - int iptr; - quint16 iblk; - qint8 nrx; - char iusb; - double d8[174]; - } b; - - int n60z=99; - int k=0; - int nsec; - int n60; - int nhsym0=0; - int iz=174; - int nBusy=0; - - // Main loop for input of UDP packets over the network: - while (!qe) { - qe = quitExecution; - if (qe) break; - if (!udpSocket->hasPendingDatagrams()) { - msleep(2); // Sleep if no packet available - } else { - int nBytesRead = udpSocket->readDatagram((char *)&b,1416); - if (nBytesRead != 1416) qDebug() << "UDP Read Error:" << nBytesRead; - - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - nsec = ms/1000; // Time according to this computer - n60 = nsec % 60; - -// Reset buffer pointer and symbol number at start of minute - if(n60 < n60z) { - k=0; - nhsym0=0; - } - n60z=n60; - - if(m_monitoring) { - m_nrx=b.nrx; - if(m_nrx == +1) iz=348; //One RF channel, i*2 data - if(m_nrx == -1 or m_nrx == +2) iz=174; //One Rf channel, r*4 data - // or 2 RF channels, i*2 data - if(m_nrx == -2) iz=87; // Two RF channels, r*4 data - - // If buffer will not overflow, move data into datcom_ - if ((k+iz) <= 60*96000) { - int nsam=-1; - recvpkt_(&nsam, &b.iblk, &b.nrx, &k, b.d8, b.d8, b.d8); - if(m_bForceCenterFreq) { - datcom_.fcenter=m_dForceCenterFreq; - } else { - datcom_.fcenter=b.cfreq + m_fAdd; - } - } - - m_hsym=(k-2048)*11025.0/(2048.0*m_rate); - if(m_hsym != nhsym0) { - if(m_dataSinkBusy) { - nBusy++; - } else { - m_dataSinkBusy=true; - emit readyForFFT(k); //Signal to compute new FFTs - } - nhsym0=m_hsym; - } - } - } - } - delete udpSocket; -} +#include "soundin.h" +#include + +#define NFFT 32768 +#define FRAMES_PER_BUFFER 1024 + +extern "C" { +#include +extern struct { + double d8[2*60*96000]; //This is "common/datcom/..." in fortran + float ss[4*322*NFFT]; + float savg[4*NFFT]; + double fcenter; + int nutc; + int idphi; //Phase correction for Y pol'n, degrees + int mousedf; //User-selected DF + int mousefqso; //User-selected QSO freq (kHz) + int nagain; //1 ==> decode only at fQSO +/- Tol + int ndepth; //How much hinted decoding to do? + int ndiskdat; //1 ==> data read from *.tf2 or *.iq file + int neme; //Hinted decoding tries only for EME calls + int newdat; //1 ==> new data, must do long FFT + int nfa; //Low decode limit (kHz) + int nfb; //High decode limit (kHz) + int nfcal; //Frequency correction, for calibration (Hz) + int nfshift; //Shift of displayed center freq (kHz) + int mcall3; //1 ==> CALL3.TXT has been modified + int ntimeout; //Max for timeouts in Messages and BandMap + int ntol; //+/- decoding range around fQSO (Hz) + int nxant; //1 ==> add 45 deg to measured pol angle + int map65RxLog; //Flags to control log files + int nfsample; //Input sample rate + int nxpol; //1 if using xpol antennas, 0 otherwise + int mode65; //JT65 sub-mode: A=1, B=2, C=4 + char mycall[12]; + char mygrid[6]; + char hiscall[12]; + char hisgrid[6]; + char datetime[20]; +} datcom_; +} + +typedef struct +{ + int kin; //Parameters sent to/from the portaudio callback function + int nrx; + bool bzero; + bool iqswap; + bool b10db; +} paUserData; + +//--------------------------------------------------------------- a2dCallback +extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesToProcess, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) + +// This routine called by the PortAudio engine when samples are available. +// It may be called at interrupt level, so don't do anything +// that could mess up the system like calling malloc() or free(). + +{ + paUserData *udata=(paUserData*)userData; + (void) outputBuffer; //Prevent unused variable warnings. + (void) timeInfo; + (void) userData; + int nbytes,i,j; + float d4[4*FRAMES_PER_BUFFER]; + float d4a[4*FRAMES_PER_BUFFER]; + float tmp; + float fac; + + if( (statusFlags&paInputOverflow) != 0) { + qDebug() << "Input Overflow"; + } + if(udata->bzero) { //Start of a new minute + udata->kin=0; //Reset buffer pointer + udata->bzero=false; + } + + nbytes=udata->nrx*8*framesToProcess; //Bytes per frame + memcpy(d4,inputBuffer,nbytes); //Copy all samples to d4 + + fac=32767.0; + if(udata->b10db) fac=103618.35; + + if(udata->nrx==2) { + for(i=0; i<4*int(framesToProcess); i++) { //Negate odd-numbered frames + d4[i]=fac*d4[i]; + j=i/4; + if((j%2)==1) d4[i]=-d4[i]; + } + if(!udata->iqswap) { + for(i=0; ikin],d4,nbytes); //Copy from d4 to dd() + } else { + int k=0; + for(i=0; i<2*int(framesToProcess); i+=2) { //Negate odd-numbered frames + j=i/2; + if(j%2==0) { + d4a[k++]=fac*d4[i]; + d4a[k++]=fac*d4[i+1]; + } else { + d4a[k++]=-fac*d4[i]; + d4a[k++]=-fac*d4[i+1]; + } + d4a[k++]=0.0; + d4a[k++]=0.0; + } + if(!udata->iqswap) { + for(i=0; ikin],d4a,2*nbytes); //Copy from d4a to dd() + } + udata->kin += framesToProcess; + return paContinue; +} + +void SoundInThread::run() //SoundInThread::run() +{ + quitExecution = false; + + if (m_net) { +// qDebug() << "Start inputUDP()"; + inputUDP(); +// qDebug() << "Finished inputUDP()"; + return; + } + +//---------------------------------------------------- Soundcard Setup +// qDebug() << "Start souncard input"; + + PaError paerr; + PaStreamParameters inParam; + PaStream *inStream; + paUserData udata; + + udata.kin=0; //Buffer pointer + udata.bzero=false; //Flag to request reset of kin + udata.nrx=m_nrx; //Number of polarizations + udata.iqswap=m_IQswap; + udata.b10db=m_10db; + + inParam.device=m_nDevIn; //### Input Device Number ### + inParam.channelCount=2*m_nrx; //Number of analog channels + inParam.sampleFormat=paFloat32; //Get floats from Portaudio + inParam.suggestedLatency=0.05; + inParam.hostApiSpecificStreamInfo=NULL; + + paerr=Pa_IsFormatSupported(&inParam,NULL,96000.0); + if(paerr<0) { + emit error("PortAudio says requested soundcard format not supported."); +// return; + } + paerr=Pa_OpenStream(&inStream, //Input stream + &inParam, //Input parameters + NULL, //No output parameters + 96000.0, //Sample rate + FRAMES_PER_BUFFER, //Frames per buffer +// paClipOff+paDitherOff, //No clipping or dithering + paClipOff, //No clipping + a2dCallback, //Input callbeck routine + &udata); //userdata + + paerr=Pa_StartStream(inStream); + if(paerr<0) { + emit error("Failed to start audio input stream."); + return; + } +// const PaStreamInfo* p=Pa_GetStreamInfo(inStream); + + bool qe = quitExecution; + int n60z=99; + int k=0; + int nsec; + int n60; + int nBusy=0; + int nhsym0=0; + +//---------------------------------------------- Soundcard input loop + while (!qe) { + qe = quitExecution; + if (qe) break; + qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; + nsec = ms/1000; // Time according to this computer + n60 = nsec % 60; + +// Reset buffer pointer and symbol number at start of minute + if(n60 < n60z or !m_monitoring) { + nhsym0=0; + udata.bzero=true; + } + k=udata.kin; + udata.iqswap=m_IQswap; + udata.b10db=m_10db; + if(m_monitoring) { + if(m_bForceCenterFreq) { + datcom_.fcenter=m_dForceCenterFreq;\ + } else { + datcom_.fcenter=144.125; + } + m_hsym=(k-2048)*11025.0/(2048.0*m_rate); + if(m_hsym != nhsym0) { + if(m_dataSinkBusy) { + nBusy++; + } else { + m_dataSinkBusy=true; + emit readyForFFT(k); //Signal to compute new FFTs + } + nhsym0=m_hsym; + } + } + msleep(100); + n60z=n60; + } + Pa_StopStream(inStream); + Pa_CloseStream(inStream); +} + +void SoundInThread::setSwapIQ(bool b) +{ + m_IQswap=b; +} + +void SoundInThread::set10db(bool b) +{ + m_10db=b; +} +void SoundInThread::setPort(int n) //setPort() +{ + if (isRunning()) return; + this->m_udpPort=n; +} + +void SoundInThread::setInputDevice(int n) //setInputDevice() +{ + if (isRunning()) return; + this->m_nDevIn=n; +} + +void SoundInThread::setRate(double rate) //setRate() +{ + if (isRunning()) return; + this->m_rate = rate; +} + +void SoundInThread::setBufSize(unsigned n) //setBufSize() +{ + if (isRunning()) return; + this->bufSize = n; +} + +void SoundInThread::setFadd(double x) +{ + m_fAdd=x; +} + + +void SoundInThread::quit() //quit() +{ + quitExecution = true; +} + +void SoundInThread::setNetwork(bool b) //setNetwork() +{ + m_net = b; +} + +void SoundInThread::setMonitoring(bool b) //setMonitoring() +{ + m_monitoring = b; +} + +void SoundInThread::setForceCenterFreqBool(bool b) +{ + m_bForceCenterFreq=b; + +} + +void SoundInThread::setForceCenterFreqMHz(double d) +{ + m_dForceCenterFreq=d; +} + +void SoundInThread::setNrx(int n) //setNrx() +{ + m_nrx = n; +} + +int SoundInThread::nrx() +{ + return m_nrx; +} + +int SoundInThread::mhsym() +{ + return m_hsym; +} + +//--------------------------------------------------------------- inputUDP() +void SoundInThread::inputUDP() +{ + udpSocket = new QUdpSocket(); + if(!udpSocket->bind(m_udpPort,QUdpSocket::ShareAddress) ) + { + emit error(tr("UDP Socket bind failed.")); + return; + } + + // Set this socket's total buffer space for received UDP packets + int v=141600; + ::setsockopt(udpSocket->socketDescriptor(), SOL_SOCKET, SO_RCVBUF, + (char *)&v, sizeof(v)); + + bool qe = quitExecution; + struct linradBuffer { + double cfreq; + int msec; + float userfreq; + int iptr; + quint16 iblk; + qint8 nrx; + char iusb; + double d8[174]; + } b; + + int n60z=99; + int k=0; + int nsec; + int n60; + int nhsym0=0; + int iz=174; + int nBusy=0; + + // Main loop for input of UDP packets over the network: + while (!qe) { + qe = quitExecution; + if (qe) break; + if (!udpSocket->hasPendingDatagrams()) { + msleep(2); // Sleep if no packet available + } else { + int nBytesRead = udpSocket->readDatagram((char *)&b,1416); + if (nBytesRead != 1416) qDebug() << "UDP Read Error:" << nBytesRead; + + qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; + nsec = ms/1000; // Time according to this computer + n60 = nsec % 60; + +// Reset buffer pointer and symbol number at start of minute + if(n60 < n60z) { + k=0; + nhsym0=0; + } + n60z=n60; + + if(m_monitoring) { + m_nrx=b.nrx; + if(m_nrx == +1) iz=348; //One RF channel, i*2 data + if(m_nrx == -1 or m_nrx == +2) iz=174; //One Rf channel, r*4 data + // or 2 RF channels, i*2 data + if(m_nrx == -2) iz=87; // Two RF channels, r*4 data + + // If buffer will not overflow, move data into datcom_ + if ((k+iz) <= 60*96000) { + int nsam=-1; + recvpkt_(&nsam, &b.iblk, &b.nrx, &k, b.d8, b.d8, b.d8); + if(m_bForceCenterFreq) { + datcom_.fcenter=m_dForceCenterFreq; + } else { + datcom_.fcenter=b.cfreq + m_fAdd; + } + } + + m_hsym=(k-2048)*11025.0/(2048.0*m_rate); + if(m_hsym != nhsym0) { + if(m_dataSinkBusy) { + nBusy++; + } else { + m_dataSinkBusy=true; + emit readyForFFT(k); //Signal to compute new FFTs + } + nhsym0=m_hsym; + } + } + } + } + delete udpSocket; +} diff --git a/soundin.h b/soundin.h index c618b9a87..db8d71016 100644 --- a/soundin.h +++ b/soundin.h @@ -1,85 +1,85 @@ -#ifndef SOUNDIN_H -#define SOUNDIN_H - -#include -#include -#include -#include - -#ifdef Q_OS_WIN32 -#include -#else -#include -#endif //Q_OS_WIN32 - -// Thread gets audio data from soundcard and signals when a buffer of -// specified size is available. -class SoundInThread : public QThread -{ - Q_OBJECT - bool quitExecution; // if true, thread exits gracefully - double m_rate; // sample rate - unsigned bufSize; // user's buffer size - -protected: - virtual void run(); - -public: - bool m_dataSinkBusy; - - SoundInThread(): - quitExecution(false), - m_dataSinkBusy(false), - m_rate(0), - bufSize(0) - { - } - - void setSwapIQ(bool b); - void set10db(bool b); - void setPort(qint32 n); - void setInputDevice(qint32 n); - void setRate(double rate); - void setBufSize(unsigned bufSize); - void setNetwork(bool b); - void setMonitoring(bool b); - void setFadd(double x); - void setNrx(int n); - void setForceCenterFreqBool(bool b); - void setForceCenterFreqMHz(double d); - int nrx(); - int mhsym(); - -signals: - void bufferAvailable(std::valarray samples, double rate); - void readyForFFT(int k); - void error(const QString& message); - void status(const QString& message); - -public slots: - void quit(); - -private: - void inputUDP(); - - double m_fAdd; - bool m_net; - bool m_monitoring; - bool m_bForceCenterFreq; - bool m_IQswap; - bool m_10db; - double m_dForceCenterFreq; - qint32 m_nrx; - qint32 m_hsym; - qint32 m_nDevIn; - qint32 m_udpPort; - - QUdpSocket *udpSocket; -}; - -extern "C" { - void recvpkt_(int* nsam, quint16* iblk, qint8* nrx, int* k, double s1[], - double s2[], double s3[]); -} - -#endif // SOUNDIN_H +#ifndef SOUNDIN_H +#define SOUNDIN_H + +#include +#include +#include +#include + +#ifdef Q_OS_WIN32 +#include +#else +#include +#endif //Q_OS_WIN32 + +// Thread gets audio data from soundcard and signals when a buffer of +// specified size is available. +class SoundInThread : public QThread +{ + Q_OBJECT + bool quitExecution; // if true, thread exits gracefully + double m_rate; // sample rate + unsigned bufSize; // user's buffer size + +protected: + virtual void run(); + +public: + bool m_dataSinkBusy; + + SoundInThread(): + quitExecution(false), + m_dataSinkBusy(false), + m_rate(0), + bufSize(0) + { + } + + void setSwapIQ(bool b); + void set10db(bool b); + void setPort(qint32 n); + void setInputDevice(qint32 n); + void setRate(double rate); + void setBufSize(unsigned bufSize); + void setNetwork(bool b); + void setMonitoring(bool b); + void setFadd(double x); + void setNrx(int n); + void setForceCenterFreqBool(bool b); + void setForceCenterFreqMHz(double d); + int nrx(); + int mhsym(); + +signals: + void bufferAvailable(std::valarray samples, double rate); + void readyForFFT(int k); + void error(const QString& message); + void status(const QString& message); + +public slots: + void quit(); + +private: + void inputUDP(); + + double m_fAdd; + bool m_net; + bool m_monitoring; + bool m_bForceCenterFreq; + bool m_IQswap; + bool m_10db; + double m_dForceCenterFreq; + qint32 m_nrx; + qint32 m_hsym; + qint32 m_nDevIn; + qint32 m_udpPort; + + QUdpSocket *udpSocket; +}; + +extern "C" { + void recvpkt_(int* nsam, quint16* iblk, qint8* nrx, int* k, double s1[], + double s2[], double s3[]); +} + +#endif // SOUNDIN_H diff --git a/soundout.cpp b/soundout.cpp index 9fb99ce9d..3ee67bddc 100644 --- a/soundout.cpp +++ b/soundout.cpp @@ -1,170 +1,170 @@ -#include "soundout.h" - -#define FRAMES_PER_BUFFER 256 - -extern "C" { -#include -} - -extern float gran(); //Noise generator (for tests only) - -extern short int iwave[60*11025]; //Wave file for Tx audio -extern int nwave; -extern bool btxok; -extern double outputLatency; - -typedef struct //Parameters sent to or received from callback function -{ - int dummy; -} paUserData; - -//--------------------------------------------------------------- d2aCallback -extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer, - unsigned long framesToProcess, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) -{ - paUserData *udata=(paUserData*)userData; - short *wptr = (short*)outputBuffer; - unsigned int i,n; - static int ic=0; -// static int ic0=0; -// static int nsec0=-99; - static bool btxok0=false; - static int nminStart=0; -// static t0,t1; - double tsec,tstart; - - int nsec; - - // Get System time - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - tsec = 0.001*ms; - nsec = ms/1000; - - if(btxok and !btxok0) { //Start (or re-start) a transmission - n=nsec/60; - tstart=tsec - n*60.0 - 1.0; - - if(tstart<1.0) { - ic=0; //Start of minute, set starting index to 0 -// ic0=ic; - nminStart=n; -// t0=timeInfo->currentTime; - } else { - if(n != nminStart) { //Late start in new minute: compute starting index - ic=(int)(tstart*11025.0); -// ic0=ic; -// t0=timeInfo->currentTime; -// qDebug() << "B" << t0 << ic0; - nminStart=n; - } - } - /* - qDebug() << "A" << n << ic - << QString::number( tsec, 'f', 3 ) - << QString::number( tstart, 'f', 3 ) - << QString::number( timeInfo->currentTime, 'f', 3 ) - << QString::number( timeInfo->outputBufferDacTime, 'f', 3 ) - << QString::number( timeInfo->outputBufferDacTime - - timeInfo->currentTime, 'f', 3 ) - << QString::number( timeInfo->currentTime - tsec, 'f', 3 ); - */ - } - btxok0=btxok; - - /* - if(nsec!=nsec0) { - double txt=timeInfo->currentTime - t0; - double r=0.0; - if(txt>0.0) r=(ic-ic0)/txt; - qDebug() << "C" << txt << ic-ic0 << r; - nsec0=nsec; - } - */ - - if(btxok) { - for(i=0 ; i nwave) i2=0; -// i2 = 500.0*(i2/32767.0 + 5.0*gran()); //Add noise (tests only!) - if(!btxok) i2=0; - *wptr++ = i2; //left - *wptr++ = i2; //right - ic++; - } - } else { - for(i=0 ; i nwave) { - btxok=0; - ic=0; - } - return 0; -} - -void SoundOutThread::run() -{ - PaError paerr; - PaStreamParameters outParam; - PaStream *outStream; - paUserData udata; - quitExecution = false; - - outParam.device=m_nDevOut; //Output device number - outParam.channelCount=2; //Number of analog channels - outParam.sampleFormat=paInt16; //Send short ints to PortAudio - outParam.suggestedLatency=0.05; - outParam.hostApiSpecificStreamInfo=NULL; - - paerr=Pa_IsFormatSupported(NULL,&outParam,11025.0); - if(paerr<0) { - qDebug() << "PortAudio says requested output format not supported."; - qDebug() << paerr; - return; - } - -// udata.nwave=m_nwave; -// udata.btxok=false; - - paerr=Pa_OpenStream(&outStream, //Output stream - NULL, //No input parameters - &outParam, //Output parameters - 11025.0, //Sample rate - FRAMES_PER_BUFFER, //Frames per buffer - paClipOff, //No clipping - d2aCallback, //output callbeck routine - &udata); //userdata - - paerr=Pa_StartStream(outStream); - if(paerr<0) { - qDebug() << "Failed to start audio output stream."; - return; - } - const PaStreamInfo* p=Pa_GetStreamInfo(outStream); - outputLatency = p->outputLatency; - bool qe = quitExecution; - -//---------------------------------------------- Soundcard output loop - while (!qe) { - qe = quitExecution; - if (qe) break; -// udata.nwave=m_nwave; -// if(m_txOK) udata.btxok=1; -// if(!m_txOK) udata.btxok=0; - msleep(100); - } - Pa_StopStream(outStream); - Pa_CloseStream(outStream); -} - -void SoundOutThread::setOutputDevice(int n) //setOutputDevice() -{ - if (isRunning()) return; - this->m_nDevOut=n; -} +#include "soundout.h" + +#define FRAMES_PER_BUFFER 256 + +extern "C" { +#include +} + +extern float gran(); //Noise generator (for tests only) + +extern short int iwave[60*11025]; //Wave file for Tx audio +extern int nwave; +extern bool btxok; +extern double outputLatency; + +typedef struct //Parameters sent to or received from callback function +{ + int dummy; +} paUserData; + +//--------------------------------------------------------------- d2aCallback +extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesToProcess, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paUserData *udata=(paUserData*)userData; + short *wptr = (short*)outputBuffer; + unsigned int i,n; + static int ic=0; +// static int ic0=0; +// static int nsec0=-99; + static bool btxok0=false; + static int nminStart=0; +// static t0,t1; + double tsec,tstart; + + int nsec; + + // Get System time + qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; + tsec = 0.001*ms; + nsec = ms/1000; + + if(btxok and !btxok0) { //Start (or re-start) a transmission + n=nsec/60; + tstart=tsec - n*60.0 - 1.0; + + if(tstart<1.0) { + ic=0; //Start of minute, set starting index to 0 +// ic0=ic; + nminStart=n; +// t0=timeInfo->currentTime; + } else { + if(n != nminStart) { //Late start in new minute: compute starting index + ic=(int)(tstart*11025.0); +// ic0=ic; +// t0=timeInfo->currentTime; +// qDebug() << "B" << t0 << ic0; + nminStart=n; + } + } + /* + qDebug() << "A" << n << ic + << QString::number( tsec, 'f', 3 ) + << QString::number( tstart, 'f', 3 ) + << QString::number( timeInfo->currentTime, 'f', 3 ) + << QString::number( timeInfo->outputBufferDacTime, 'f', 3 ) + << QString::number( timeInfo->outputBufferDacTime - + timeInfo->currentTime, 'f', 3 ) + << QString::number( timeInfo->currentTime - tsec, 'f', 3 ); + */ + } + btxok0=btxok; + + /* + if(nsec!=nsec0) { + double txt=timeInfo->currentTime - t0; + double r=0.0; + if(txt>0.0) r=(ic-ic0)/txt; + qDebug() << "C" << txt << ic-ic0 << r; + nsec0=nsec; + } + */ + + if(btxok) { + for(i=0 ; i nwave) i2=0; +// i2 = 500.0*(i2/32767.0 + 5.0*gran()); //Add noise (tests only!) + if(!btxok) i2=0; + *wptr++ = i2; //left + *wptr++ = i2; //right + ic++; + } + } else { + for(i=0 ; i nwave) { + btxok=0; + ic=0; + } + return 0; +} + +void SoundOutThread::run() +{ + PaError paerr; + PaStreamParameters outParam; + PaStream *outStream; + paUserData udata; + quitExecution = false; + + outParam.device=m_nDevOut; //Output device number + outParam.channelCount=2; //Number of analog channels + outParam.sampleFormat=paInt16; //Send short ints to PortAudio + outParam.suggestedLatency=0.05; + outParam.hostApiSpecificStreamInfo=NULL; + + paerr=Pa_IsFormatSupported(NULL,&outParam,11025.0); + if(paerr<0) { + qDebug() << "PortAudio says requested output format not supported."; + qDebug() << paerr; + return; + } + +// udata.nwave=m_nwave; +// udata.btxok=false; + + paerr=Pa_OpenStream(&outStream, //Output stream + NULL, //No input parameters + &outParam, //Output parameters + 11025.0, //Sample rate + FRAMES_PER_BUFFER, //Frames per buffer + paClipOff, //No clipping + d2aCallback, //output callbeck routine + &udata); //userdata + + paerr=Pa_StartStream(outStream); + if(paerr<0) { + qDebug() << "Failed to start audio output stream."; + return; + } + const PaStreamInfo* p=Pa_GetStreamInfo(outStream); + outputLatency = p->outputLatency; + bool qe = quitExecution; + +//---------------------------------------------- Soundcard output loop + while (!qe) { + qe = quitExecution; + if (qe) break; +// udata.nwave=m_nwave; +// if(m_txOK) udata.btxok=1; +// if(!m_txOK) udata.btxok=0; + msleep(100); + } + Pa_StopStream(outStream); + Pa_CloseStream(outStream); +} + +void SoundOutThread::setOutputDevice(int n) //setOutputDevice() +{ + if (isRunning()) return; + this->m_nDevOut=n; +} diff --git a/soundout.h b/soundout.h index 3df140d37..198c6d763 100644 --- a/soundout.h +++ b/soundout.h @@ -1,42 +1,42 @@ -#ifndef SOUNDOUT_H -#define SOUNDOUT_H -#include -#include - -// An instance of this thread sends audio data to a specified soundcard. -// Output can be muted while underway, preserving waveform timing when -// transmission is resumed. - -class SoundOutThread : public QThread -{ - Q_OBJECT - -protected: - virtual void run(); - -public: -// Constructs (but does not start) a SoundOutThread - SoundOutThread() - : quitExecution(false) // Initialize some private members - , m_rate(0) - , m_nwave(48*11025) - , m_txOK(false) - , m_txMute(false) - { - } - -public: - void setOutputDevice(qint32 n); - bool quitExecution; //If true, thread exits gracefully - - -// Private members -private: - double m_rate; //Sample rate - qint32 m_nDevOut; //Output device number - qint32 m_nwave; //Length of wave file - bool m_txOK; //Enable Tx audio - bool m_txMute; //Mute temporarily -}; - -#endif +#ifndef SOUNDOUT_H +#define SOUNDOUT_H +#include +#include + +// An instance of this thread sends audio data to a specified soundcard. +// Output can be muted while underway, preserving waveform timing when +// transmission is resumed. + +class SoundOutThread : public QThread +{ + Q_OBJECT + +protected: + virtual void run(); + +public: +// Constructs (but does not start) a SoundOutThread + SoundOutThread() + : quitExecution(false) // Initialize some private members + , m_rate(0) + , m_nwave(48*11025) + , m_txOK(false) + , m_txMute(false) + { + } + +public: + void setOutputDevice(qint32 n); + bool quitExecution; //If true, thread exits gracefully + + +// Private members +private: + double m_rate; //Sample rate + qint32 m_nDevOut; //Output device number + qint32 m_nwave; //Length of wave file + bool m_txOK; //Enable Tx audio + bool m_txMute; //Mute temporarily +}; + +#endif diff --git a/widegraph.cpp b/widegraph.cpp index 7d181066b..93c21cf57 100644 --- a/widegraph.cpp +++ b/widegraph.cpp @@ -1,318 +1,318 @@ -#include "widegraph.h" -#include "ui_widegraph.h" - -#define NFFT 32768 - -WideGraph::WideGraph(QWidget *parent) : - QDialog(parent), - ui(new Ui::WideGraph) -{ - ui->setupUi(this); - this->setWindowFlags(Qt::Dialog); - this->installEventFilter(parent); //Installing the filter - ui->widePlot->setCursor(Qt::CrossCursor); - this->setMaximumWidth(2048); - this->setMaximumHeight(880); - ui->widePlot->setMaximumHeight(800); - - connect(ui->widePlot, SIGNAL(freezeDecode1(int)),this, - SLOT(wideFreezeDecode(int))); - - //Restore user's settings - QString inifile(QApplication::applicationDirPath()); - inifile += "/map65.ini"; - QSettings settings(inifile, QSettings::IniFormat); - - settings.beginGroup("WideGraph"); - ui->widePlot->setPlotZero(settings.value("PlotZero", 20).toInt()); - ui->widePlot->setPlotGain(settings.value("PlotGain", 0).toInt()); - ui->zeroSpinBox->setValue(ui->widePlot->getPlotZero()); - ui->gainSpinBox->setValue(ui->widePlot->getPlotGain()); - int n = settings.value("FreqSpan",60).toInt(); - int w = settings.value("PlotWidth",1000).toInt(); - ui->freqSpanSpinBox->setValue(n); - ui->widePlot->setNSpan(n); - int nbpp = n * 32768.0/(w*96.0) + 0.5; - ui->widePlot->setBinsPerPixel(nbpp); - m_waterfallAvg = settings.value("WaterfallAvg",10).toInt(); - ui->waterfallAvgSpinBox->setValue(m_waterfallAvg); - ui->freqOffsetSpinBox->setValue(settings.value("FreqOffset",0).toInt()); - m_bForceCenterFreq=settings.value("ForceCenterFreqBool",false).toBool(); - m_dForceCenterFreq=settings.value("ForceCenterFreqMHz",144.125).toDouble(); - ui->cbFcenter->setChecked(m_bForceCenterFreq); - ui->fCenterLineEdit->setText(QString::number(m_dForceCenterFreq)); - settings.endGroup(); -} - - -WideGraph::~WideGraph() -{ - saveSettings(); - delete ui; -} - -void WideGraph::saveSettings() -{ - //Save user's settings - QString inifile(QApplication::applicationDirPath()); - inifile += "/map65.ini"; - QSettings settings(inifile, QSettings::IniFormat); - - settings.beginGroup("WideGraph"); - settings.setValue("PlotZero",ui->widePlot->m_plotZero); - settings.setValue("PlotGain",ui->widePlot->m_plotGain); - settings.setValue("PlotWidth",ui->widePlot->plotWidth()); - settings.setValue("FreqSpan",ui->freqSpanSpinBox->value()); - settings.setValue("WaterfallAvg",ui->waterfallAvgSpinBox->value()); - settings.setValue("FreqOffset",ui->widePlot->freqOffset()); - settings.setValue("ForceCenterFreqBool",m_bForceCenterFreq); - settings.setValue("ForceCenterFreqMHz",m_dForceCenterFreq); - settings.endGroup(); -} - -void WideGraph::dataSink2(float s[], int nkhz, int ihsym, int ndiskdata, - uchar lstrong[]) -{ - static float splot[NFFT]; - float swide[2048]; - float smax; - double df; - int nbpp = ui->widePlot->binsPerPixel(); - static int n=0; - static int nkhz0=-999; - static int n60z=0; - - df = m_fSample/32768.0; - if(nkhz != nkhz0) { - ui->widePlot->setNkhz(nkhz); //Why do we need both? - ui->widePlot->SetCenterFreq(nkhz); //Why do we need both? - ui->widePlot->setFQSO(nkhz,true); - nkhz0 = nkhz; - } - - //Average spectra over specified number, m_waterfallAvg - if (n==0) { - for (int i=0; i=m_waterfallAvg) { - for (int i=0; iwidePlot->plotWidth(); - qint64 sf = nkhz + ui->widePlot->freqOffset() - 0.5*w*nbpp*df/1000.0; - if(sf != ui->widePlot->startFreq()) ui->widePlot->SetStartFreq(sf); - int i0=16384.0+(ui->widePlot->startFreq()-nkhz+1.27046+0.001*m_fCal) * - 1000.0/df + 0.5; - int i=i0; - for (int j=0; j<2048; j++) { - smax=0; - for (int k=0; ksmax) smax=splot[i]; - } - swide[j]=smax; - if(lstrong[1 + i/32]!=0) swide[j]=-smax; //Tag strong signals - } - -// Time according to this computer - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int n60 = (ms/1000) % 60; - - if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && n60widePlot->draw(swide,i0,splot); - } -} - -void WideGraph::on_freqOffsetSpinBox_valueChanged(int f) -{ - ui->widePlot->SetFreqOffset(f); -} - -void WideGraph::on_freqSpanSpinBox_valueChanged(int n) -{ - ui->widePlot->setNSpan(n); - int w = ui->widePlot->plotWidth(); - int nbpp = n * 32768.0/(w*96.0) + 0.5; - if(nbpp < 1) nbpp=1; - if(w > 0) { - ui->widePlot->setBinsPerPixel(nbpp); - } -} - -void WideGraph::on_waterfallAvgSpinBox_valueChanged(int n) -{ - m_waterfallAvg = n; -} - -void WideGraph::on_zeroSpinBox_valueChanged(int value) -{ - ui->widePlot->setPlotZero(value); -} - -void WideGraph::on_gainSpinBox_valueChanged(int value) -{ - ui->widePlot->setPlotGain(value); -} - -void WideGraph::keyPressEvent(QKeyEvent *e) -{ - switch(e->key()) - { - case Qt::Key_F11: - emit f11f12(11); - break; - case Qt::Key_F12: - emit f11f12(12); - break; - default: - e->ignore(); - } -} - -int WideGraph::QSOfreq() -{ - return ui->widePlot->fQSO(); -} - -int WideGraph::nSpan() -{ - return ui->widePlot->m_nSpan; -} - -float WideGraph::fSpan() -{ - return ui->widePlot->m_fSpan; -} - -int WideGraph::nStartFreq() -{ - return ui->widePlot->startFreq(); -} - -void WideGraph::wideFreezeDecode(int n) -{ - emit freezeDecode2(n); -} - -void WideGraph::setTol(int n) -{ - ui->widePlot->m_tol=n; - ui->widePlot->DrawOverlay(); - ui->widePlot->update(); -} - -int WideGraph::Tol() -{ - return ui->widePlot->m_tol; -} - -void WideGraph::setDF(int n) -{ - ui->widePlot->m_DF=n; - ui->widePlot->DrawOverlay(); - ui->widePlot->update(); -} - -void WideGraph::setFcal(int n) -{ - m_fCal=n; - ui->widePlot->setFcal(n); -} - - -int WideGraph::DF() -{ - return ui->widePlot->m_DF; -} - -void WideGraph::on_autoZeroPushButton_clicked() -{ - int nzero=ui->widePlot->autoZero(); - ui->zeroSpinBox->setValue(nzero); -} - -void WideGraph::setPalette(QString palette) -{ - ui->widePlot->setPalette(palette); -} -void WideGraph::setFsample(int n) -{ - m_fSample=n; - ui->widePlot->setFsample(n); -} - -void WideGraph::setMode65(int n) -{ - m_mode65=n; - ui->widePlot->setMode65(n); -} - -void WideGraph::on_cbFcenter_stateChanged(int n) -{ - m_bForceCenterFreq = (n!=0); - if(m_bForceCenterFreq) { - ui->fCenterLineEdit->setEnabled(true); - ui->pbSetRxHardware->setEnabled(true); - } else { - ui->fCenterLineEdit->setDisabled(true); - ui->pbSetRxHardware->setDisabled(true); - } -} - -void WideGraph::on_fCenterLineEdit_editingFinished() -{ - m_dForceCenterFreq=ui->fCenterLineEdit->text().toDouble(); -} - -void WideGraph::on_pbSetRxHardware_clicked() -{ -#ifdef WIN32 - int iret=set570(m_mult570*(1.0+0.000001*m_cal570)*m_dForceCenterFreq); - if(iret != 0) { - QMessageBox mb; - if(iret==-1) mb.setText("Failed to open Si570."); - if(iret==-2) mb.setText("Frequency out of permitted range."); - mb.exec(); - } -#endif -} - -void WideGraph::initIQplus() -{ -#ifdef WIN32 - int iret=set570(288.0); - if(iret != 0) { - QMessageBox mb; - if(iret==-1) mb.setText("Failed to open Si570."); - if(iret==-2) mb.setText("Frequency out of permitted range."); - mb.exec(); - } else { - on_pbSetRxHardware_clicked(); - } -#endif -} - -void WideGraph::on_cbSpec2d_toggled(bool b) -{ - ui->widePlot->set2Dspec(b); -} - -double WideGraph::fGreen() -{ - return ui->widePlot->fGreen(); -} +#include "widegraph.h" +#include "ui_widegraph.h" + +#define NFFT 32768 + +WideGraph::WideGraph(QWidget *parent) : + QDialog(parent), + ui(new Ui::WideGraph) +{ + ui->setupUi(this); + this->setWindowFlags(Qt::Dialog); + this->installEventFilter(parent); //Installing the filter + ui->widePlot->setCursor(Qt::CrossCursor); + this->setMaximumWidth(2048); + this->setMaximumHeight(880); + ui->widePlot->setMaximumHeight(800); + + connect(ui->widePlot, SIGNAL(freezeDecode1(int)),this, + SLOT(wideFreezeDecode(int))); + + //Restore user's settings + QString inifile(QApplication::applicationDirPath()); + inifile += "/map65.ini"; + QSettings settings(inifile, QSettings::IniFormat); + + settings.beginGroup("WideGraph"); + ui->widePlot->setPlotZero(settings.value("PlotZero", 20).toInt()); + ui->widePlot->setPlotGain(settings.value("PlotGain", 0).toInt()); + ui->zeroSpinBox->setValue(ui->widePlot->getPlotZero()); + ui->gainSpinBox->setValue(ui->widePlot->getPlotGain()); + int n = settings.value("FreqSpan",60).toInt(); + int w = settings.value("PlotWidth",1000).toInt(); + ui->freqSpanSpinBox->setValue(n); + ui->widePlot->setNSpan(n); + int nbpp = n * 32768.0/(w*96.0) + 0.5; + ui->widePlot->setBinsPerPixel(nbpp); + m_waterfallAvg = settings.value("WaterfallAvg",10).toInt(); + ui->waterfallAvgSpinBox->setValue(m_waterfallAvg); + ui->freqOffsetSpinBox->setValue(settings.value("FreqOffset",0).toInt()); + m_bForceCenterFreq=settings.value("ForceCenterFreqBool",false).toBool(); + m_dForceCenterFreq=settings.value("ForceCenterFreqMHz",144.125).toDouble(); + ui->cbFcenter->setChecked(m_bForceCenterFreq); + ui->fCenterLineEdit->setText(QString::number(m_dForceCenterFreq)); + settings.endGroup(); +} + + +WideGraph::~WideGraph() +{ + saveSettings(); + delete ui; +} + +void WideGraph::saveSettings() +{ + //Save user's settings + QString inifile(QApplication::applicationDirPath()); + inifile += "/map65.ini"; + QSettings settings(inifile, QSettings::IniFormat); + + settings.beginGroup("WideGraph"); + settings.setValue("PlotZero",ui->widePlot->m_plotZero); + settings.setValue("PlotGain",ui->widePlot->m_plotGain); + settings.setValue("PlotWidth",ui->widePlot->plotWidth()); + settings.setValue("FreqSpan",ui->freqSpanSpinBox->value()); + settings.setValue("WaterfallAvg",ui->waterfallAvgSpinBox->value()); + settings.setValue("FreqOffset",ui->widePlot->freqOffset()); + settings.setValue("ForceCenterFreqBool",m_bForceCenterFreq); + settings.setValue("ForceCenterFreqMHz",m_dForceCenterFreq); + settings.endGroup(); +} + +void WideGraph::dataSink2(float s[], int nkhz, int ihsym, int ndiskdata, + uchar lstrong[]) +{ + static float splot[NFFT]; + float swide[2048]; + float smax; + double df; + int nbpp = ui->widePlot->binsPerPixel(); + static int n=0; + static int nkhz0=-999; + static int n60z=0; + + df = m_fSample/32768.0; + if(nkhz != nkhz0) { + ui->widePlot->setNkhz(nkhz); //Why do we need both? + ui->widePlot->SetCenterFreq(nkhz); //Why do we need both? + ui->widePlot->setFQSO(nkhz,true); + nkhz0 = nkhz; + } + + //Average spectra over specified number, m_waterfallAvg + if (n==0) { + for (int i=0; i=m_waterfallAvg) { + for (int i=0; iwidePlot->plotWidth(); + qint64 sf = nkhz + ui->widePlot->freqOffset() - 0.5*w*nbpp*df/1000.0; + if(sf != ui->widePlot->startFreq()) ui->widePlot->SetStartFreq(sf); + int i0=16384.0+(ui->widePlot->startFreq()-nkhz+1.27046+0.001*m_fCal) * + 1000.0/df + 0.5; + int i=i0; + for (int j=0; j<2048; j++) { + smax=0; + for (int k=0; ksmax) smax=splot[i]; + } + swide[j]=smax; + if(lstrong[1 + i/32]!=0) swide[j]=-smax; //Tag strong signals + } + +// Time according to this computer + qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; + int n60 = (ms/1000) % 60; + + if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && n60widePlot->draw(swide,i0,splot); + } +} + +void WideGraph::on_freqOffsetSpinBox_valueChanged(int f) +{ + ui->widePlot->SetFreqOffset(f); +} + +void WideGraph::on_freqSpanSpinBox_valueChanged(int n) +{ + ui->widePlot->setNSpan(n); + int w = ui->widePlot->plotWidth(); + int nbpp = n * 32768.0/(w*96.0) + 0.5; + if(nbpp < 1) nbpp=1; + if(w > 0) { + ui->widePlot->setBinsPerPixel(nbpp); + } +} + +void WideGraph::on_waterfallAvgSpinBox_valueChanged(int n) +{ + m_waterfallAvg = n; +} + +void WideGraph::on_zeroSpinBox_valueChanged(int value) +{ + ui->widePlot->setPlotZero(value); +} + +void WideGraph::on_gainSpinBox_valueChanged(int value) +{ + ui->widePlot->setPlotGain(value); +} + +void WideGraph::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) + { + case Qt::Key_F11: + emit f11f12(11); + break; + case Qt::Key_F12: + emit f11f12(12); + break; + default: + e->ignore(); + } +} + +int WideGraph::QSOfreq() +{ + return ui->widePlot->fQSO(); +} + +int WideGraph::nSpan() +{ + return ui->widePlot->m_nSpan; +} + +float WideGraph::fSpan() +{ + return ui->widePlot->m_fSpan; +} + +int WideGraph::nStartFreq() +{ + return ui->widePlot->startFreq(); +} + +void WideGraph::wideFreezeDecode(int n) +{ + emit freezeDecode2(n); +} + +void WideGraph::setTol(int n) +{ + ui->widePlot->m_tol=n; + ui->widePlot->DrawOverlay(); + ui->widePlot->update(); +} + +int WideGraph::Tol() +{ + return ui->widePlot->m_tol; +} + +void WideGraph::setDF(int n) +{ + ui->widePlot->m_DF=n; + ui->widePlot->DrawOverlay(); + ui->widePlot->update(); +} + +void WideGraph::setFcal(int n) +{ + m_fCal=n; + ui->widePlot->setFcal(n); +} + + +int WideGraph::DF() +{ + return ui->widePlot->m_DF; +} + +void WideGraph::on_autoZeroPushButton_clicked() +{ + int nzero=ui->widePlot->autoZero(); + ui->zeroSpinBox->setValue(nzero); +} + +void WideGraph::setPalette(QString palette) +{ + ui->widePlot->setPalette(palette); +} +void WideGraph::setFsample(int n) +{ + m_fSample=n; + ui->widePlot->setFsample(n); +} + +void WideGraph::setMode65(int n) +{ + m_mode65=n; + ui->widePlot->setMode65(n); +} + +void WideGraph::on_cbFcenter_stateChanged(int n) +{ + m_bForceCenterFreq = (n!=0); + if(m_bForceCenterFreq) { + ui->fCenterLineEdit->setEnabled(true); + ui->pbSetRxHardware->setEnabled(true); + } else { + ui->fCenterLineEdit->setDisabled(true); + ui->pbSetRxHardware->setDisabled(true); + } +} + +void WideGraph::on_fCenterLineEdit_editingFinished() +{ + m_dForceCenterFreq=ui->fCenterLineEdit->text().toDouble(); +} + +void WideGraph::on_pbSetRxHardware_clicked() +{ +#ifdef WIN32 + int iret=set570(m_mult570*(1.0+0.000001*m_cal570)*m_dForceCenterFreq); + if(iret != 0) { + QMessageBox mb; + if(iret==-1) mb.setText("Failed to open Si570."); + if(iret==-2) mb.setText("Frequency out of permitted range."); + mb.exec(); + } +#endif +} + +void WideGraph::initIQplus() +{ +#ifdef WIN32 + int iret=set570(288.0); + if(iret != 0) { + QMessageBox mb; + if(iret==-1) mb.setText("Failed to open Si570."); + if(iret==-2) mb.setText("Frequency out of permitted range."); + mb.exec(); + } else { + on_pbSetRxHardware_clicked(); + } +#endif +} + +void WideGraph::on_cbSpec2d_toggled(bool b) +{ + ui->widePlot->set2Dspec(b); +} + +double WideGraph::fGreen() +{ + return ui->widePlot->fGreen(); +}