Initial Commit
This commit is contained in:
@@ -0,0 +1,522 @@
|
||||
#include "widegraph.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <QApplication>
|
||||
#include <QSettings>
|
||||
#include "ui_widegraph.h"
|
||||
#include "commons.h"
|
||||
#include "Configuration.hpp"
|
||||
#include "MessageBox.hpp"
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "moc_widegraph.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
auto user_defined = QObject::tr ("User Defined");
|
||||
float swide[MAX_SCREENSIZE];
|
||||
}
|
||||
|
||||
WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::WideGraph),
|
||||
m_settings (settings),
|
||||
m_palettes_path {":/Palettes"},
|
||||
m_ntr0 {0},
|
||||
m_lockTxFreq {false},
|
||||
m_bHaveTransmitted {false},
|
||||
m_n {0}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Wide Graph"));
|
||||
setWindowFlags (Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
|
||||
setMaximumWidth (MAX_SCREENSIZE);
|
||||
setMaximumHeight (880);
|
||||
|
||||
ui->widePlot->setCursor(Qt::CrossCursor);
|
||||
ui->widePlot->setMaximumHeight(800);
|
||||
ui->widePlot->setCurrent(false);
|
||||
|
||||
connect(ui->widePlot, SIGNAL(freezeDecode1(int)),this,
|
||||
SLOT(wideFreezeDecode(int)));
|
||||
|
||||
connect(ui->widePlot, SIGNAL(setFreq1(int,int)),this,
|
||||
SLOT(setFreq2(int,int)));
|
||||
|
||||
{
|
||||
//Restore user's settings
|
||||
SettingsGroup g {m_settings, "WideGraph"};
|
||||
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
|
||||
ui->widePlot->setPlotZero(m_settings->value("PlotZero", 0).toInt());
|
||||
ui->widePlot->setPlotGain(m_settings->value("PlotGain", 0).toInt());
|
||||
ui->widePlot->setPlot2dGain(m_settings->value("Plot2dGain", 0).toInt());
|
||||
ui->widePlot->setPlot2dZero(m_settings->value("Plot2dZero", 0).toInt());
|
||||
ui->zeroSlider->setValue(ui->widePlot->plotZero());
|
||||
ui->gainSlider->setValue(ui->widePlot->plotGain());
|
||||
ui->gain2dSlider->setValue(ui->widePlot->plot2dGain());
|
||||
ui->zero2dSlider->setValue(ui->widePlot->plot2dZero());
|
||||
int n = m_settings->value("BinsPerPixel",2).toInt();
|
||||
m_bFlatten=m_settings->value("Flatten",true).toBool();
|
||||
m_bRef=m_settings->value("UseRef",false).toBool();
|
||||
ui->cbFlatten->setChecked(m_bFlatten);
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
ui->cbRef->setChecked(m_bRef);
|
||||
ui->widePlot->setBreadth(m_settings->value("PlotWidth",1000).toInt());
|
||||
ui->bppSpinBox->setValue(n);
|
||||
m_nsmo=m_settings->value("SmoothYellow",1).toInt();
|
||||
ui->smoSpinBox->setValue(m_nsmo);
|
||||
m_Percent2DScreen=m_settings->value("Percent2D",30).toInt();
|
||||
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
|
||||
m_waterfallAvg = m_settings->value("WaterfallAvg",5).toInt();
|
||||
ui->waterfallAvgSpinBox->setValue(m_waterfallAvg);
|
||||
ui->widePlot->setWaterfallAvg(m_waterfallAvg);
|
||||
ui->widePlot->setCurrent(m_settings->value("Current",false).toBool());
|
||||
ui->widePlot->setCumulative(m_settings->value("Cumulative",true).toBool());
|
||||
ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool());
|
||||
ui->widePlot->setReference(m_settings->value("Reference",false).toBool());
|
||||
if(ui->widePlot->current()) ui->spec2dComboBox->setCurrentIndex(0);
|
||||
if(ui->widePlot->cumulative()) ui->spec2dComboBox->setCurrentIndex(1);
|
||||
if(ui->widePlot->linearAvg()) ui->spec2dComboBox->setCurrentIndex(2);
|
||||
if(ui->widePlot->Reference()) ui->spec2dComboBox->setCurrentIndex(3);
|
||||
int nbpp=m_settings->value("BinsPerPixel",2).toInt();
|
||||
ui->widePlot->setBinsPerPixel(nbpp);
|
||||
ui->widePlot->setStartFreq(m_settings->value("StartFreq",0).toInt());
|
||||
ui->fStartSpinBox->setValue(ui->widePlot->startFreq());
|
||||
m_waterfallPalette=m_settings->value("WaterfallPalette","Default").toString();
|
||||
m_userPalette = WFPalette {m_settings->value("UserPalette").value<WFPalette::Colours> ()};
|
||||
int m_fMin = m_settings->value ("Fmin", 2500).toInt ();
|
||||
ui->fSplitSpinBox->setValue (m_fMin);
|
||||
setRxRange ();
|
||||
ui->controls_widget->setVisible(!m_settings->value("HideControls", false).toBool ());
|
||||
}
|
||||
|
||||
saveSettings (); // update config with defaults
|
||||
|
||||
int index=0;
|
||||
for (QString const& file:
|
||||
m_palettes_path.entryList(QDir::NoDotAndDotDot |
|
||||
QDir::System | QDir::Hidden |
|
||||
QDir::AllDirs | QDir::Files,
|
||||
QDir::DirsFirst)) {
|
||||
QString t=file.mid(0,file.length()-4);
|
||||
ui->paletteComboBox->addItem(t);
|
||||
if(t==m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
|
||||
index++;
|
||||
}
|
||||
ui->paletteComboBox->addItem (user_defined);
|
||||
if (user_defined == m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
|
||||
readPalette ();
|
||||
}
|
||||
|
||||
WideGraph::~WideGraph ()
|
||||
{
|
||||
}
|
||||
|
||||
void WideGraph::closeEvent (QCloseEvent * e)
|
||||
{
|
||||
saveSettings ();
|
||||
QDialog::closeEvent (e);
|
||||
}
|
||||
|
||||
void WideGraph::saveSettings() //saveSettings
|
||||
{
|
||||
SettingsGroup g {m_settings, "WideGraph"};
|
||||
m_settings->setValue ("geometry", saveGeometry ());
|
||||
m_settings->setValue ("PlotZero", ui->widePlot->plotZero());
|
||||
m_settings->setValue ("PlotGain", ui->widePlot->plotGain());
|
||||
m_settings->setValue ("Plot2dGain", ui->widePlot->plot2dGain());
|
||||
m_settings->setValue ("Plot2dZero", ui->widePlot->plot2dZero());
|
||||
m_settings->setValue ("PlotWidth", ui->widePlot->plotWidth ());
|
||||
m_settings->setValue ("BinsPerPixel", ui->bppSpinBox->value ());
|
||||
m_settings->setValue ("SmoothYellow", ui->smoSpinBox->value ());
|
||||
m_settings->setValue ("Percent2D",m_Percent2DScreen);
|
||||
m_settings->setValue ("WaterfallAvg", ui->waterfallAvgSpinBox->value ());
|
||||
m_settings->setValue ("Current", ui->widePlot->current());
|
||||
m_settings->setValue ("Cumulative", ui->widePlot->cumulative());
|
||||
m_settings->setValue ("LinearAvg", ui->widePlot->linearAvg());
|
||||
m_settings->setValue ("Reference", ui->widePlot->Reference());
|
||||
m_settings->setValue ("BinsPerPixel", ui->widePlot->binsPerPixel ());
|
||||
m_settings->setValue ("StartFreq", ui->widePlot->startFreq ());
|
||||
m_settings->setValue ("WaterfallPalette", m_waterfallPalette);
|
||||
m_settings->setValue ("UserPalette", QVariant::fromValue (m_userPalette.colours ()));
|
||||
m_settings->setValue("Flatten",m_bFlatten);
|
||||
m_settings->setValue("UseRef",m_bRef);
|
||||
m_settings->setValue ("HideControls", ui->controls_widget->isHidden ());
|
||||
}
|
||||
|
||||
void WideGraph::drawRed(int ia, int ib)
|
||||
{
|
||||
ui->widePlot->drawRed(ia,ib,swide);
|
||||
}
|
||||
|
||||
void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dataSink2
|
||||
{
|
||||
static float splot[NSMAX];
|
||||
int nbpp = ui->widePlot->binsPerPixel();
|
||||
|
||||
//Average spectra over specified number, m_waterfallAvg
|
||||
if (m_n==0) {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i]=s[i];
|
||||
} else {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i] += s[i];
|
||||
}
|
||||
m_n++;
|
||||
|
||||
if (m_n>=m_waterfallAvg) {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i] /= m_n; //Normalize the average
|
||||
m_n=0;
|
||||
int i=int(ui->widePlot->startFreq()/df3 + 0.5);
|
||||
int jz=5000.0/(nbpp*df3);
|
||||
if(jz>MAX_SCREENSIZE) jz=MAX_SCREENSIZE;
|
||||
for (int j=0; j<jz; j++) {
|
||||
float ss=0;
|
||||
for (int k=0; k<nbpp; k++) {
|
||||
if(splot[i]>ss) ss=splot[i];
|
||||
i++;
|
||||
}
|
||||
swide[j]=nbpp*ss;
|
||||
}
|
||||
|
||||
// Time according to this computer
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
int ntr = (ms/1000) % m_TRperiod;
|
||||
if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntr<m_ntr0)) {
|
||||
float flagValue=1.0e30;
|
||||
if(m_bHaveTransmitted) flagValue=2.0e30;
|
||||
for (int i=0; i<2048; i++) {
|
||||
swide[i] = flagValue;
|
||||
}
|
||||
m_bHaveTransmitted=false;
|
||||
}
|
||||
m_ntr0=ntr;
|
||||
ui->widePlot->draw(swide,true,false);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_bppSpinBox_valueChanged(int n) //bpp
|
||||
{
|
||||
ui->widePlot->setBinsPerPixel(n);
|
||||
}
|
||||
|
||||
void WideGraph::on_waterfallAvgSpinBox_valueChanged(int n) //Navg
|
||||
{
|
||||
m_waterfallAvg = n;
|
||||
ui->widePlot->setWaterfallAvg(n);
|
||||
}
|
||||
|
||||
void WideGraph::keyPressEvent(QKeyEvent *e) //F11, F12
|
||||
{
|
||||
switch(e->key())
|
||||
{
|
||||
int n;
|
||||
case Qt::Key_F11:
|
||||
n=11;
|
||||
if(e->modifiers() & Qt::ControlModifier) n+=100;
|
||||
emit f11f12(n);
|
||||
break;
|
||||
case Qt::Key_F12:
|
||||
n=12;
|
||||
if(e->modifiers() & Qt::ControlModifier) n+=100;
|
||||
emit f11f12(n);
|
||||
break;
|
||||
case Qt::Key_M:
|
||||
if(e->modifiers() & Qt::ControlModifier) {
|
||||
ui->controls_widget->setVisible(!ui->controls_widget->isVisible());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
QDialog::keyPressEvent (e);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::setRxFreq(int n) //setRxFreq
|
||||
{
|
||||
ui->widePlot->setRxFreq(n);
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_lockTxFreq) setTxFreq(n);
|
||||
}
|
||||
|
||||
int WideGraph::rxFreq() //rxFreq
|
||||
{
|
||||
return ui->widePlot->rxFreq();
|
||||
}
|
||||
|
||||
int WideGraph::nStartFreq() //nStartFreq
|
||||
{
|
||||
return ui->widePlot->startFreq();
|
||||
}
|
||||
|
||||
void WideGraph::wideFreezeDecode(int n) //wideFreezeDecode
|
||||
{
|
||||
emit freezeDecode2(n);
|
||||
}
|
||||
|
||||
void WideGraph::setRxRange ()
|
||||
{
|
||||
ui->widePlot->setRxRange (Fmin ());
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
int WideGraph::Fmin() //Fmin
|
||||
{
|
||||
return "60m" == m_rxBand ? 0 : m_fMin;
|
||||
}
|
||||
|
||||
int WideGraph::Fmax() //Fmax
|
||||
{
|
||||
return std::min(5000,ui->widePlot->Fmax());
|
||||
}
|
||||
|
||||
int WideGraph::fSpan()
|
||||
{
|
||||
return ui->widePlot->fSpan ();
|
||||
}
|
||||
|
||||
void WideGraph::setPeriod(int ntrperiod, int nsps) //SetPeriod
|
||||
{
|
||||
m_TRperiod=ntrperiod;
|
||||
m_nsps=nsps;
|
||||
ui->widePlot->setNsps(ntrperiod, nsps);
|
||||
}
|
||||
|
||||
void WideGraph::setTxFreq(int n) //setTxFreq
|
||||
{
|
||||
emit setXIT2(n);
|
||||
ui->widePlot->setTxFreq(n);
|
||||
}
|
||||
|
||||
void WideGraph::setMode(QString mode) //setMode
|
||||
{
|
||||
m_mode=mode;
|
||||
ui->fSplitSpinBox->setEnabled(m_mode=="JT9+JT65");
|
||||
ui->widePlot->setMode(mode);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
void WideGraph::setSubMode(int n) //setSubMode
|
||||
{
|
||||
m_nSubMode=n;
|
||||
ui->widePlot->setSubMode(n);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
void WideGraph::setModeTx(QString modeTx) //setModeTx
|
||||
{
|
||||
m_modeTx=modeTx;
|
||||
ui->widePlot->setModeTx(modeTx);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
//Current-Cumulative-Yellow
|
||||
void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1)
|
||||
{
|
||||
ui->widePlot->setCurrent(false);
|
||||
ui->widePlot->setCumulative(false);
|
||||
ui->widePlot->setLinearAvg(false);
|
||||
ui->widePlot->setReference(false);
|
||||
ui->smoSpinBox->setEnabled(false);
|
||||
if(arg1=="Current") ui->widePlot->setCurrent(true);
|
||||
if(arg1=="Cumulative") ui->widePlot->setCumulative(true);
|
||||
if(arg1=="Linear Avg") {
|
||||
ui->widePlot->setLinearAvg(true);
|
||||
ui->smoSpinBox->setEnabled(true);
|
||||
}
|
||||
if(arg1=="Reference") {
|
||||
ui->widePlot->setReference(true);
|
||||
}
|
||||
if(ui->widePlot->m_bScaleOK) ui->widePlot->draw(swide,false,false);
|
||||
}
|
||||
|
||||
void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit
|
||||
{
|
||||
if (m_rxBand != "60m") m_fMin=n;
|
||||
setRxRange ();
|
||||
}
|
||||
|
||||
void WideGraph::setLockTxFreq(bool b) //LockTxFreq
|
||||
{
|
||||
m_lockTxFreq=b;
|
||||
ui->widePlot->setLockTxFreq(b);
|
||||
}
|
||||
|
||||
void WideGraph::setFreq2(int rxFreq, int txFreq) //setFreq2
|
||||
{
|
||||
emit setFreq3(rxFreq,txFreq);
|
||||
}
|
||||
|
||||
void WideGraph::setDialFreq(double d) //setDialFreq
|
||||
{
|
||||
ui->widePlot->setDialFreq(d);
|
||||
}
|
||||
|
||||
void WideGraph::setRxBand (QString const& band)
|
||||
{
|
||||
m_rxBand = band;
|
||||
if ("60m" == m_rxBand)
|
||||
{
|
||||
ui->fSplitSpinBox->setEnabled (false);
|
||||
ui->fSplitSpinBox->setValue (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->fSplitSpinBox->setValue (m_fMin);
|
||||
ui->fSplitSpinBox->setEnabled (true);
|
||||
}
|
||||
ui->widePlot->setRxBand(band);
|
||||
setRxRange ();
|
||||
}
|
||||
|
||||
|
||||
void WideGraph::on_fStartSpinBox_valueChanged(int n) //fStart
|
||||
{
|
||||
ui->widePlot->setStartFreq(n);
|
||||
}
|
||||
|
||||
void WideGraph::readPalette () //readPalette
|
||||
{
|
||||
try
|
||||
{
|
||||
if (user_defined == m_waterfallPalette)
|
||||
{
|
||||
ui->widePlot->setColours (WFPalette {m_userPalette}.interpolate ());
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->widePlot->setColours (WFPalette {m_palettes_path.absoluteFilePath (m_waterfallPalette + ".pal")}.interpolate());
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_paletteComboBox_activated (QString const& palette) //palette selector
|
||||
{
|
||||
m_waterfallPalette = palette;
|
||||
readPalette();
|
||||
}
|
||||
|
||||
void WideGraph::on_cbFlatten_toggled(bool b) //Flatten On/Off
|
||||
{
|
||||
m_bFlatten=b;
|
||||
if(m_bRef and m_bFlatten) {
|
||||
m_bRef=false;
|
||||
ui->cbRef->setChecked(false);
|
||||
}
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
}
|
||||
|
||||
void WideGraph::on_cbRef_toggled(bool b)
|
||||
{
|
||||
m_bRef=b;
|
||||
if(m_bRef and m_bFlatten) {
|
||||
m_bFlatten=false;
|
||||
ui->cbFlatten->setChecked(false);
|
||||
}
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
}
|
||||
|
||||
void WideGraph::on_cbControls_toggled(bool b)
|
||||
{
|
||||
ui->controls_widget->setVisible(b);
|
||||
}
|
||||
|
||||
void WideGraph::on_adjust_palette_push_button_clicked (bool) //Adjust Palette
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_userPalette.design ())
|
||||
{
|
||||
m_waterfallPalette = user_defined;
|
||||
ui->paletteComboBox->setCurrentText (m_waterfallPalette);
|
||||
readPalette ();
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
|
||||
}
|
||||
}
|
||||
|
||||
bool WideGraph::flatten() //Flatten
|
||||
{
|
||||
return m_bFlatten;
|
||||
}
|
||||
|
||||
bool WideGraph::useRef() //Flatten
|
||||
{
|
||||
return m_bRef;
|
||||
}
|
||||
|
||||
void WideGraph::on_gainSlider_valueChanged(int value) //Gain
|
||||
{
|
||||
ui->widePlot->setPlotGain(value);
|
||||
}
|
||||
|
||||
void WideGraph::on_zeroSlider_valueChanged(int value) //Zero
|
||||
{
|
||||
ui->widePlot->setPlotZero(value);
|
||||
}
|
||||
|
||||
void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
|
||||
{
|
||||
ui->widePlot->setPlot2dGain(value);
|
||||
if(ui->widePlot->m_bScaleOK) {
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_zero2dSlider_valueChanged(int value) //Zero2
|
||||
{
|
||||
ui->widePlot->setPlot2dZero(value);
|
||||
if(ui->widePlot->m_bScaleOK) {
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::setTol(int n) //setTol
|
||||
{
|
||||
ui->widePlot->setTol(n);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
void WideGraph::on_smoSpinBox_valueChanged(int n)
|
||||
{
|
||||
m_nsmo=n;
|
||||
}
|
||||
|
||||
int WideGraph::smoothYellow()
|
||||
{
|
||||
return m_nsmo;
|
||||
}
|
||||
|
||||
void WideGraph::setWSPRtransmitted()
|
||||
{
|
||||
m_bHaveTransmitted=true;
|
||||
}
|
||||
|
||||
void WideGraph::setVHF(bool bVHF)
|
||||
{
|
||||
ui->widePlot->setVHF(bVHF);
|
||||
}
|
||||
|
||||
void WideGraph::on_sbPercent2dPlot_valueChanged(int n)
|
||||
{
|
||||
m_Percent2DScreen=n;
|
||||
ui->widePlot->SetPercent2DScreen(n);
|
||||
}
|
||||
|
||||
void WideGraph::setRedFile(QString fRed)
|
||||
{
|
||||
ui->widePlot->setRedFile(fRed);
|
||||
}
|
||||
@@ -0,0 +1,726 @@
|
||||
#include "OmniRigTransceiver.hpp"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <objbase.h>
|
||||
#include <QThread>
|
||||
|
||||
#include "qt_helpers.hpP"
|
||||
|
||||
#include "moc_OmniRigTransceiver.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
auto constexpr OmniRig_transceiver_one_name = "OmniRig Rig 1";
|
||||
auto constexpr OmniRig_transceiver_two_name = "OmniRig Rig 2";
|
||||
}
|
||||
|
||||
auto OmniRigTransceiver::map_mode (OmniRig::RigParamX param) -> MODE
|
||||
{
|
||||
if (param & OmniRig::PM_CW_U)
|
||||
{
|
||||
return CW_R;
|
||||
}
|
||||
else if (param & OmniRig::PM_CW_L)
|
||||
{
|
||||
return CW;
|
||||
}
|
||||
else if (param & OmniRig::PM_SSB_U)
|
||||
{
|
||||
return USB;
|
||||
}
|
||||
else if (param & OmniRig::PM_SSB_L)
|
||||
{
|
||||
return LSB;
|
||||
}
|
||||
else if (param & OmniRig::PM_DIG_U)
|
||||
{
|
||||
return DIG_U;
|
||||
}
|
||||
else if (param & OmniRig::PM_DIG_L)
|
||||
{
|
||||
return DIG_L;
|
||||
}
|
||||
else if (param & OmniRig::PM_AM)
|
||||
{
|
||||
return AM;
|
||||
}
|
||||
else if (param & OmniRig::PM_FM)
|
||||
{
|
||||
return FM;
|
||||
}
|
||||
TRACE_CAT ("OmniRigTransceiver", "unrecognized mode");
|
||||
throw_qstring (tr ("OmniRig: unrecognized mode"));
|
||||
return UNK;
|
||||
}
|
||||
|
||||
OmniRig::RigParamX OmniRigTransceiver::map_mode (MODE mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case AM: return OmniRig::PM_AM;
|
||||
case CW: return OmniRig::PM_CW_L;
|
||||
case CW_R: return OmniRig::PM_CW_U;
|
||||
case USB: return OmniRig::PM_SSB_U;
|
||||
case LSB: return OmniRig::PM_SSB_L;
|
||||
case FSK: return OmniRig::PM_DIG_L;
|
||||
case FSK_R: return OmniRig::PM_DIG_U;
|
||||
case DIG_L: return OmniRig::PM_DIG_L;
|
||||
case DIG_U: return OmniRig::PM_DIG_U;
|
||||
case FM: return OmniRig::PM_FM;
|
||||
case DIG_FM: return OmniRig::PM_FM;
|
||||
default: break;
|
||||
}
|
||||
return OmniRig::PM_SSB_U; // quieten compiler grumble
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id1, int id2)
|
||||
{
|
||||
(*registry)[OmniRig_transceiver_one_name] = TransceiverFactory::Capabilities {
|
||||
id1
|
||||
, TransceiverFactory::Capabilities::none // COM isn't serial or network
|
||||
, true // does PTT
|
||||
, false // doesn't select mic/data (use OmniRig config file)
|
||||
, true // can remote control RTS nd DTR
|
||||
, true // asynchronous interface
|
||||
};
|
||||
(*registry)[OmniRig_transceiver_two_name] = TransceiverFactory::Capabilities {
|
||||
id2
|
||||
, TransceiverFactory::Capabilities::none // COM isn't serial or network
|
||||
, true // does PTT
|
||||
, false // doesn't select mic/data (use OmniRig config file)
|
||||
, true // can remote control RTS nd DTR
|
||||
, true // asynchronous interface
|
||||
};
|
||||
}
|
||||
|
||||
OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped,
|
||||
RigNumber n, TransceiverFactory::PTTMethod ptt_type,
|
||||
QString const& ptt_port, QObject * parent)
|
||||
: TransceiverBase {parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {TransceiverFactory::PTT_method_CAT == ptt_type || ("CAT" == ptt_port && (TransceiverFactory::PTT_method_RTS == ptt_type || TransceiverFactory::PTT_method_DTR == ptt_type))}
|
||||
, ptt_type_ {ptt_type}
|
||||
, rig_number_ {n}
|
||||
, readable_params_ {0}
|
||||
, writable_params_ {0}
|
||||
, send_update_signal_ {false}
|
||||
, reversed_ {false}
|
||||
{
|
||||
}
|
||||
|
||||
int OmniRigTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "starting");
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
CoInitializeEx (nullptr, 0 /*COINIT_APARTMENTTHREADED*/); // required because Qt only does this for GUI thread
|
||||
|
||||
omni_rig_.reset (new OmniRig::OmniRigX {this});
|
||||
if (omni_rig_->isNull ())
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "failed to start COM server");
|
||||
throw_qstring (tr ("Failed to start OmniRig COM server"));
|
||||
}
|
||||
|
||||
// COM/OLE exceptions get signaled
|
||||
connect (&*omni_rig_, SIGNAL (exception (int, QString, QString, QString)), this, SLOT (handle_COM_exception (int, QString, QString, QString)));
|
||||
|
||||
// IOmniRigXEvent interface signals
|
||||
connect (&*omni_rig_, SIGNAL (VisibleChange ()), this, SLOT (handle_visible_change ()));
|
||||
connect (&*omni_rig_, SIGNAL (RigTypeChange (int)), this, SLOT (handle_rig_type_change (int)));
|
||||
connect (&*omni_rig_, SIGNAL (StatusChange (int)), this, SLOT (handle_status_change (int)));
|
||||
connect (&*omni_rig_, SIGNAL (ParamsChange (int, int)), this, SLOT (handle_params_change (int, int)));
|
||||
connect (&*omni_rig_
|
||||
, SIGNAL (CustomReply (int, QVariant const&, QVariant const&))
|
||||
, this, SLOT (handle_custom_reply (int, QVariant const&, QVariant const&)));
|
||||
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig s/w version:" << QString::number (omni_rig_->SoftwareVersion ()).toLocal8Bit ()
|
||||
<< "i/f version:" << QString::number (omni_rig_->InterfaceVersion ()).toLocal8Bit ());
|
||||
|
||||
// fetch the interface of the RigX CoClass and instantiate a proxy object
|
||||
switch (rig_number_)
|
||||
{
|
||||
case One: rig_.reset (new OmniRig::RigX (omni_rig_->Rig1 ())); break;
|
||||
case Two: rig_.reset (new OmniRig::RigX (omni_rig_->Rig2 ())); break;
|
||||
}
|
||||
|
||||
Q_ASSERT (rig_);
|
||||
Q_ASSERT (!rig_->isNull ());
|
||||
|
||||
if (use_for_ptt_ && (TransceiverFactory::PTT_method_DTR == ptt_type_ || TransceiverFactory::PTT_method_RTS == ptt_type_))
|
||||
{
|
||||
// fetch the interface for the serial port if we need it for PTT
|
||||
port_.reset (new OmniRig::PortBits (rig_->PortBits ()));
|
||||
|
||||
Q_ASSERT (port_);
|
||||
Q_ASSERT (!port_->isNull ());
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig RTS state:" << port_->Rts ());
|
||||
|
||||
if (!port_->Lock ()) // try to take exclusive use of the OmniRig serial port for PTT
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "Failed to get exclusive use of serial port for PTT from OmniRig");
|
||||
}
|
||||
|
||||
// start off so we don't accidentally key the radio
|
||||
if (TransceiverFactory::PTT_method_DTR == ptt_type_)
|
||||
{
|
||||
port_->SetDtr (false);
|
||||
}
|
||||
else // RTS
|
||||
{
|
||||
port_->SetRts (false);
|
||||
}
|
||||
}
|
||||
|
||||
rig_type_ = rig_->RigType ();
|
||||
readable_params_ = rig_->ReadableParams ();
|
||||
writable_params_ = rig_->WriteableParams ();
|
||||
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig initial rig type: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
|
||||
.arg (rig_type_)
|
||||
.arg (readable_params_, 8, 16, QChar ('0'))
|
||||
.arg (writable_params_, 8, 16, QChar ('0'))
|
||||
.arg (rig_number_).toLocal8Bit ());
|
||||
|
||||
offline_timer_.reset (new QTimer);
|
||||
offline_timer_->setSingleShot (true);
|
||||
offline_timer_->setInterval (5 * 1000);
|
||||
connect (&*offline_timer_, &QTimer::timeout, this, &OmniRigTransceiver::timeout_check);
|
||||
|
||||
for (unsigned tries {0}; tries < 10; ++tries)
|
||||
{
|
||||
QThread::msleep (100); // wait until OmniRig polls the rig
|
||||
auto f = rig_->GetRxFrequency ();
|
||||
int resolution {0};
|
||||
if (f)
|
||||
{
|
||||
if (OmniRig::PM_UNKNOWN == rig_->Vfo ()
|
||||
&& (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
|
||||
== (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
|
||||
{
|
||||
// start with VFO A (probably MAIN) on rigs that we
|
||||
// can't query VFO but can set explicitly
|
||||
rig_->SetVfo (OmniRig::PM_VFOA);
|
||||
}
|
||||
if (f % 10) return resolution; // 1Hz resolution
|
||||
auto test_frequency = f - f % 100 + 55;
|
||||
if (OmniRig::PM_FREQ & writable_params_)
|
||||
{
|
||||
rig_->SetFreq (test_frequency);
|
||||
}
|
||||
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
|
||||
{
|
||||
rig_->SetFreqB (test_frequency);
|
||||
}
|
||||
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
|
||||
{
|
||||
rig_->SetFreqA (test_frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_qstring (tr ("OmniRig: don't know how to set rig frequency"));
|
||||
}
|
||||
switch (rig_->GetRxFrequency () - test_frequency)
|
||||
{
|
||||
case -5: resolution = -1; break; // 10Hz truncated
|
||||
case 5: resolution = 1; break; // 10Hz rounded
|
||||
case -15: resolution = -2; break; // 20Hz truncated
|
||||
case -55: resolution = -2; break; // 100Hz truncated
|
||||
case 45: resolution = 2; break; // 100Hz rounded
|
||||
}
|
||||
if (1 == resolution) // may be 20Hz rounded
|
||||
{
|
||||
test_frequency = f - f % 100 + 51;
|
||||
if (OmniRig::PM_FREQ & writable_params_)
|
||||
{
|
||||
rig_->SetFreq (test_frequency);
|
||||
}
|
||||
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
|
||||
{
|
||||
rig_->SetFreqB (test_frequency);
|
||||
}
|
||||
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
|
||||
{
|
||||
rig_->SetFreqA (test_frequency);
|
||||
}
|
||||
if (9 == rig_->GetRxFrequency () - test_frequency)
|
||||
{
|
||||
resolution = 2; // 20Hz rounded
|
||||
}
|
||||
}
|
||||
if (OmniRig::PM_FREQ & writable_params_)
|
||||
{
|
||||
rig_->SetFreq (f);
|
||||
}
|
||||
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
|
||||
{
|
||||
rig_->SetFreqB (f);
|
||||
}
|
||||
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
|
||||
{
|
||||
rig_->SetFreqA (f);
|
||||
}
|
||||
update_rx_frequency (f);
|
||||
return resolution;
|
||||
}
|
||||
}
|
||||
throw_qstring (tr ("OmniRig: Initialization timed out"));
|
||||
return 0; // keep compiler happy
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_stop ()
|
||||
{
|
||||
if (offline_timer_)
|
||||
{
|
||||
offline_timer_->stop ();
|
||||
offline_timer_.reset ();
|
||||
}
|
||||
|
||||
QThread::msleep (200); // leave some time for pending
|
||||
// commands at the server end
|
||||
if (port_)
|
||||
{
|
||||
port_->Unlock (); // release serial port
|
||||
port_->clear ();
|
||||
port_.reset ();
|
||||
}
|
||||
if (omni_rig_)
|
||||
{
|
||||
if (rig_)
|
||||
{
|
||||
rig_->clear ();
|
||||
rig_.reset ();
|
||||
}
|
||||
omni_rig_->clear ();
|
||||
omni_rig_.reset ();
|
||||
CoUninitialize ();
|
||||
}
|
||||
if (wrapped_) wrapped_->stop ();
|
||||
TRACE_CAT ("OmniRigTransceiver", "stopped");
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_sync (bool force_signal, bool /*no_poll*/)
|
||||
{
|
||||
// nothing much we can do here, we just have to let OmniRig do its
|
||||
// stuff and its first poll should send us and update that will
|
||||
// trigger a update signal from us. Any attempt to query OmniRig
|
||||
// leads to a whole mess of trouble since its internal state is
|
||||
// garbage until it has done its first rig poll.
|
||||
send_update_signal_ = force_signal;
|
||||
update_complete ();
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", QString::number (code) + " at " + source + ": " + desc + " (" + help + ')');
|
||||
throw_qstring (tr ("OmniRig COM/OLE error: %1 at %2: %3 (%4)").arg (QString::number (code)).arg (source). arg (desc). arg (help));
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_visible_change ()
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "visibility change: visibility =" << omni_rig_->DialogVisible ());
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_rig_type_change (int rig_number)
|
||||
{
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
readable_params_ = rig_->ReadableParams ();
|
||||
writable_params_ = rig_->WriteableParams ();
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
|
||||
.arg (rig_->RigType ())
|
||||
.arg (readable_params_, 8, 16, QChar ('0'))
|
||||
.arg (writable_params_, 8, 16, QChar ('0'))
|
||||
.arg (rig_number).toLocal8Bit ());
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_status_change (int rig_number)
|
||||
{
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
auto const& status = rig_->StatusStr ().toLocal8Bit ();
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig status change: new status for rig %1 = "}.arg (rig_number).toLocal8Bit () << status);
|
||||
if (OmniRig::ST_ONLINE != rig_->Status ())
|
||||
{
|
||||
if (!offline_timer_->isActive ())
|
||||
{
|
||||
offline_timer_->start (); // give OmniRig time to recover
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offline_timer_->stop ();
|
||||
update_rx_frequency (rig_->GetRxFrequency ());
|
||||
update_complete ();
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig frequency:" << state ().frequency ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::timeout_check ()
|
||||
{
|
||||
offline ("Rig went offline");
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
{
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig params change: params = 0x%1 for rig %2"}
|
||||
.arg (params, 8, 16, QChar ('0'))
|
||||
.arg (rig_number).toLocal8Bit ()
|
||||
<< "state before:" << state ());
|
||||
// starting_ = false;
|
||||
TransceiverState old_state {state ()};
|
||||
auto need_frequency = false;
|
||||
// state_.online = true; // sometimes we don't get an initial
|
||||
// // OmniRig::ST_ONLINE status change
|
||||
// // event
|
||||
if (params & OmniRig::PM_VFOAA)
|
||||
{
|
||||
update_split (false);
|
||||
reversed_ = false;
|
||||
update_rx_frequency (rig_->FreqA ());
|
||||
update_other_frequency (rig_->FreqB ());
|
||||
}
|
||||
if (params & OmniRig::PM_VFOAB)
|
||||
{
|
||||
update_split (true);
|
||||
reversed_ = false;
|
||||
update_rx_frequency (rig_->FreqA ());
|
||||
update_other_frequency (rig_->FreqB ());
|
||||
}
|
||||
if (params & OmniRig::PM_VFOBA)
|
||||
{
|
||||
update_split (true);
|
||||
reversed_ = true;
|
||||
update_other_frequency (rig_->FreqA ());
|
||||
update_rx_frequency (rig_->FreqB ());
|
||||
}
|
||||
if (params & OmniRig::PM_VFOBB)
|
||||
{
|
||||
update_split (false);
|
||||
reversed_ = true;
|
||||
update_other_frequency (rig_->FreqA ());
|
||||
update_rx_frequency (rig_->FreqB ());
|
||||
}
|
||||
if (params & OmniRig::PM_VFOA)
|
||||
{
|
||||
reversed_ = false;
|
||||
need_frequency = true;
|
||||
}
|
||||
if (params & OmniRig::PM_VFOB)
|
||||
{
|
||||
reversed_ = true;
|
||||
need_frequency = true;
|
||||
}
|
||||
|
||||
if (params & OmniRig::PM_FREQ)
|
||||
{
|
||||
need_frequency = true;
|
||||
}
|
||||
if (params & OmniRig::PM_FREQA)
|
||||
{
|
||||
if (reversed_)
|
||||
{
|
||||
update_other_frequency (rig_->FreqA ());
|
||||
}
|
||||
else
|
||||
{
|
||||
update_rx_frequency (rig_->FreqA ());
|
||||
}
|
||||
}
|
||||
if (params & OmniRig::PM_FREQB)
|
||||
{
|
||||
if (reversed_)
|
||||
{
|
||||
update_rx_frequency (rig_->FreqB ());
|
||||
}
|
||||
else
|
||||
{
|
||||
update_other_frequency (rig_->FreqB ());
|
||||
}
|
||||
}
|
||||
if (need_frequency)
|
||||
{
|
||||
if (readable_params_ & OmniRig::PM_FREQA)
|
||||
{
|
||||
if (reversed_)
|
||||
{
|
||||
update_other_frequency (rig_->FreqA ());
|
||||
}
|
||||
else
|
||||
{
|
||||
update_rx_frequency (rig_->FreqA ());
|
||||
}
|
||||
need_frequency = false;
|
||||
}
|
||||
if (readable_params_ & OmniRig::PM_FREQB)
|
||||
{
|
||||
if (reversed_)
|
||||
{
|
||||
update_rx_frequency (rig_->FreqB ());
|
||||
}
|
||||
else
|
||||
{
|
||||
update_other_frequency (rig_->FreqB ());
|
||||
}
|
||||
need_frequency = false;
|
||||
}
|
||||
}
|
||||
if (need_frequency && (readable_params_ & OmniRig::PM_FREQ)
|
||||
&& !state ().ptt ())
|
||||
{
|
||||
update_rx_frequency (rig_->Freq ());
|
||||
}
|
||||
if (params & OmniRig::PM_PITCH)
|
||||
{
|
||||
}
|
||||
if (params & OmniRig::PM_RITOFFSET)
|
||||
{
|
||||
}
|
||||
if (params & OmniRig::PM_RIT0)
|
||||
{
|
||||
}
|
||||
if (params & OmniRig::PM_VFOEQUAL)
|
||||
{
|
||||
auto f = readable_params_ & OmniRig::PM_FREQA ? rig_->FreqA () : rig_->Freq ();
|
||||
update_rx_frequency (f);
|
||||
update_other_frequency (f);
|
||||
update_mode (map_mode (rig_->Mode ()));
|
||||
}
|
||||
if (params & OmniRig::PM_VFOSWAP)
|
||||
{
|
||||
auto temp = state ().tx_frequency ();
|
||||
update_other_frequency (state ().frequency ());
|
||||
update_rx_frequency (temp);
|
||||
update_mode (map_mode (rig_->Mode ()));
|
||||
}
|
||||
if (params & OmniRig::PM_SPLITON)
|
||||
{
|
||||
update_split (true);
|
||||
}
|
||||
if (params & OmniRig::PM_SPLITOFF)
|
||||
{
|
||||
update_split (false);
|
||||
}
|
||||
if (params & OmniRig::PM_RITON)
|
||||
{
|
||||
}
|
||||
if (params & OmniRig::PM_RITOFF)
|
||||
{
|
||||
}
|
||||
if (params & OmniRig::PM_XITON)
|
||||
{
|
||||
}
|
||||
if (params & OmniRig::PM_XITOFF)
|
||||
{
|
||||
}
|
||||
if (params & OmniRig::PM_RX)
|
||||
{
|
||||
update_PTT (false);
|
||||
}
|
||||
if (params & OmniRig::PM_TX)
|
||||
{
|
||||
update_PTT ();
|
||||
}
|
||||
if (params & OmniRig::PM_CW_U)
|
||||
{
|
||||
update_mode (CW_R);
|
||||
}
|
||||
if (params & OmniRig::PM_CW_L)
|
||||
{
|
||||
update_mode (CW);
|
||||
}
|
||||
if (params & OmniRig::PM_SSB_U)
|
||||
{
|
||||
update_mode (USB);
|
||||
}
|
||||
if (params & OmniRig::PM_SSB_L)
|
||||
{
|
||||
update_mode (LSB);
|
||||
}
|
||||
if (params & OmniRig::PM_DIG_U)
|
||||
{
|
||||
update_mode (DIG_U);
|
||||
}
|
||||
if (params & OmniRig::PM_DIG_L)
|
||||
{
|
||||
update_mode (DIG_L);
|
||||
}
|
||||
if (params & OmniRig::PM_AM)
|
||||
{
|
||||
update_mode (AM);
|
||||
}
|
||||
if (params & OmniRig::PM_FM)
|
||||
{
|
||||
update_mode (FM);
|
||||
}
|
||||
|
||||
if (old_state != state () || send_update_signal_)
|
||||
{
|
||||
update_complete ();
|
||||
send_update_signal_ = false;
|
||||
}
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig params change: state after:" << state ());
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& command, QVariant const& reply)
|
||||
{
|
||||
(void)command;
|
||||
(void)reply;
|
||||
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "custom command" << command.toString ().toLocal8Bit ()
|
||||
<< "with reply" << reply.toString ().toLocal8Bit ()
|
||||
<< QString ("for rig %1").arg (rig_number).toLocal8Bit ());
|
||||
TRACE_CAT ("OmniRigTransceiver", "rig number:" << rig_number_ << ':' << state ());
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", on << state ());
|
||||
if (use_for_ptt_ && TransceiverFactory::PTT_method_CAT == ptt_type_)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set PTT");
|
||||
rig_->SetTx (on ? OmniRig::PM_TX : OmniRig::PM_RX);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (port_)
|
||||
{
|
||||
if (TransceiverFactory::PTT_method_RTS == ptt_type_)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set RTS");
|
||||
port_->SetRts (on);
|
||||
}
|
||||
else // "DTR"
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set DTR");
|
||||
port_->SetDtr (on);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set PTT using basic transceiver");
|
||||
Q_ASSERT (wrapped_);
|
||||
TransceiverState new_state {wrapped_->state ()};
|
||||
new_state.ptt (on);
|
||||
wrapped_->set (new_state, 0);
|
||||
}
|
||||
}
|
||||
update_PTT (on);
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", f << state ());
|
||||
if (UNK != m)
|
||||
{
|
||||
do_mode (m);
|
||||
}
|
||||
if (OmniRig::PM_FREQ & writable_params_)
|
||||
{
|
||||
rig_->SetFreq (f);
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
|
||||
{
|
||||
rig_->SetFreqB (f);
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
|
||||
{
|
||||
rig_->SetFreqA (f);
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_qstring (tr ("OmniRig: don't know how to set rig frequency"));
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", tx << state ());
|
||||
bool split {tx != 0};
|
||||
if (split)
|
||||
{
|
||||
if (UNK != m)
|
||||
{
|
||||
do_mode (m);
|
||||
if (OmniRig::PM_UNKNOWN == rig_->Vfo ())
|
||||
{
|
||||
if (writable_params_ & OmniRig::PM_VFOEQUAL)
|
||||
{
|
||||
// nothing to do here because OmniRig will use VFO
|
||||
// equalize to set the mode of the Tx VFO for us
|
||||
}
|
||||
else if ((writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
|
||||
== (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
|
||||
{
|
||||
rig_->SetVfo (OmniRig::PM_VFOB);
|
||||
do_mode (m);
|
||||
rig_->SetVfo (OmniRig::PM_VFOA);
|
||||
}
|
||||
else if (writable_params_ & OmniRig::PM_VFOSWAP)
|
||||
{
|
||||
rig_->SetVfo (OmniRig::PM_VFOSWAP);
|
||||
do_mode (m);
|
||||
rig_->SetVfo (OmniRig::PM_VFOSWAP);
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE_CAT ("OmniRigTransceiver", "set SPLIT mode on");
|
||||
rig_->SetSplitMode (state ().frequency (), tx);
|
||||
update_other_frequency (tx);
|
||||
update_split (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set SPLIT mode off");
|
||||
rig_->SetSimplexMode (state ().frequency ());
|
||||
update_split (false);
|
||||
}
|
||||
bool notify {false};
|
||||
if (readable_params_ & OmniRig::PM_FREQ || !(readable_params_ & (OmniRig::PM_FREQA | OmniRig::PM_FREQB)))
|
||||
{
|
||||
update_other_frequency (tx); // async updates won't return this
|
||||
// so just store it and hope
|
||||
// operator doesn't change the
|
||||
// "back" VFO on rig
|
||||
notify = true;
|
||||
}
|
||||
if (!((OmniRig::PM_VFOAB | OmniRig::PM_VFOBA | OmniRig::PM_SPLITON) & readable_params_))
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "setting SPLIT manually");
|
||||
update_split (split); // we can't read it so just set and
|
||||
// hope op doesn't change it
|
||||
notify = true;
|
||||
}
|
||||
if (notify)
|
||||
{
|
||||
update_complete ();
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", mode << state ());
|
||||
// TODO: G4WJS OmniRig doesn't seem to have any capability of tracking/setting VFO B mode
|
||||
auto mapped = map_mode (mode);
|
||||
if (mapped & writable_params_)
|
||||
{
|
||||
rig_->SetMode (mapped);
|
||||
update_mode (mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
offline ("OmniRig invalid mode");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,546 @@
|
||||
#include "PhaseEqualizationDialog.hpp"
|
||||
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
#include <QDir>
|
||||
#include <QVector>
|
||||
#include <QHBoxLayout>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
#include <QSettings>
|
||||
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "qcustomplot.h"
|
||||
#include "pimpl_impl.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float constexpr PI = 3.1415927f;
|
||||
char const * const title = "Phase Equalization";
|
||||
size_t constexpr intervals = 144;
|
||||
|
||||
// plot data loaders - wraps a plot providing value_type and
|
||||
// push_back so that a std::back_inserter output iterator can be
|
||||
// used to load plot data
|
||||
template<typename T, typename A>
|
||||
struct plot_data_loader
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
// the adjust argument is a function that is passed the plot
|
||||
// pointer, the graph index and a data point, it returns a
|
||||
// possibly adjusted data point and can modify the graph including
|
||||
// adding extra points or gaps (quiet_NaN)
|
||||
plot_data_loader (QCustomPlot * plot, int graph_index, A adjust)
|
||||
: plot_ {plot}
|
||||
, index_ {graph_index}
|
||||
, adjust_ (adjust)
|
||||
{
|
||||
}
|
||||
|
||||
// load point into graph
|
||||
void push_back (value_type const& d)
|
||||
{
|
||||
plot_->graph (index_)->data ()->add (adjust_ (plot_, index_, d));
|
||||
}
|
||||
|
||||
private:
|
||||
QCustomPlot * plot_;
|
||||
int index_;
|
||||
A adjust_;
|
||||
};
|
||||
// helper function template to make a plot_data_loader instance
|
||||
template<typename A>
|
||||
auto make_plot_data_loader (QCustomPlot * plot, int index, A adjust)
|
||||
-> plot_data_loader<QCPGraphData, decltype (adjust)>
|
||||
{
|
||||
return plot_data_loader<QCPGraphData, decltype (adjust)> {plot, index, adjust};
|
||||
}
|
||||
// identity adjust function when no adjustment is needed with the
|
||||
// above instantiation helper
|
||||
QCPGraphData adjust_identity (QCustomPlot *, int, QCPGraphData const& v) {return v;}
|
||||
|
||||
// a plot_data_loader adjustment function that wraps Y values of
|
||||
// (-1..+1) plotting discontinuities as gaps in the graph data
|
||||
auto wrap_pi = [] (QCustomPlot * plot, int index, QCPGraphData d)
|
||||
{
|
||||
double constexpr limit {1};
|
||||
static unsigned wrap_count {0};
|
||||
static double last_x {std::numeric_limits<double>::lowest ()};
|
||||
|
||||
d.value += 2 * limit * wrap_count;
|
||||
if (d.value > limit)
|
||||
{
|
||||
// insert a gap in the graph
|
||||
plot->graph (index)->data ()->add ({last_x + (d.key - last_x) / 2
|
||||
, std::numeric_limits<double>::quiet_NaN ()});
|
||||
while (d.value > limit)
|
||||
{
|
||||
--wrap_count;
|
||||
d.value -= 2 * limit;
|
||||
}
|
||||
}
|
||||
else if (d.value < -limit)
|
||||
{
|
||||
// insert a gap into the graph
|
||||
plot->graph (index)->data ()->add ({last_x + (d.key - last_x) / 2
|
||||
, std::numeric_limits<double>::quiet_NaN ()});
|
||||
while (d.value < -limit)
|
||||
{
|
||||
++wrap_count;
|
||||
d.value += 2 * limit;
|
||||
}
|
||||
}
|
||||
last_x = d.key;
|
||||
return d;
|
||||
};
|
||||
|
||||
// generate points of type R from a function of type F for X in
|
||||
// (-1..+1) with N intervals and function of type SX to scale X and
|
||||
// of type SY to scale Y
|
||||
//
|
||||
// it is up to the user to call the generator sufficient times which
|
||||
// is interval+1 times to reach +1
|
||||
template<typename R, typename F, typename SX, typename SY>
|
||||
struct graph_generator
|
||||
{
|
||||
public:
|
||||
graph_generator (F f, size_t intervals, SX x_scaling, SY y_scaling)
|
||||
: x_ {0}
|
||||
, f_ (f)
|
||||
, intervals_ {intervals}
|
||||
, x_scaling_ (x_scaling)
|
||||
, y_scaling_ (y_scaling)
|
||||
{
|
||||
}
|
||||
|
||||
R operator () ()
|
||||
{
|
||||
typename F::value_type x {x_++ * 2.f / intervals_ - 1.f};
|
||||
return {x_scaling_ (x), y_scaling_ (f_ (x))};
|
||||
}
|
||||
|
||||
private:
|
||||
int x_;
|
||||
F f_;
|
||||
size_t intervals_;
|
||||
SX x_scaling_;
|
||||
SY y_scaling_;
|
||||
};
|
||||
// helper function template to make a graph_generator instance for
|
||||
// QCPGraphData type points with intervals intervals
|
||||
template<typename F, typename SX, typename SY>
|
||||
auto make_graph_generator (F function, SX x_scaling, SY y_scaling)
|
||||
-> graph_generator<QCPGraphData, F, decltype (x_scaling), decltype (y_scaling)>
|
||||
{
|
||||
return graph_generator<QCPGraphData, F, decltype (x_scaling), decltype (y_scaling)>
|
||||
{function, intervals, x_scaling, y_scaling};
|
||||
}
|
||||
|
||||
// template function object for a polynomial with coefficients
|
||||
template<typename C>
|
||||
class polynomial
|
||||
{
|
||||
public:
|
||||
typedef typename C::value_type value_type;
|
||||
|
||||
explicit polynomial (C const& coefficients)
|
||||
: c_ {coefficients}
|
||||
{
|
||||
}
|
||||
|
||||
value_type operator () (value_type const& x)
|
||||
{
|
||||
value_type y {};
|
||||
for (typename C::size_type i = c_.size (); i > 0; --i)
|
||||
{
|
||||
y = c_[i - 1] + x * y;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
private:
|
||||
C c_;
|
||||
};
|
||||
// helper function template to instantiate a polynomial instance
|
||||
template<typename C>
|
||||
auto make_polynomial (C const& coefficients) -> polynomial<C>
|
||||
{
|
||||
return polynomial<C> (coefficients);
|
||||
}
|
||||
|
||||
// template function object for a group delay with coefficients
|
||||
template<typename C>
|
||||
class group_delay
|
||||
{
|
||||
public:
|
||||
typedef typename C::value_type value_type;
|
||||
|
||||
explicit group_delay (C const& coefficients)
|
||||
: c_ {coefficients}
|
||||
{
|
||||
}
|
||||
|
||||
value_type operator () (value_type const& x)
|
||||
{
|
||||
value_type tau {};
|
||||
for (typename C::size_type i = 2; i < c_.size (); ++i)
|
||||
{
|
||||
tau += i * c_[i] * std::pow (x, i - 1);
|
||||
}
|
||||
return -1 / (2 * PI) * tau;
|
||||
}
|
||||
|
||||
private:
|
||||
C c_;
|
||||
};
|
||||
// helper function template to instantiate a group_delay function
|
||||
// object
|
||||
template<typename C>
|
||||
auto make_group_delay (C const& coefficients) -> group_delay<C>
|
||||
{
|
||||
return group_delay<C> (coefficients);
|
||||
}
|
||||
|
||||
// handy identity function
|
||||
template<typename T> T identity (T const& v) {return v;}
|
||||
|
||||
// a lambda that scales the X axis from normalized to (500..2500)Hz
|
||||
auto freq_scaling = [] (float v) -> float {return 1500.f + 1000.f * v;};
|
||||
|
||||
// a lambda that scales the phase Y axis from radians to units of Pi
|
||||
auto pi_scaling = [] (float v) -> float {return v / PI;};
|
||||
}
|
||||
|
||||
class PhaseEqualizationDialog::impl final
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit impl (PhaseEqualizationDialog * self, QSettings * settings
|
||||
, QDir const& data_directory, QVector<double> const& coefficients
|
||||
, QWidget * parent);
|
||||
~impl () {save_window_state ();}
|
||||
|
||||
protected:
|
||||
void closeEvent (QCloseEvent * e) override
|
||||
{
|
||||
save_window_state ();
|
||||
QDialog::closeEvent (e);
|
||||
}
|
||||
|
||||
private:
|
||||
void save_window_state ()
|
||||
{
|
||||
SettingsGroup g (settings_, title);
|
||||
settings_->setValue ("geometry", saveGeometry ());
|
||||
}
|
||||
|
||||
void plot_current ();
|
||||
void plot_phase ();
|
||||
void plot_amplitude ();
|
||||
|
||||
PhaseEqualizationDialog * self_;
|
||||
QSettings * settings_;
|
||||
QDir data_directory_;
|
||||
QHBoxLayout layout_;
|
||||
QVector<double> current_coefficients_;
|
||||
QVector<double> new_coefficients_;
|
||||
unsigned amp_poly_low_;
|
||||
unsigned amp_poly_high_;
|
||||
QVector<double> amp_coefficients_;
|
||||
QCustomPlot plot_;
|
||||
QDialogButtonBox button_box_;
|
||||
};
|
||||
|
||||
#include "PhaseEqualizationDialog.moc"
|
||||
|
||||
PhaseEqualizationDialog::PhaseEqualizationDialog (QSettings * settings
|
||||
, QDir const& data_directory
|
||||
, QVector<double> const& coefficients
|
||||
, QWidget * parent)
|
||||
: m_ {this, settings, data_directory, coefficients, parent}
|
||||
{
|
||||
}
|
||||
|
||||
void PhaseEqualizationDialog::show ()
|
||||
{
|
||||
m_->show ();
|
||||
}
|
||||
|
||||
PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
||||
, QSettings * settings
|
||||
, QDir const& data_directory
|
||||
, QVector<double> const& coefficients
|
||||
, QWidget * parent)
|
||||
: QDialog {parent}
|
||||
, self_ {self}
|
||||
, settings_ {settings}
|
||||
, data_directory_ {data_directory}
|
||||
, current_coefficients_ {coefficients}
|
||||
, amp_poly_low_ {0}
|
||||
, amp_poly_high_ {6000}
|
||||
, button_box_ {QDialogButtonBox::Discard | QDialogButtonBox::Apply
|
||||
| QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Close
|
||||
, Qt::Vertical}
|
||||
{
|
||||
setWindowTitle (windowTitle () + ' ' + tr (title));
|
||||
resize (500, 600);
|
||||
{
|
||||
SettingsGroup g {settings_, title};
|
||||
restoreGeometry (settings_->value ("geometry", saveGeometry ()).toByteArray ());
|
||||
}
|
||||
|
||||
auto legend_title = new QCPTextElement {&plot_, tr ("Phase"), QFont {"sans", 9, QFont::Bold}};
|
||||
legend_title->setLayer (plot_.legend->layer ());
|
||||
plot_.legend->addElement (0, 0, legend_title);
|
||||
plot_.legend->setVisible (true);
|
||||
|
||||
plot_.xAxis->setLabel (tr ("Freq (Hz)"));
|
||||
plot_.xAxis->setRange (500, 2500);
|
||||
plot_.yAxis->setLabel (tr ("Phase (Π)"));
|
||||
plot_.yAxis->setRange (-1, +1);
|
||||
plot_.yAxis2->setLabel (tr ("Delay (ms)"));
|
||||
plot_.axisRect ()->setRangeDrag (Qt::Vertical);
|
||||
plot_.axisRect ()->setRangeZoom (Qt::Vertical);
|
||||
plot_.yAxis2->setVisible (true);
|
||||
plot_.axisRect ()->setRangeDragAxes (nullptr, plot_.yAxis2);
|
||||
plot_.axisRect ()->setRangeZoomAxes (nullptr, plot_.yAxis2);
|
||||
plot_.axisRect ()->insetLayout ()->setInsetAlignment (0, Qt::AlignBottom|Qt::AlignRight);
|
||||
plot_.setInteractions (QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
|
||||
|
||||
plot_.addGraph ()->setName (tr ("Measured"));
|
||||
plot_.graph ()->setPen (QPen {Qt::blue});
|
||||
plot_.graph ()->setVisible (false);
|
||||
plot_.graph ()->removeFromLegend ();
|
||||
|
||||
plot_.addGraph ()->setName (tr ("Proposed"));
|
||||
plot_.graph ()->setPen (QPen {Qt::red});
|
||||
plot_.graph ()->setVisible (false);
|
||||
plot_.graph ()->removeFromLegend ();
|
||||
|
||||
plot_.addGraph ()->setName (tr ("Current"));
|
||||
plot_.graph ()->setPen (QPen {Qt::green});
|
||||
|
||||
plot_.addGraph (plot_.xAxis, plot_.yAxis2)->setName (tr ("Group Delay"));
|
||||
plot_.graph ()->setPen (QPen {Qt::darkGreen});
|
||||
|
||||
plot_.plotLayout ()->addElement (new QCPAxisRect {&plot_});
|
||||
plot_.plotLayout ()->setRowStretchFactor (1, 0.5);
|
||||
|
||||
auto amp_legend = new QCPLegend;
|
||||
plot_.axisRect (1)->insetLayout ()->addElement (amp_legend, Qt::AlignTop | Qt::AlignRight);
|
||||
plot_.axisRect (1)->insetLayout ()->setMargins (QMargins {12, 12, 12, 12});
|
||||
amp_legend->setVisible (true);
|
||||
amp_legend->setLayer (QLatin1String {"legend"});
|
||||
legend_title = new QCPTextElement {&plot_, tr ("Amplitude"), QFont {"sans", 9, QFont::Bold}};
|
||||
legend_title->setLayer (amp_legend->layer ());
|
||||
amp_legend->addElement (0, 0, legend_title);
|
||||
|
||||
plot_.axisRect (1)->axis (QCPAxis::atBottom)->setLabel (tr ("Freq (Hz)"));
|
||||
plot_.axisRect (1)->axis (QCPAxis::atBottom)->setRange (0, 6000);
|
||||
plot_.axisRect (1)->axis (QCPAxis::atLeft)->setLabel (tr ("Relative Power (dB)"));
|
||||
plot_.axisRect (1)->axis (QCPAxis::atLeft)->setRangeLower (0);
|
||||
plot_.axisRect (1)->setRangeDragAxes (nullptr, nullptr);
|
||||
plot_.axisRect (1)->setRangeZoomAxes (nullptr, nullptr);
|
||||
|
||||
plot_.addGraph (plot_.axisRect (1)->axis (QCPAxis::atBottom)
|
||||
, plot_.axisRect (1)->axis (QCPAxis::atLeft))->setName (tr ("Reference"));
|
||||
plot_.graph ()->setPen (QPen {Qt::blue});
|
||||
plot_.graph ()->removeFromLegend ();
|
||||
plot_.graph ()->addToLegend (amp_legend);
|
||||
|
||||
layout_.addWidget (&plot_);
|
||||
|
||||
auto load_phase_button = button_box_.addButton (tr ("Phase ..."), QDialogButtonBox::ActionRole);
|
||||
auto refresh_button = button_box_.addButton (tr ("Refresh"), QDialogButtonBox::ActionRole);
|
||||
layout_.addWidget (&button_box_);
|
||||
setLayout (&layout_);
|
||||
|
||||
connect (&button_box_, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect (&button_box_, &QDialogButtonBox::clicked, [=] (QAbstractButton * button) {
|
||||
if (button == load_phase_button)
|
||||
{
|
||||
plot_phase ();
|
||||
}
|
||||
else if (button == refresh_button)
|
||||
{
|
||||
plot_current ();
|
||||
}
|
||||
else if (button == button_box_.button (QDialogButtonBox::Apply))
|
||||
{
|
||||
if (plot_.graph (0)->dataCount ()) // something loaded
|
||||
{
|
||||
current_coefficients_ = new_coefficients_;
|
||||
Q_EMIT self_->phase_equalization_changed (current_coefficients_);
|
||||
plot_current ();
|
||||
}
|
||||
}
|
||||
else if (button == button_box_.button (QDialogButtonBox::RestoreDefaults))
|
||||
{
|
||||
current_coefficients_ = QVector<double> {0., 0., 0., 0., 0.};
|
||||
Q_EMIT self_->phase_equalization_changed (current_coefficients_);
|
||||
plot_current ();
|
||||
}
|
||||
else if (button == button_box_.button (QDialogButtonBox::Discard))
|
||||
{
|
||||
new_coefficients_ = QVector<double> {0., 0., 0., 0., 0.};
|
||||
|
||||
plot_.graph (0)->data ()->clear ();
|
||||
plot_.graph (0)->setVisible (false);
|
||||
plot_.graph (0)->removeFromLegend ();
|
||||
|
||||
plot_.graph (1)->data ()->clear ();
|
||||
plot_.graph (1)->setVisible (false);
|
||||
plot_.graph (1)->removeFromLegend ();
|
||||
|
||||
plot_.replot ();
|
||||
}
|
||||
});
|
||||
|
||||
plot_current ();
|
||||
}
|
||||
|
||||
struct PowerSpectrumPoint
|
||||
{
|
||||
operator QCPGraphData () const
|
||||
{
|
||||
return QCPGraphData {freq_, power_};
|
||||
}
|
||||
|
||||
float freq_;
|
||||
float power_;
|
||||
};
|
||||
|
||||
// read an amplitude point line from a stream (refspec.dat)
|
||||
std::istream& operator >> (std::istream& is, PowerSpectrumPoint& r)
|
||||
{
|
||||
float y1, y3, y4; // discard these
|
||||
is >> r.freq_ >> y1 >> r.power_ >> y3 >> y4;
|
||||
return is;
|
||||
}
|
||||
|
||||
void PhaseEqualizationDialog::impl::plot_current ()
|
||||
{
|
||||
auto phase_graph = make_plot_data_loader (&plot_, 2, wrap_pi);
|
||||
plot_.graph (2)->data ()->clear ();
|
||||
std::generate_n (std::back_inserter (phase_graph), intervals + 1
|
||||
, make_graph_generator (make_polynomial (current_coefficients_), freq_scaling, pi_scaling));
|
||||
|
||||
auto group_delay_graph = make_plot_data_loader (&plot_, 3, adjust_identity);
|
||||
plot_.graph (3)->data ()->clear ();
|
||||
std::generate_n (std::back_inserter (group_delay_graph), intervals + 1
|
||||
, make_graph_generator (make_group_delay (current_coefficients_), freq_scaling, identity<double>));
|
||||
plot_.graph (3)->rescaleValueAxis ();
|
||||
|
||||
QFileInfo refspec_file_info {data_directory_.absoluteFilePath ("refspec.dat")};
|
||||
std::ifstream refspec_file (refspec_file_info.absoluteFilePath ().toLatin1 ().constData (), std::ifstream::in);
|
||||
unsigned n;
|
||||
if (refspec_file >> amp_poly_low_ >> amp_poly_high_ >> n)
|
||||
{
|
||||
std::istream_iterator<double> isi {refspec_file};
|
||||
amp_coefficients_.clear ();
|
||||
std::copy_n (isi, n, std::back_inserter (amp_coefficients_));
|
||||
}
|
||||
else
|
||||
{
|
||||
// may be old format refspec.dat with no header so rewind
|
||||
refspec_file.clear ();
|
||||
refspec_file.seekg (0);
|
||||
}
|
||||
|
||||
auto reference_spectrum_graph = make_plot_data_loader (&plot_, 4, adjust_identity);
|
||||
plot_.graph (4)->data ()->clear ();
|
||||
std::copy (std::istream_iterator<PowerSpectrumPoint> {refspec_file},
|
||||
std::istream_iterator<PowerSpectrumPoint> {},
|
||||
std::back_inserter (reference_spectrum_graph));
|
||||
plot_.graph (4)->rescaleValueAxis (true);
|
||||
|
||||
plot_.replot ();
|
||||
}
|
||||
|
||||
struct PhasePoint
|
||||
{
|
||||
operator QCPGraphData () const
|
||||
{
|
||||
return QCPGraphData {freq_, phase_};
|
||||
}
|
||||
|
||||
double freq_;
|
||||
double phase_;
|
||||
};
|
||||
|
||||
// read a phase point line from a stream (pcoeff file)
|
||||
std::istream& operator >> (std::istream& is, PhasePoint& c)
|
||||
{
|
||||
double pp, sigmay; // discard these
|
||||
if (is >> c.freq_ >> pp >> c.phase_ >> sigmay)
|
||||
{
|
||||
c.freq_ = 1500. + 1000. * c.freq_; // scale frequency to Hz
|
||||
c.phase_ /= PI; // scale to units of Pi
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
void PhaseEqualizationDialog::impl::plot_phase ()
|
||||
{
|
||||
auto const& phase_file_name = QFileDialog::getOpenFileName (this
|
||||
, "Select Phase Response Coefficients"
|
||||
, data_directory_.absolutePath ()
|
||||
, "Phase Coefficient Files (*.pcoeff)");
|
||||
if (!phase_file_name.size ()) return;
|
||||
|
||||
std::ifstream phase_file (phase_file_name.toLatin1 ().constData (), std::ifstream::in);
|
||||
int n;
|
||||
float chi;
|
||||
float rmsdiff;
|
||||
unsigned freq_low;
|
||||
unsigned freq_high;
|
||||
unsigned terms;
|
||||
// read header information
|
||||
if (phase_file >> n >> chi >> rmsdiff >> freq_low >> freq_high >> terms)
|
||||
{
|
||||
std::istream_iterator<double> isi {phase_file};
|
||||
new_coefficients_.clear ();
|
||||
std::copy_n (isi, terms, std::back_inserter (new_coefficients_));
|
||||
|
||||
if (phase_file)
|
||||
{
|
||||
plot_.graph (0)->data ()->clear ();
|
||||
plot_.graph (1)->data ()->clear ();
|
||||
|
||||
// read the phase data and plot as graph 0
|
||||
auto graph = make_plot_data_loader (&plot_, 0, adjust_identity);
|
||||
std::copy_n (std::istream_iterator<PhasePoint> {phase_file},
|
||||
intervals + 1, std::back_inserter (graph));
|
||||
|
||||
if (phase_file)
|
||||
{
|
||||
plot_.graph(0)->setLineStyle(QCPGraph::lsNone);
|
||||
plot_.graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 4));
|
||||
plot_.graph (0)->setVisible (true);
|
||||
plot_.graph (0)->addToLegend ();
|
||||
|
||||
// generate the proposed polynomial plot as graph 1
|
||||
auto graph = make_plot_data_loader (&plot_, 1, wrap_pi);
|
||||
std::generate_n (std::back_inserter (graph), intervals + 1
|
||||
, make_graph_generator (make_polynomial (new_coefficients_)
|
||||
, freq_scaling, pi_scaling));
|
||||
plot_.graph (1)->setVisible (true);
|
||||
plot_.graph (1)->addToLegend ();
|
||||
}
|
||||
|
||||
plot_.replot ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_PhaseEqualizationDialog.cpp"
|
||||
@@ -0,0 +1,181 @@
|
||||
// -*- Mode: C++ -*-
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
#ifdef QT5
|
||||
#include <QtWidgets>
|
||||
#else
|
||||
#include <QtGui>
|
||||
#endif
|
||||
#include <QFrame>
|
||||
#include <QImage>
|
||||
#include <QVector>
|
||||
#include <cstring>
|
||||
|
||||
#define VERT_DIVS 7 //specify grid screen divisions
|
||||
#define HORZ_DIVS 20
|
||||
|
||||
extern bool g_single_decode;
|
||||
|
||||
class CPlotter : public QFrame
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
explicit CPlotter(QWidget *parent = 0);
|
||||
~CPlotter();
|
||||
|
||||
QSize minimumSizeHint() const;
|
||||
QSize sizeHint() const;
|
||||
bool m_bScaleOK;
|
||||
|
||||
void draw(float swide[], bool bScroll, bool bRed); //Update the waterfall
|
||||
void SetRunningState(bool running);
|
||||
void setPlotZero(int plotZero);
|
||||
int plotZero();
|
||||
void setPlotGain(int plotGain);
|
||||
int plotGain();
|
||||
int plot2dGain();
|
||||
void setPlot2dGain(int n);
|
||||
int plot2dZero();
|
||||
void setPlot2dZero(int plot2dZero);
|
||||
void setStartFreq(int f);
|
||||
int startFreq();
|
||||
int plotWidth();
|
||||
void UpdateOverlay();
|
||||
void setDataFromDisk(bool b);
|
||||
void setRxRange(int fMin);
|
||||
void setBinsPerPixel(int n);
|
||||
int binsPerPixel();
|
||||
void setWaterfallAvg(int n);
|
||||
void setRxFreq(int n);
|
||||
void DrawOverlay();
|
||||
int rxFreq();
|
||||
void setFsample(int n);
|
||||
void setNsps(int ntrperiod, int nsps);
|
||||
void setTxFreq(int n);
|
||||
void setMode(QString mode);
|
||||
void setSubMode(int n);
|
||||
void setModeTx(QString modeTx);
|
||||
void SetPercent2DScreen(int percent);
|
||||
int Fmax();
|
||||
void setDialFreq(double d);
|
||||
void setCurrent(bool b) {m_bCurrent = b;}
|
||||
bool current() const {return m_bCurrent;}
|
||||
void setCumulative(bool b) {m_bCumulative = b;}
|
||||
bool cumulative() const {return m_bCumulative;}
|
||||
void setLinearAvg(bool b) {m_bLinearAvg = b;}
|
||||
bool linearAvg() const {return m_bLinearAvg;}
|
||||
void setBreadth(qint32 w) {m_w = w;}
|
||||
qint32 breadth() const {return m_w;}
|
||||
float fSpan() const {return m_fSpan;}
|
||||
void setColours(QVector<QColor> const& cl);
|
||||
void setFlatten(bool b1, bool b2);
|
||||
void setTol(int n);
|
||||
void setRxBand(QString band);
|
||||
void setReference(bool b) {m_bReference = b;}
|
||||
bool Reference() const {return m_bReference;}
|
||||
void drawRed(int ia, int ib, float swide[]);
|
||||
void setVHF(bool bVHF);
|
||||
void setRedFile(QString fRed);
|
||||
|
||||
signals:
|
||||
void freezeDecode1(int n);
|
||||
void setFreq1(int rxFreq, int txFreq);
|
||||
|
||||
protected:
|
||||
//re-implemented widget event handlers
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
void MakeFrequencyStrs();
|
||||
int XfromFreq(float f);
|
||||
float FreqfromX(int x);
|
||||
|
||||
bool m_bCurrent;
|
||||
bool m_bCumulative;
|
||||
bool m_bLinearAvg;
|
||||
bool m_bReference;
|
||||
bool m_bReference0;
|
||||
bool m_bVHF;
|
||||
|
||||
float m_fSpan;
|
||||
|
||||
qint32 m_plotZero;
|
||||
qint32 m_plotGain;
|
||||
qint32 m_plot2dGain;
|
||||
qint32 m_plot2dZero;
|
||||
qint32 m_binsPerPixel;
|
||||
qint32 m_waterfallAvg;
|
||||
qint32 m_w;
|
||||
qint32 m_Flatten;
|
||||
qint32 m_nSubMode;
|
||||
qint32 m_ia;
|
||||
qint32 m_ib;
|
||||
|
||||
QPixmap m_WaterfallPixmap;
|
||||
QPixmap m_2DPixmap;
|
||||
QPixmap m_ScalePixmap;
|
||||
QPixmap m_OverlayPixmap;
|
||||
|
||||
QSize m_Size;
|
||||
QString m_Str;
|
||||
QString m_HDivText[483];
|
||||
QString m_mode;
|
||||
QString m_modeTx;
|
||||
QString m_rxBand;
|
||||
QString m_redFile;
|
||||
|
||||
bool m_Running;
|
||||
bool m_paintEventBusy;
|
||||
bool m_dataFromDisk;
|
||||
|
||||
double m_fftBinWidth;
|
||||
double m_dialFreq;
|
||||
double m_xOffset;
|
||||
|
||||
float m_sum[2048];
|
||||
|
||||
qint32 m_dBStepSize;
|
||||
qint32 m_FreqUnits;
|
||||
qint32 m_hdivs;
|
||||
qint32 m_line;
|
||||
qint32 m_fSample;
|
||||
qint32 m_xClick;
|
||||
qint32 m_freqPerDiv;
|
||||
qint32 m_nsps;
|
||||
qint32 m_Percent2DScreen;
|
||||
qint32 m_Percent2DScreen0;
|
||||
qint32 m_h;
|
||||
qint32 m_h1;
|
||||
qint32 m_h2;
|
||||
qint32 m_TRperiod;
|
||||
qint32 m_rxFreq;
|
||||
qint32 m_txFreq;
|
||||
qint32 m_fMin;
|
||||
qint32 m_fMax;
|
||||
qint32 m_startFreq;
|
||||
qint32 m_tol;
|
||||
|
||||
char m_sutc[6];
|
||||
|
||||
private slots:
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
};
|
||||
|
||||
extern QVector<QColor> g_ColorTbl;
|
||||
|
||||
extern "C" {
|
||||
void flat4_(float swide[], int* iz, int* nflatten);
|
||||
}
|
||||
|
||||
#endif // PLOTTER_H
|
||||
@@ -0,0 +1,144 @@
|
||||
// Boost.Units - A C++ library for zero-overhead dimensional analysis and
|
||||
// unit/quantity manipulation and conversion
|
||||
//
|
||||
// Copyright (C) 2003-2008 Matthias Christian Schabel
|
||||
// Copyright (C) 2008 Steven Watanabe
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_UNITS_SCALED_BASE_UNIT_HPP_INCLUDED
|
||||
#define BOOST_UNITS_SCALED_BASE_UNIT_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/less.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
#include <boost/units/config.hpp>
|
||||
#include <boost/units/dimension.hpp>
|
||||
#include <boost/units/static_rational.hpp>
|
||||
#include <boost/units/units_fwd.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace units {
|
||||
|
||||
template<class T>
|
||||
struct heterogeneous_system;
|
||||
|
||||
template<class T, class D, class Scale>
|
||||
struct heterogeneous_system_impl;
|
||||
|
||||
template<class T, class E>
|
||||
struct heterogeneous_system_dim;
|
||||
|
||||
template<class T>
|
||||
struct base_unit_info;
|
||||
|
||||
/// INTERNAL ONLY
|
||||
struct scaled_base_unit_tag {};
|
||||
|
||||
template<class S, class Scale>
|
||||
struct scaled_base_unit
|
||||
{
|
||||
/// INTERNAL ONLY
|
||||
typedef void boost_units_is_base_unit_type;
|
||||
typedef scaled_base_unit type;
|
||||
typedef scaled_base_unit_tag tag;
|
||||
typedef S system_type;
|
||||
typedef Scale scale_type;
|
||||
typedef typename S::dimension_type dimension_type;
|
||||
|
||||
#ifdef BOOST_UNITS_DOXYGEN
|
||||
|
||||
typedef detail::unspecified unit_type;
|
||||
|
||||
#else
|
||||
|
||||
typedef unit<
|
||||
dimension_type,
|
||||
heterogeneous_system<
|
||||
heterogeneous_system_impl<
|
||||
list<
|
||||
heterogeneous_system_dim<scaled_base_unit,static_rational<1> >,
|
||||
dimensionless_type
|
||||
>,
|
||||
dimension_type,
|
||||
dimensionless_type
|
||||
>
|
||||
>
|
||||
> unit_type;
|
||||
|
||||
#endif
|
||||
|
||||
static std::string symbol()
|
||||
{
|
||||
return(Scale::symbol() + base_unit_info<S>::symbol());
|
||||
}
|
||||
static std::string name()
|
||||
{
|
||||
return(Scale::name() + base_unit_info<S>::name());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#if BOOST_UNITS_HAS_BOOST_TYPEOF
|
||||
|
||||
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
|
||||
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::scaled_base_unit, (class)(class))
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#ifndef BOOST_UNITS_DOXYGEN
|
||||
|
||||
namespace mpl {
|
||||
|
||||
/// INTERNAL ONLY
|
||||
template<class Tag>
|
||||
struct less_impl<boost::units::scaled_base_unit_tag, Tag>
|
||||
{
|
||||
template<class T0, class T1>
|
||||
struct apply : mpl::bool_<
|
||||
mpl::less<typename T0::system_type, T1>::value ||
|
||||
(boost::is_same<typename T0::system_type, T1>::value && ((T0::scale_type::exponent::Numerator) < 0)) > {};
|
||||
};
|
||||
|
||||
/// INTERNAL ONLY
|
||||
template<class Tag>
|
||||
struct less_impl<Tag, boost::units::scaled_base_unit_tag>
|
||||
{
|
||||
template<class T0, class T1>
|
||||
struct apply : mpl::bool_<
|
||||
mpl::less<T0, typename T1::system_type>::value ||
|
||||
(boost::is_same<T0, typename T1::system_type>::value && ((T1::scale_type::exponent::Numerator) > 0)) > {};
|
||||
};
|
||||
|
||||
/// INTERNAL ONLY
|
||||
template<>
|
||||
struct less_impl<boost::units::scaled_base_unit_tag, boost::units::scaled_base_unit_tag>
|
||||
{
|
||||
template<class T0, class T1>
|
||||
struct apply : mpl::bool_<
|
||||
mpl::less<typename T0::system_type, typename T1::system_type>::value ||
|
||||
((boost::is_same<typename T0::system_type, typename T1::system_type>::value) &&
|
||||
((T0::scale_type::base) < (T1::scale_type::base) ||
|
||||
((T0::scale_type::base) == (T1::scale_type::base) &&
|
||||
mpl::less<typename T0::scale_type::exponent, typename T1::scale_type::exponent>::value))) > {};
|
||||
};
|
||||
|
||||
} // namespace mpl
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
subroutine fil6521(c1,n1,c2,n2)
|
||||
|
||||
! FIR lowpass filter designed using ScopeFIR
|
||||
|
||||
! Pass #1 Pass #2
|
||||
! -----------------------------------------------
|
||||
! fsample (Hz) 1378.125 Input sample rate
|
||||
! Ntaps 21 Number of filter taps
|
||||
! fc (Hz) 40 Cutoff frequency
|
||||
! fstop (Hz) 172.266 Lower limit of stopband
|
||||
! Ripple (dB) 0.1 Ripple in passband
|
||||
! Stop Atten (dB) 38 Stopband attenuation
|
||||
! 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)
|
||||
|
||||
! Filter coefficients:
|
||||
real a(-NH:NH+NTAPS/3)
|
||||
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,1.43370769e-019,2.64031087e-006,6.25548654e+028, &
|
||||
2.44565251e+020,4.74227538e+030,10497312.0e0000,7.74079654e-039/
|
||||
|
||||
n2=(n1-NTAPS+NDOWN)/NDOWN
|
||||
k0=NH-NDOWN+1
|
||||
|
||||
! 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
|
||||
@@ -0,0 +1,192 @@
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// See http://boostorg.github.com/compute for more information.
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
#ifndef BOOST_COMPUTE_ITERATOR_PERMUTATION_ITERATOR_HPP
|
||||
#define BOOST_COMPUTE_ITERATOR_PERMUTATION_ITERATOR_HPP
|
||||
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
|
||||
#include <boost/compute/functional.hpp>
|
||||
#include <boost/compute/detail/meta_kernel.hpp>
|
||||
#include <boost/compute/detail/is_buffer_iterator.hpp>
|
||||
#include <boost/compute/detail/read_write_single_value.hpp>
|
||||
#include <boost/compute/iterator/detail/get_base_iterator_buffer.hpp>
|
||||
#include <boost/compute/type_traits/is_device_iterator.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace compute {
|
||||
|
||||
// forward declaration for transform_iterator
|
||||
template<class ElementIterator, class IndexIterator>
|
||||
class permutation_iterator;
|
||||
|
||||
namespace detail {
|
||||
|
||||
// helper class which defines the iterator_adaptor super-class
|
||||
// type for permutation_iterator
|
||||
template<class ElementIterator, class IndexIterator>
|
||||
class permutation_iterator_base
|
||||
{
|
||||
public:
|
||||
typedef ::boost::iterator_adaptor<
|
||||
::boost::compute::permutation_iterator<ElementIterator, IndexIterator>,
|
||||
ElementIterator
|
||||
> type;
|
||||
};
|
||||
|
||||
template<class ElementIterator, class IndexIterator, class IndexExpr>
|
||||
struct permutation_iterator_access_expr
|
||||
{
|
||||
typedef typename std::iterator_traits<ElementIterator>::value_type result_type;
|
||||
|
||||
permutation_iterator_access_expr(const ElementIterator &e,
|
||||
const IndexIterator &i,
|
||||
const IndexExpr &expr)
|
||||
: m_element_iter(e),
|
||||
m_index_iter(i),
|
||||
m_expr(expr)
|
||||
{
|
||||
}
|
||||
|
||||
ElementIterator m_element_iter;
|
||||
IndexIterator m_index_iter;
|
||||
IndexExpr m_expr;
|
||||
};
|
||||
|
||||
template<class ElementIterator, class IndexIterator, class IndexExpr>
|
||||
inline meta_kernel& operator<<(meta_kernel &kernel,
|
||||
const permutation_iterator_access_expr<ElementIterator,
|
||||
IndexIterator,
|
||||
IndexExpr> &expr)
|
||||
{
|
||||
return kernel << expr.m_element_iter[expr.m_index_iter[expr.m_expr]];
|
||||
}
|
||||
|
||||
} // end detail namespace
|
||||
|
||||
/// \class permutation_iterator
|
||||
/// \brief The permutation_iterator class provides a permuation iterator
|
||||
///
|
||||
/// A permutation iterator iterates over a value range and an index range. When
|
||||
/// dereferenced, it returns the value from the value range using the current
|
||||
/// index from the index range.
|
||||
///
|
||||
/// For example, to reverse a range using the copy() algorithm and a permutation
|
||||
/// sequence:
|
||||
///
|
||||
/// \snippet test/test_permutation_iterator.cpp reverse_range
|
||||
///
|
||||
/// \see make_permutation_iterator()
|
||||
template<class ElementIterator, class IndexIterator>
|
||||
class permutation_iterator
|
||||
: public detail::permutation_iterator_base<ElementIterator,
|
||||
IndexIterator>::type
|
||||
{
|
||||
public:
|
||||
typedef typename
|
||||
detail::permutation_iterator_base<ElementIterator,
|
||||
IndexIterator>::type super_type;
|
||||
typedef typename super_type::value_type value_type;
|
||||
typedef typename super_type::reference reference;
|
||||
typedef typename super_type::base_type base_type;
|
||||
typedef typename super_type::difference_type difference_type;
|
||||
typedef IndexIterator index_iterator;
|
||||
|
||||
permutation_iterator(ElementIterator e, IndexIterator i)
|
||||
: super_type(e),
|
||||
m_map(i)
|
||||
{
|
||||
}
|
||||
|
||||
permutation_iterator(const permutation_iterator<ElementIterator,
|
||||
IndexIterator> &other)
|
||||
: super_type(other),
|
||||
m_map(other.m_map)
|
||||
{
|
||||
}
|
||||
|
||||
permutation_iterator<ElementIterator, IndexIterator>&
|
||||
operator=(const permutation_iterator<ElementIterator,
|
||||
IndexIterator> &other)
|
||||
{
|
||||
if(this != &other){
|
||||
super_type::operator=(other);
|
||||
m_map = other.m_map;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~permutation_iterator()
|
||||
{
|
||||
}
|
||||
|
||||
size_t get_index() const
|
||||
{
|
||||
return super_type::base().get_index();
|
||||
}
|
||||
|
||||
const buffer& get_buffer() const
|
||||
{
|
||||
return detail::get_base_iterator_buffer(*this);
|
||||
}
|
||||
|
||||
template<class IndexExpr>
|
||||
detail::permutation_iterator_access_expr<ElementIterator,
|
||||
IndexIterator,
|
||||
IndexExpr>
|
||||
operator[](const IndexExpr &expr) const
|
||||
{
|
||||
return detail::permutation_iterator_access_expr<ElementIterator,
|
||||
IndexIterator,
|
||||
IndexExpr>(super_type::base(),
|
||||
m_map,
|
||||
expr);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ::boost::iterator_core_access;
|
||||
|
||||
reference dereference() const
|
||||
{
|
||||
return reference();
|
||||
}
|
||||
|
||||
private:
|
||||
IndexIterator m_map;
|
||||
};
|
||||
|
||||
/// Returns a permutation_iterator for \p e using indices from \p i.
|
||||
///
|
||||
/// \param e the element range iterator
|
||||
/// \param i the index range iterator
|
||||
///
|
||||
/// \return a \c permutation_iterator for \p e using \p i
|
||||
template<class ElementIterator, class IndexIterator>
|
||||
inline permutation_iterator<ElementIterator, IndexIterator>
|
||||
make_permutation_iterator(ElementIterator e, IndexIterator i)
|
||||
{
|
||||
return permutation_iterator<ElementIterator, IndexIterator>(e, i);
|
||||
}
|
||||
|
||||
/// \internal_ (is_device_iterator specialization for permutation_iterator)
|
||||
template<class ElementIterator, class IndexIterator>
|
||||
struct is_device_iterator<
|
||||
permutation_iterator<ElementIterator, IndexIterator> > : boost::true_type {};
|
||||
|
||||
} // end compute namespace
|
||||
} // end boost namespace
|
||||
|
||||
#endif // BOOST_COMPUTE_ITERATOR_PERMUTATION_ITERATOR_HPP
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#ifndef BOOST_MPL_POP_BACK_HPP_INCLUDED
|
||||
#define BOOST_MPL_POP_BACK_HPP_INCLUDED
|
||||
|
||||
// Copyright Aleksey Gurtovoy 2000-2004
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/mpl for documentation.
|
||||
|
||||
// $Id$
|
||||
// $Date$
|
||||
// $Revision$
|
||||
|
||||
#include <boost/mpl/pop_back_fwd.hpp>
|
||||
#include <boost/mpl/aux_/pop_back_impl.hpp>
|
||||
#include <boost/mpl/sequence_tag.hpp>
|
||||
#include <boost/mpl/aux_/na_spec.hpp>
|
||||
#include <boost/mpl/aux_/lambda_support.hpp>
|
||||
|
||||
namespace boost { namespace mpl {
|
||||
|
||||
template<
|
||||
typename BOOST_MPL_AUX_NA_PARAM(Sequence)
|
||||
>
|
||||
struct pop_back
|
||||
: pop_back_impl< typename sequence_tag<Sequence>::type >
|
||||
::template apply< Sequence >
|
||||
{
|
||||
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,pop_back,(Sequence))
|
||||
};
|
||||
|
||||
BOOST_MPL_AUX_NA_SPEC(1, pop_back)
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_MPL_POP_BACK_HPP_INCLUDED
|
||||
@@ -0,0 +1,197 @@
|
||||
program msk144sd
|
||||
!
|
||||
! A simple decoder for slow msk144.
|
||||
! Can be used as a (slow) brute-force multi-decoder by looping
|
||||
! over a set of carrier frequencies.
|
||||
!
|
||||
use options
|
||||
use timer_module, only: timer
|
||||
use timer_impl, only: init_timer
|
||||
use readwav
|
||||
|
||||
parameter (NRECENT=10)
|
||||
parameter (NSPM=864)
|
||||
parameter (NPATTERNS=4)
|
||||
|
||||
character ch
|
||||
character*80 line
|
||||
character*500 infile
|
||||
character*12 mycall,hiscall
|
||||
character*6 mygrid
|
||||
character(len=500) optarg
|
||||
character*22 msgreceived
|
||||
character*12 recent_calls(NRECENT)
|
||||
|
||||
complex cdat(30*375)
|
||||
complex c(NSPM)
|
||||
complex ct(NSPM)
|
||||
|
||||
real softbits(144)
|
||||
real xmc(NPATTERNS)
|
||||
|
||||
logical :: display_help=.false.
|
||||
|
||||
type(wav_header) :: wav
|
||||
|
||||
integer iavmask(8)
|
||||
integer iavpatterns(8,NPATTERNS)
|
||||
integer npkloc(10)
|
||||
|
||||
integer*2 id2(30*12000)
|
||||
integer*2 ichunk(7*1024)
|
||||
|
||||
data iavpatterns/ &
|
||||
1,1,1,1,0,0,0,0, &
|
||||
0,1,1,1,1,0,0,0, &
|
||||
0,0,1,1,1,1,0,0, &
|
||||
1,1,1,1,1,1,0,0/
|
||||
data xmc/2.0,4.5,2.5,3.0/
|
||||
|
||||
type (option) :: long_options(2) = [ &
|
||||
option ('frequency',.true.,'f','rxfreq',''), &
|
||||
option ('help',.false.,'h','Display this help message','') &
|
||||
]
|
||||
t0=0.0
|
||||
ntol=100
|
||||
nrxfreq=1500
|
||||
|
||||
do
|
||||
call getopt('f:h',long_options,ch,optarg,narglen,nstat,noffset,nremain,.true.)
|
||||
if( nstat .ne. 0 ) then
|
||||
exit
|
||||
end if
|
||||
select case (ch)
|
||||
case ('f')
|
||||
read (optarg(:narglen), *) nrxfreq
|
||||
case ('h')
|
||||
display_help = .true.
|
||||
end select
|
||||
end do
|
||||
|
||||
if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then
|
||||
print *, ''
|
||||
print *, 'Usage: msk144sd [OPTIONS] file1 [file2 ...]'
|
||||
print *, ''
|
||||
print *, ' decode pre-recorded .WAV file(s)'
|
||||
print *, ''
|
||||
print *, 'OPTIONS:'
|
||||
do i = 1, size (long_options)
|
||||
call long_options(i) % print (6)
|
||||
end do
|
||||
go to 999
|
||||
endif
|
||||
|
||||
call init_timer ('timer.out')
|
||||
call timer('msk144 ',0)
|
||||
ndecoded=0
|
||||
do ifile=noffset+1,noffset+nremain
|
||||
call get_command_argument(ifile,optarg,narglen)
|
||||
infile=optarg(:narglen)
|
||||
call timer('read ',0)
|
||||
call wav%read (infile)
|
||||
i1=index(infile,'.wav')
|
||||
if( i1 .eq. 0 ) i1=index(infile,'.WAV')
|
||||
read(infile(i1-6:i1-1),*,err=998) nutc
|
||||
inquire(FILE=infile,SIZE=isize)
|
||||
npts=min((isize-216)/2,360000)
|
||||
read(unit=wav%lun) id2(1:npts)
|
||||
close(unit=wav%lun)
|
||||
call timer('read ',1)
|
||||
|
||||
! do if=1,89 ! brute force multi-decoder
|
||||
fo=nrxfreq
|
||||
! fo=(if-1)*25.0+300.0
|
||||
call msksddc(id2,npts,fo,cdat)
|
||||
np=npts/32
|
||||
ntol=200 ! actual ntol is ntol/32=6.25 Hz. Detection window is 12.5 Hz wide
|
||||
fc=1500.0
|
||||
call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, &
|
||||
softbits,recent_calls,nrecent)
|
||||
nsnr=0 ! need an snr estimate
|
||||
if( ndecodesuccess .eq. 1 ) then
|
||||
fest=fo+fest-fc ! fudging because spd thinks input signal is at 1500 Hz
|
||||
goto 900
|
||||
endif
|
||||
! If short ping decoder doesn't find a decode
|
||||
npat=NPATTERNS
|
||||
do iavg=1,npat
|
||||
iavmask=iavpatterns(1:8,iavg)
|
||||
navg=sum(iavmask)
|
||||
deltaf=4.0/real(navg) ! search increment for frequency sync
|
||||
npeaks=4
|
||||
ntol=200
|
||||
fc=1500.0
|
||||
call msk144sync(cdat(1:6*NSPM),6,ntol,deltaf,iavmask,npeaks,fc, &
|
||||
fest,npkloc,nsyncsuccess,xmax,c)
|
||||
if( nsyncsuccess .eq. 0 ) cycle
|
||||
|
||||
do ipk=1,npeaks
|
||||
do is=1,3
|
||||
ic0=npkloc(ipk)
|
||||
if(is.eq.2) ic0=max(1,ic0-1)
|
||||
if(is.eq.3) ic0=min(NSPM,ic0+1)
|
||||
ct=cshift(c,ic0-1)
|
||||
call msk144decodeframe(ct,softbits,msgreceived,ndecodesuccess, &
|
||||
recent_calls,nrecent)
|
||||
if(ndecodesuccess .gt. 0) then
|
||||
tdec=tsec+xmc(iavg)*tframe
|
||||
fest=fo+(fest-fc)/32.0
|
||||
goto 900
|
||||
endif
|
||||
enddo !Slicer dither
|
||||
enddo !Peak loop
|
||||
enddo
|
||||
|
||||
! enddo
|
||||
900 continue
|
||||
if( ndecodesuccess .gt. 0 ) then
|
||||
write(*,1020) nutc,nsnr,tdec,nint(fest),' % ',msgreceived,navg
|
||||
1020 format(i6.6,i4,f5.1,i5,a3,a22,i4)
|
||||
endif
|
||||
enddo
|
||||
|
||||
call timer('msk144 ',1)
|
||||
call timer('msk144 ',101)
|
||||
go to 999
|
||||
|
||||
998 print*,'Cannot read from file:'
|
||||
print*,infile
|
||||
|
||||
999 continue
|
||||
end program msk144sd
|
||||
|
||||
subroutine msksddc(id2,npts,fc,cdat)
|
||||
|
||||
! The msk144 detector/demodulator/decoder will decode signals
|
||||
! with carrier frequency, fc, in the range fN/4 +/- 0.03333*fN.
|
||||
!
|
||||
! For slow MSK144 with nslow=32:
|
||||
! fs=12000/32=375 Hz, fN=187.5 Hz
|
||||
!
|
||||
! This routine accepts input samples with fs=12000 Hz. It
|
||||
! downconverts and decimates by 32 to center a signal with input carrier
|
||||
! frequency fc at new carrier frequency 1500/32=46.875 Hz.
|
||||
! The analytic signal is returned.
|
||||
|
||||
parameter (NFFT1=30*12000,NFFT2=30*375)
|
||||
integer*2 id2(npts)
|
||||
complex cx(0:NFFT1)
|
||||
complex cdat(30*375)
|
||||
|
||||
dt=1.0/12000.0
|
||||
df=1.0/(NFFT1*dt)
|
||||
icenter=int(fc/df+0.5)
|
||||
i46p875=int(46.875/df+0.5)
|
||||
ishift=icenter-i46p875
|
||||
cx=cmplx(0.0,0.0)
|
||||
cx(1:npts)=id2
|
||||
call four2a(cx,NFFT1,1,-1,1)
|
||||
cx=cshift(cx,ishift)
|
||||
cx(1)=0.5*cx(1)
|
||||
cx(2*i46p875+1:)=cmplx(0.0,0.0)
|
||||
call four2a(cx,NFFT2,1,1,1)
|
||||
cdat(1:npts/32)=cx(0:npts/32-1)/NFFT1
|
||||
return
|
||||
|
||||
end subroutine msksddc
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
// chrono_io
|
||||
//
|
||||
// (C) Copyright Howard Hinnant
|
||||
// (C) Copyright 2010-2011 Vicente J. Botet Escriba
|
||||
// Use, modification and distribution are subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// This code was adapted by Vicente from Howard Hinnant's experimental work
|
||||
// on chrono i/o under lvm/libc++ to Boost
|
||||
|
||||
#ifndef BOOST_CHRONO_CHRONO_IO_HPP
|
||||
#define BOOST_CHRONO_CHRONO_IO_HPP
|
||||
|
||||
#include <boost/chrono/config.hpp>
|
||||
|
||||
//#if BOOST_CHRONO_VERSION == 2
|
||||
//#include <boost/chrono/io/time_point_io.hpp>
|
||||
//#include <boost/chrono/io/duration_io.hpp>
|
||||
//#elif BOOST_CHRONO_VERSION == 1
|
||||
//#include <boost/chrono/io_v1/chrono_io.hpp>
|
||||
//#endif
|
||||
|
||||
#if defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0
|
||||
#include <boost/chrono/io/time_point_io.hpp>
|
||||
#include <boost/chrono/io/duration_io.hpp>
|
||||
#else
|
||||
#include <boost/chrono/io_v1/chrono_io.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/chrono/io/utility/to_string.hpp>
|
||||
|
||||
#endif // BOOST_CHRONO_CHRONO_IO_HPP
|
||||
@@ -0,0 +1,354 @@
|
||||
// boost process_cpu_clocks.cpp -----------------------------------------------------------//
|
||||
|
||||
// Copyright Beman Dawes 1994, 2006, 2008
|
||||
// Copyright Vicente J. Botet Escriba 2009
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// See http://www.boost.org/libs/chrono for documentation.
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
#include <boost/chrono/config.hpp>
|
||||
#include <boost/chrono/process_cpu_clocks.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <sys/times.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h> // for clock_gettime
|
||||
|
||||
|
||||
namespace boost { namespace chrono {
|
||||
namespace chrono_detail
|
||||
{
|
||||
inline nanoseconds::rep tick_factor() // multiplier to convert ticks
|
||||
// to nanoseconds; -1 if unknown
|
||||
{
|
||||
long factor = 0;
|
||||
if ( !factor )
|
||||
{
|
||||
if ( (factor = ::sysconf( _SC_CLK_TCK )) <= 0 )
|
||||
factor = -1;
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT( factor <= 1000000000l ); // doesn't handle large ticks
|
||||
factor = 1000000000l / factor; // compute factor
|
||||
if ( !factor ) factor = -1;
|
||||
}
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
|
||||
process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT
|
||||
{
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( chrono_detail::tick_factor() != -1 )
|
||||
{
|
||||
return time_point(
|
||||
nanoseconds(c*chrono_detail::tick_factor()));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
}
|
||||
return time_point();
|
||||
}
|
||||
|
||||
#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
|
||||
process_real_cpu_clock::time_point process_real_cpu_clock::now(
|
||||
system::error_code & ec)
|
||||
{
|
||||
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_real_cpu_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( chrono_detail::tick_factor() != -1 )
|
||||
{
|
||||
if (!BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
ec.clear();
|
||||
}
|
||||
return time_point(
|
||||
nanoseconds(c*chrono_detail::tick_factor()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_real_cpu_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT
|
||||
{
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( chrono_detail::tick_factor() != -1 )
|
||||
{
|
||||
return time_point(
|
||||
nanoseconds((tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor()));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
}
|
||||
return time_point();
|
||||
}
|
||||
|
||||
#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
|
||||
process_user_cpu_clock::time_point process_user_cpu_clock::now(
|
||||
system::error_code & ec)
|
||||
{
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_user_cpu_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( chrono_detail::tick_factor() != -1 )
|
||||
{
|
||||
if (!BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
ec.clear();
|
||||
}
|
||||
return time_point(
|
||||
nanoseconds((tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_user_cpu_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT
|
||||
{
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
return time_point();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( chrono_detail::tick_factor() != -1 )
|
||||
{
|
||||
return time_point(
|
||||
nanoseconds((tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor()));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
|
||||
process_system_cpu_clock::time_point process_system_cpu_clock::now(
|
||||
system::error_code & ec)
|
||||
{
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_system_cpu_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( chrono_detail::tick_factor() != -1 )
|
||||
{
|
||||
if (!BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
ec.clear();
|
||||
}
|
||||
return time_point(
|
||||
nanoseconds((tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_system_cpu_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
process_cpu_clock::time_point process_cpu_clock::now() BOOST_NOEXCEPT
|
||||
{
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
else
|
||||
{
|
||||
nanoseconds::rep factor = chrono_detail::tick_factor();
|
||||
if ( factor != -1 )
|
||||
{
|
||||
time_point::rep r(
|
||||
c*factor,
|
||||
(tm.tms_utime + tm.tms_cutime)*factor,
|
||||
(tm.tms_stime + tm.tms_cstime)*factor);
|
||||
return time_point(duration(r));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
}
|
||||
return time_point();
|
||||
}
|
||||
|
||||
#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
|
||||
process_cpu_clock::time_point process_cpu_clock::now(
|
||||
system::error_code & ec )
|
||||
{
|
||||
tms tm;
|
||||
clock_t c = ::times( &tm );
|
||||
if ( c == clock_t(-1) ) // error
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( chrono_detail::tick_factor() != -1 )
|
||||
{
|
||||
time_point::rep r(
|
||||
c*chrono_detail::tick_factor(),
|
||||
(tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor(),
|
||||
(tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor());
|
||||
return time_point(duration(r));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BOOST_CHRONO_IS_THROWS(ec))
|
||||
{
|
||||
boost::throw_exception(
|
||||
system::system_error(
|
||||
errno,
|
||||
BOOST_CHRONO_SYSTEM_CATEGORY,
|
||||
"chrono::process_clock" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
|
||||
return time_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
} }
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef DATE_TIME_PARSE_FORMAT_BASE__
|
||||
#define DATE_TIME_PARSE_FORMAT_BASE__
|
||||
|
||||
/* Copyright (c) 2002,2003 CrystalClear Software, Inc.
|
||||
* Use, modification and distribution is subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
* Author: Jeff Garland
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace date_time {
|
||||
|
||||
//! Enum for distinguishing parsing and formatting options
|
||||
enum month_format_spec {month_as_integer, month_as_short_string,
|
||||
month_as_long_string};
|
||||
|
||||
//! Enum for distinguishing the order of Month, Day, & Year.
|
||||
/*! Enum for distinguishing the order in which Month, Day, & Year
|
||||
* will appear in a date string */
|
||||
enum ymd_order_spec {ymd_order_iso, //order is year-month-day
|
||||
ymd_order_dmy, //day-month-year
|
||||
ymd_order_us}; //order is month-day-year
|
||||
|
||||
|
||||
} }//namespace date_time
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,278 @@
|
||||
#include "astro.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QSettings>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "commons.h"
|
||||
#include "MessageBox.hpp"
|
||||
#include "Configuration.hpp"
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
#include "ui_astro.h"
|
||||
#include "moc_astro.cpp"
|
||||
|
||||
|
||||
extern "C" {
|
||||
void astrosub_(int* nyear, int* month, int* nday, double* uth, double* freqMoon,
|
||||
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, double* techo, double* width1, double* width2,
|
||||
bool* bTx, const char* AzElFileName, const char* jpleph,
|
||||
int len1, int len2, int len3, int len4);
|
||||
}
|
||||
|
||||
Astro::Astro(QSettings * settings, Configuration const * configuration, QWidget * parent)
|
||||
: QDialog {parent, Qt::WindowTitleHint}
|
||||
, settings_ {settings}
|
||||
, configuration_ {configuration}
|
||||
, ui_ {new Ui::Astro}
|
||||
, m_DopplerMethod {0}
|
||||
{
|
||||
ui_->setupUi (this);
|
||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Astronomical Data"));
|
||||
setStyleSheet ("QWidget {background: white;}");
|
||||
connect (ui_->cbDopplerTracking, &QAbstractButton::toggled, ui_->doppler_widget, &QWidget::setVisible);
|
||||
read_settings ();
|
||||
ui_->text_label->clear ();
|
||||
}
|
||||
|
||||
Astro::~Astro ()
|
||||
{
|
||||
ui_->cbDopplerTracking->setChecked (false);
|
||||
Q_EMIT tracking_update ();
|
||||
if (isVisible ()) write_settings ();
|
||||
}
|
||||
|
||||
void Astro::closeEvent (QCloseEvent * e)
|
||||
{
|
||||
write_settings ();
|
||||
QWidget::closeEvent (e);
|
||||
}
|
||||
|
||||
void Astro::read_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
ui_->doppler_widget->setVisible (ui_->cbDopplerTracking->isChecked ());
|
||||
m_DopplerMethod=settings_->value("DopplerMethod",0).toInt();
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 0: ui_->rbNoDoppler->setChecked (true); break;
|
||||
case 1: ui_->rbFullTrack->setChecked (true); break;
|
||||
case 2: ui_->rbConstFreqOnMoon->setChecked (true); break;
|
||||
case 3: ui_->rbRxOnly->setChecked (true); break;
|
||||
}
|
||||
move (settings_->value ("window/pos", pos ()).toPoint ());
|
||||
}
|
||||
|
||||
void Astro::write_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
//settings_->setValue ("DopplerTracking", ui_->cbDopplerTracking->isChecked ());
|
||||
settings_->setValue ("DopplerMethod",m_DopplerMethod);
|
||||
settings_->setValue ("window/pos", pos ());
|
||||
}
|
||||
|
||||
auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency freq,
|
||||
bool dx_is_self, bool bTx, bool no_tx_QSY, int TR_period) -> Correction
|
||||
{
|
||||
Frequency freq_moon {freq};
|
||||
double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx;
|
||||
double ramoon,decmoon,dgrd,poloffset,xnr,techo,width1,width2;
|
||||
int ntsky;
|
||||
QString date {t.date().toString("yyyy MMM dd").trimmed ()};
|
||||
QString utc {t.time().toString().trimmed ()};
|
||||
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()};
|
||||
double uth {nhr + nmin/60.0 + sec/3600.0};
|
||||
if(freq_moon < 1) freq_moon = 144000000;
|
||||
int nfreq {static_cast<int> (freq_moon / 1000000u)};
|
||||
double freq8 {static_cast<double> (freq_moon)};
|
||||
auto const& AzElFileName = QDir::toNativeSeparators (configuration_->azel_directory ().absoluteFilePath ("azel.dat"));
|
||||
auto const& jpleph = configuration_->data_dir ().absoluteFilePath ("JPLEPH");
|
||||
int ndop;
|
||||
int ndop00;
|
||||
|
||||
QString mygrid_padded {(mygrid + " ").left (6)};
|
||||
QString hisgrid_padded {(hisgrid + " ").left (6)};
|
||||
astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(),
|
||||
hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon,
|
||||
&azmoondx, &elmoondx, &ntsky, &ndop, &ndop00, &ramoon, &decmoon,
|
||||
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
|
||||
AzElFileName.toLatin1().constData(), jpleph.toLatin1().constData(), 6, 6,
|
||||
AzElFileName.length(), jpleph.length());
|
||||
|
||||
if(hisgrid_padded==" ") {
|
||||
azmoondx=0.0;
|
||||
elmoondx=0.0;
|
||||
ndop=0;
|
||||
width2=0.0;
|
||||
}
|
||||
QString message;
|
||||
{
|
||||
QTextStream out {&message};
|
||||
out << " " << date << "\n"
|
||||
"UTC: " << utc << "\n"
|
||||
<< fixed
|
||||
<< qSetFieldWidth (6)
|
||||
<< qSetRealNumberPrecision (1)
|
||||
<< "Az: " << azmoon << "\n"
|
||||
"El: " << elmoon << "\n"
|
||||
"SelfDop:" << ndop00 << "\n"
|
||||
"Width: " << int(width1) << "\n"
|
||||
<< qSetRealNumberPrecision (2)
|
||||
<< "Delay: " << techo << "\n"
|
||||
<< qSetRealNumberPrecision (1)
|
||||
<< "DxAz: " << azmoondx << "\n"
|
||||
"DxEl: " << elmoondx << "\n"
|
||||
"DxDop: " << ndop << "\n"
|
||||
"DxWid: " << int(width2) << "\n"
|
||||
"Dec: " << decmoon << "\n"
|
||||
"SunAz: " << azsun << "\n"
|
||||
"SunEl: " << elsun << "\n"
|
||||
"Freq: " << nfreq << "\n";
|
||||
if(nfreq>=50) { //Suppress data not relevant below VHF
|
||||
out << "Tsky: " << ntsky << "\n"
|
||||
"Dpol: " << poloffset << "\n"
|
||||
"MNR: " << xnr << "\n"
|
||||
"Dgrd: " << dgrd;
|
||||
}
|
||||
}
|
||||
ui_->text_label->setText(message);
|
||||
|
||||
Correction correction;
|
||||
if (ui_->cbDopplerTracking->isChecked ()) {
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1: // All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
case 3: // Both stations do full correction on Rx and none on Tx
|
||||
correction.rx = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
correction.rx = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (3 != m_DopplerMethod) correction.tx = -correction.rx;
|
||||
if(dx_is_self && m_DopplerMethod == 1) correction.rx = 0;
|
||||
|
||||
if (no_tx_QSY && 3 != m_DopplerMethod && 0 != m_DopplerMethod)
|
||||
{
|
||||
// calculate a single correction for transmit half way through
|
||||
// the period as a compromise for rigs that can't CAT QSY
|
||||
// while transmitting
|
||||
//
|
||||
// use a base time of (secs-since-epoch + 2) so as to be sure
|
||||
// we do the next period if we calculate just before it starts
|
||||
auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2;
|
||||
auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2;
|
||||
auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000);
|
||||
QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()};
|
||||
QString utc {target_date_time.time().toString().trimmed ()};
|
||||
int nyear {target_date_time.date().year()};
|
||||
int month {target_date_time.date().month()};
|
||||
int nday {target_date_time.date().day()};
|
||||
int nhr {target_date_time.time().hour()};
|
||||
int nmin {target_date_time.time().minute()};
|
||||
double sec {target_date_time.time().second() + 0.001*target_date_time.time().msec()};
|
||||
double uth {nhr + nmin/60.0 + sec/3600.0};
|
||||
astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(),
|
||||
hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon,
|
||||
&azmoondx, &elmoondx, &ntsky, &ndop, &ndop00, &ramoon, &decmoon,
|
||||
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
|
||||
"", jpleph.toLatin1().constData(), 6, 6,
|
||||
0, jpleph.length());
|
||||
FrequencyDelta offset {0};
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1:
|
||||
// All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
offset = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
offset = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
correction.tx = -offset;
|
||||
}
|
||||
}
|
||||
return correction;
|
||||
}
|
||||
|
||||
void Astro::check_split ()
|
||||
{
|
||||
if (doppler_tracking () && !configuration_->split_mode ())
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Doppler Tracking Error"),
|
||||
tr ("Split operating is required for Doppler tracking"),
|
||||
tr ("Go to \"Menu->File->Settings->Radio\" to enable split operation"));
|
||||
ui_->rbNoDoppler->click ();
|
||||
}
|
||||
}
|
||||
|
||||
void Astro::on_rbFullTrack_clicked()
|
||||
{
|
||||
m_DopplerMethod = 1;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbRxOnly_clicked()
|
||||
{
|
||||
m_DopplerMethod = 3;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbConstFreqOnMoon_clicked()
|
||||
{
|
||||
m_DopplerMethod = 2;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbNoDoppler_clicked()
|
||||
{
|
||||
m_DopplerMethod = 0;
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
bool Astro::doppler_tracking () const
|
||||
{
|
||||
return ui_->cbDopplerTracking->isChecked () && m_DopplerMethod;
|
||||
}
|
||||
|
||||
void Astro::on_cbDopplerTracking_toggled(bool)
|
||||
{
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::nominal_frequency (Frequency rx, Frequency tx)
|
||||
{
|
||||
ui_->sked_frequency_label->setText (Radio::pretty_frequency_MHz_string (rx));
|
||||
ui_->sked_tx_frequency_label->setText (Radio::pretty_frequency_MHz_string (tx));
|
||||
}
|
||||
|
||||
void Astro::hideEvent (QHideEvent * e)
|
||||
{
|
||||
Q_EMIT tracking_update ();
|
||||
QWidget::hideEvent (e);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 1998-2003 Joel de Guzman
|
||||
Copyright (c) 2001 Daniel Nuffer
|
||||
Copyright (c) 2002 Hartmut Kaiser
|
||||
http://spirit.sourceforge.net/
|
||||
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
=============================================================================*/
|
||||
#if !defined(BOOST_SPIRIT_LIST_IPP)
|
||||
#define BOOST_SPIRIT_LIST_IPP
|
||||
|
||||
namespace boost { namespace spirit {
|
||||
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// operator% is defined as:
|
||||
// a % b ---> a >> *(b >> a)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename A, typename B>
|
||||
inline sequence<A, kleene_star<sequence<B, A> > >
|
||||
operator%(parser<A> const& a, parser<B> const& b)
|
||||
{
|
||||
return a.derived() >> *(b.derived() >> a.derived());
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
inline sequence<A, kleene_star<sequence<chlit<char>, A> > >
|
||||
operator%(parser<A> const& a, char b)
|
||||
{
|
||||
return a.derived() >> *(b >> a.derived());
|
||||
}
|
||||
|
||||
template <typename B>
|
||||
inline sequence<chlit<char>, kleene_star<sequence<B, chlit<char> > > >
|
||||
operator%(char a, parser<B> const& b)
|
||||
{
|
||||
return a >> *(b.derived() >> a);
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
inline sequence<A, kleene_star<sequence<strlit<char const*>, A> > >
|
||||
operator%(parser<A> const& a, char const* b)
|
||||
{
|
||||
return a.derived() >> *(b >> a.derived());
|
||||
}
|
||||
|
||||
template <typename B>
|
||||
inline sequence<strlit<char const*>,
|
||||
kleene_star<sequence<B, strlit<char const*> > > >
|
||||
operator%(char const* a, parser<B> const& b)
|
||||
{
|
||||
return a >> *(b.derived() >> a);
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
inline sequence<A, kleene_star<sequence<chlit<wchar_t>, A> > >
|
||||
operator%(parser<A> const& a, wchar_t b)
|
||||
{
|
||||
return a.derived() >> *(b >> a.derived());
|
||||
}
|
||||
|
||||
template <typename B>
|
||||
inline sequence<chlit<wchar_t>, kleene_star<sequence<B, chlit<wchar_t> > > >
|
||||
operator%(wchar_t a, parser<B> const& b)
|
||||
{
|
||||
return a >> *(b.derived() >> a);
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
inline sequence<A, kleene_star<sequence<strlit<wchar_t const*>, A> > >
|
||||
operator%(parser<A> const& a, wchar_t const* b)
|
||||
{
|
||||
return a.derived() >> *(b >> a.derived());
|
||||
}
|
||||
|
||||
template <typename B>
|
||||
inline sequence<strlit<wchar_t const*>,
|
||||
kleene_star<sequence<B, strlit<wchar_t const*> > > >
|
||||
operator%(wchar_t const* a, parser<B> const& b)
|
||||
{
|
||||
return a >> *(b.derived() >> a);
|
||||
}
|
||||
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||
|
||||
}} // namespace boost::spirit
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
#ifndef BOOST_MPL_LIST_LIST10_HPP_INCLUDED
|
||||
#define BOOST_MPL_LIST_LIST10_HPP_INCLUDED
|
||||
|
||||
// Copyright Aleksey Gurtovoy 2000-2004
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/mpl for documentation.
|
||||
|
||||
// $Id$
|
||||
// $Date$
|
||||
// $Revision$
|
||||
|
||||
#if !defined(BOOST_MPL_PREPROCESSING_MODE)
|
||||
# include <boost/mpl/list/list0.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/mpl/aux_/config/use_preprocessed.hpp>
|
||||
|
||||
#if !defined(BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS) \
|
||||
&& !defined(BOOST_MPL_PREPROCESSING_MODE)
|
||||
|
||||
# define BOOST_MPL_PREPROCESSED_HEADER list10.hpp
|
||||
# include <boost/mpl/list/aux_/include_preprocessed.hpp>
|
||||
|
||||
#else
|
||||
|
||||
# include <boost/preprocessor/iterate.hpp>
|
||||
|
||||
namespace boost { namespace mpl {
|
||||
|
||||
# define BOOST_PP_ITERATION_PARAMS_1 \
|
||||
(3,(1, 10, <boost/mpl/list/aux_/numbered.hpp>))
|
||||
# include BOOST_PP_ITERATE()
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
|
||||
|
||||
#endif // BOOST_MPL_LIST_LIST10_HPP_INCLUDED
|
||||
@@ -0,0 +1,40 @@
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// See http://boostorg.github.com/compute for more information.
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
#ifndef BOOST_COMPUTE_ALGORITHM_ANY_OF_HPP
|
||||
#define BOOST_COMPUTE_ALGORITHM_ANY_OF_HPP
|
||||
|
||||
#include <boost/compute/system.hpp>
|
||||
#include <boost/compute/algorithm/find_if.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace compute {
|
||||
|
||||
/// Returns \c true if \p predicate returns \c true for any of the elements in
|
||||
/// the range [\p first, \p last).
|
||||
///
|
||||
/// For example, to test if a vector contains any negative values:
|
||||
///
|
||||
/// \snippet test/test_any_all_none_of.cpp any_of
|
||||
///
|
||||
/// \see all_of(), none_of()
|
||||
template<class InputIterator, class UnaryPredicate>
|
||||
inline bool any_of(InputIterator first,
|
||||
InputIterator last,
|
||||
UnaryPredicate predicate,
|
||||
command_queue &queue = system::default_queue())
|
||||
{
|
||||
return ::boost::compute::find_if(first, last, predicate, queue) != last;
|
||||
}
|
||||
|
||||
} // end compute namespace
|
||||
} // end boost namespace
|
||||
|
||||
#endif // BOOST_COMPUTE_ALGORITHM_ANY_OF_HPP
|
||||
@@ -0,0 +1,49 @@
|
||||
// (C) Copyright 2009-2011 Frederic Bron.
|
||||
//
|
||||
// Use, modification and distribution are subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// See http://www.boost.org/libs/type_traits for most recent version including documentation.
|
||||
|
||||
#ifndef BOOST_TT_HAS_LEFT_SHIFT_HPP_INCLUDED
|
||||
#define BOOST_TT_HAS_LEFT_SHIFT_HPP_INCLUDED
|
||||
|
||||
#define BOOST_TT_TRAIT_NAME has_left_shift
|
||||
#define BOOST_TT_TRAIT_OP <<
|
||||
#define BOOST_TT_FORBIDDEN_IF\
|
||||
(\
|
||||
/* Lhs==fundamental and Rhs==fundamental and (Lhs!=integral or Rhs!=integral) */\
|
||||
(\
|
||||
::boost::is_fundamental< Lhs_nocv >::value && \
|
||||
::boost::is_fundamental< Rhs_nocv >::value && \
|
||||
( \
|
||||
(! ::boost::is_integral< Lhs_noref >::value ) || \
|
||||
(! ::boost::is_integral< Rhs_noref >::value )\
|
||||
)\
|
||||
)||\
|
||||
/* Lhs==fundamental and Rhs==pointer */\
|
||||
(\
|
||||
::boost::is_fundamental< Lhs_nocv >::value && \
|
||||
::boost::is_pointer< Rhs_noref >::value\
|
||||
)||\
|
||||
/* Rhs==fundamental and Lhs==pointer */\
|
||||
(\
|
||||
::boost::is_fundamental< Rhs_nocv >::value && \
|
||||
::boost::is_pointer< Lhs_noref >::value\
|
||||
)||\
|
||||
/* Lhs==pointer and Rhs==pointer */\
|
||||
(\
|
||||
::boost::is_pointer< Lhs_noref >::value && \
|
||||
::boost::is_pointer< Rhs_noref >::value\
|
||||
)\
|
||||
)
|
||||
|
||||
|
||||
#include <boost/type_traits/detail/has_binary_operator.hpp>
|
||||
|
||||
#undef BOOST_TT_TRAIT_NAME
|
||||
#undef BOOST_TT_TRAIT_OP
|
||||
#undef BOOST_TT_FORBIDDEN_IF
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2011 Joel de Guzman
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
==============================================================================*/
|
||||
#if !defined(FUSION_POP_BACK_10022005_1801)
|
||||
#define FUSION_POP_BACK_10022005_1801
|
||||
|
||||
#include <boost/fusion/support/config.hpp>
|
||||
#include <boost/mpl/pop_back.hpp>
|
||||
#include <boost/fusion/support/tag_of.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/pop_back.hpp>
|
||||
#include <boost/fusion/sequence/convert.hpp>
|
||||
|
||||
namespace boost { namespace mpl
|
||||
{
|
||||
template <typename Tag>
|
||||
struct pop_back_impl;
|
||||
|
||||
template <>
|
||||
struct pop_back_impl<fusion::fusion_sequence_tag>
|
||||
{
|
||||
template <typename Sequence>
|
||||
struct apply
|
||||
{
|
||||
typedef typename
|
||||
fusion::result_of::pop_back<Sequence>::type
|
||||
result;
|
||||
|
||||
typedef typename
|
||||
fusion::result_of::convert<
|
||||
typename fusion::detail::tag_of<Sequence>::type, result>::type
|
||||
type;
|
||||
};
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 1999-2003 Jaakko Jarvi
|
||||
Copyright (c) 2001-2011 Joel de Guzman
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
==============================================================================*/
|
||||
#if !defined(FUSION_NOT_EQUAL_TO_05052005_1141)
|
||||
#define FUSION_NOT_EQUAL_TO_05052005_1141
|
||||
|
||||
#include <boost/fusion/support/config.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/fusion/iterator/deref.hpp>
|
||||
#include <boost/fusion/iterator/next.hpp>
|
||||
#include <boost/fusion/iterator/equal_to.hpp>
|
||||
#include <boost/fusion/support/as_const.hpp>
|
||||
|
||||
namespace boost { namespace fusion { namespace detail
|
||||
{
|
||||
template <typename Seq1, typename Seq2, bool same_size>
|
||||
struct sequence_not_equal_to
|
||||
{
|
||||
typedef typename result_of::end<Seq1>::type end1_type;
|
||||
typedef typename result_of::end<Seq2>::type end2_type;
|
||||
|
||||
template <typename I1, typename I2>
|
||||
BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
|
||||
static bool
|
||||
call(I1 const&, I2 const&, mpl::true_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename I1, typename I2>
|
||||
BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
|
||||
static bool
|
||||
call(I1 const& a, I2 const& b, mpl::false_)
|
||||
{
|
||||
return extension::as_const(*a) != extension::as_const(*b)
|
||||
|| call(fusion::next(a), fusion::next(b));
|
||||
}
|
||||
|
||||
template <typename I1, typename I2>
|
||||
BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
|
||||
static bool
|
||||
call(I1 const& a, I2 const& b)
|
||||
{
|
||||
typename result_of::equal_to<I1, end1_type>::type eq;
|
||||
return call(a, b, eq);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Seq1, typename Seq2>
|
||||
struct sequence_not_equal_to<Seq1, Seq2, false>
|
||||
{
|
||||
template <typename I1, typename I2>
|
||||
BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
|
||||
static bool
|
||||
call(I1 const& a, I2 const& b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user