#include "specwidget.h"
#include "ui_specwidget.h"
#include "qtgui/bookmarks.h"
#include <QSettings>
#include <QDir>
#include <QDateTime>
#include <QFileInfo>
#include <QFileDialog>
specWidget::specWidget(QWidget *parent) :
	QWidget(parent),
	ui(new Ui::specWidget),
	m_pDevMod(new QStandardItemModel(this)),
	m_attenMod(new QStandardItemModel(this)),
	m_attenTxMod(new QStandardItemModel(this)),
	m_pModRXGain(new QStandardItemModel(this)),
	m_pModTXGain(new QStandardItemModel(this)),
	m_rxth(new uhd_io_thread(this)),
	m_saveth(new uhd_io_thread(this)),
	m_txth(new uhd_io_thread(this)),
	m_readth(new uhd_io_thread(this)),
	m_bSaveToFile(false),
	watcher(new stdout_watcher(this))
{
	ui->setupUi(this);
	Bookmarks::create();
	enumDevices();
	ui->combox_dev->setModel(m_pDevMod);

	ui->plotter->setFftFill(false);
	ui->plotter->setPeakHold(true);
	ui->plotter->setFftPlotColor(QColor(255,255,255));
	ui->plotter->setRunningState(true);
	ui->plotter->setFreqUnits(1000000);//MHz

	//选择带宽
	ui->plotter->setFilterBoxEnabled(true);


	ui->plotter->setTooltipsEnabled(true);
	ui->plotter->setPeakDetection(false,128.0);

	m_attenMod->appendRow(new QStandardItem("TX/RX"));
	m_attenMod->appendRow(new QStandardItem("RX2"));
	ui->comboBox_rx_gainNames->setModel(m_pModRXGain);
	ui->comboBox_tx_gainNames->setModel(m_pModTXGain);
	ui->comboBox_atn->setModel(m_attenMod);
	ui->comboBox_atn_tx->setModel(m_attenTxMod);

	//连接
	//connect (ui->plotter,&CPlotter::newDemodFreq,ui->freqCtrl,&CFreqCtrl::setFrequency);
	connect (ui->plotter,&CPlotter::newDemodFreq,this, &specWidget::slot_newDemodFreq);
	connect (ui->freqCtrl,&CFreqCtrl::newFrequency,this, &specWidget::setCenterFreq);
	connect (watcher,&stdout_watcher::evt_stdata,this,&specWidget::slot_msg,Qt::QueuedConnection);
	connect (ui->plotter,&CPlotter::pandapterRangeChanged,this,&specWidget::slot_YAxisRangeChanged);
	loadSettings();
	watcher->start();
}

specWidget::~specWidget()
{
	disconnect_usrp();
	watcher->stop_and_wait();
	delete ui;
}

void specWidget::slot_newDemodFreq(qint64 freq, qint64 delta)/* delta is the offset from the center */
{
	qint64 offfreq = freq - ui->plotter->getCenterFreq();
	if (ui->plotter->getSpanFreq()==0)
		return;
	double ratio = offfreq *1.0/ ui->plotter->getSpanFreq() + 0.5;

	int v = m_nFFTSize * ratio + .5;
	if (v<0) v = 0;

	if (v>=m_nFFTSize)
		v = m_nFFTSize - 1;
	m_nCurrentCenter = v;

}
void specWidget::update_Info()
{
	if (!usrp)
		return;
	m_pModRXGain->clear();
	m_pModTXGain->clear();
	m_attenTxMod->clear();
	m_attenMod->clear();
	std::vector<std::string> vec_rg = get_rx_gain_names();
	std::vector<std::string> vec_tg = get_tx_gain_names();
	std::vector<std::string> vec_ar = get_rx_atns();
	std::vector<std::string> vec_at = get_tx_atns();
	foreach(std::string g, vec_rg)
	{
		m_pModRXGain->appendRow(new QStandardItem(g.c_str()));
	}
	foreach(std::string g, vec_tg)
	{
		m_pModTXGain->appendRow(new QStandardItem(g.c_str()));
	}
	foreach(std::string g, vec_ar)
	{
		m_attenMod->appendRow(new QStandardItem(g.c_str()));
	}
	foreach(std::string g, vec_at)
	{
		m_attenTxMod->appendRow(new QStandardItem(g.c_str()));
	}
}
void specWidget::slot_msg(QByteArray s, bool bStdErr)
{
	ui->plainTextEdit_msg->appendPlainText(
				(bStdErr?"STDERR>":"STDIO>") +
				QString::fromUtf8(s));
}

void specWidget::setCenterFreq(quint64 f){
	if (f<=0)
		return;
	f = set_rx_freq(f);
	ui->plotter->setCenterFreq(f);
	if (ui->doubleSpinBox_center->value() * 1e6 !=ui->freqCtrl->getFrequency())
		ui->doubleSpinBox_center->setValue(ui->freqCtrl->getFrequency()/1e6);
	//ui->plotter->setCenterFreq(f);
}

void specWidget::setRxRate(double rate){
	rate = set_rx_rate(rate);
	ui->plotter->setSampleRate(rate);
}


void specWidget::slot_YAxisRangeChanged(double minv, double maxv)
{
	double v1 = ui->doubleSpinBox_range_min->value();
	double v2 = ui->doubleSpinBox_range_max->value();
	if (minv!=v1)
		ui->doubleSpinBox_range_min->setValue(minv);
	if (maxv!=v2)
		ui->doubleSpinBox_range_max->setValue(maxv);
}

void specWidget::connect_usrp()
{
	disconnect_usrp();
#ifdef Q_OS_WIN
	m_dev_args = ui->combox_dev->lineEdit()->text().toLocal8Bit().toStdString();
#else
	m_dev_args = ui->combox_dev->lineEdit()->text().toStdString();
#endif
	initFFTW();
	if (!usrp)
		open_device();
	if (!usrp)
	{
		ui->pushButton_connect->setChecked(false);
		return;
	}
	int updateIntelv = 1000.0 /ui->spinBox_fftUpdate->value() + .5;
	m_nTimerID = startTimer(updateIntelv);
	update_Info();
	ui->combox_dev->setEnabled(false);
	ui->spinBox_fftUpdate->setEnabled(false);
	ui->checkBox_rx->setEnabled(true);
	ui->checkBox_tx->setEnabled(true);
}
void specWidget::enumDevices()
{
	uhd_string_vector_handle stringv;
	uhd_string_vector_make(&stringv);
	uhd_usrp_find("",&stringv);
	size_t szStrings = 0;
	uhd_string_vector_size(stringv, &szStrings);
	char * bufo = new char [1024*1024*16]{0};
	m_pDevMod->removeRows(0,m_pDevMod->rowCount());
	for (int i=0;i<szStrings;++i)
	{
		uhd_string_vector_at(stringv,i,bufo,1024*1024*16);
#ifdef Q_OS_WIN
		m_pDevMod->appendRow(new QStandardItem(QString::fromLocal8Bit(bufo)));
#else
		m_pDevMod->appendRow(new QStandardItem(QString::fromUtf8(bufo)));
#endif
	}
	uhd_string_vector_free(&stringv);
}

void specWidget::disconnect_usrp()
{
	do_tx(false);
	do_rx(false);
	freeFFTW();
	if (usrp)
		close_device();
	if (m_nTimerID>=0)
	{
		killTimer(m_nTimerID);
		m_nTimerID = -1;
	}

	ui->combox_dev->setEnabled(true);
	ui->spinBox_fftUpdate->setEnabled(true);
	ui->checkBox_rx->setEnabled(false);
	ui->checkBox_tx->setEnabled(false);
}

void specWidget::loadSettings()
{
	QSettings settings(QCoreApplication::applicationFilePath()+".ini", QSettings::IniFormat);
	const QString combox_dev = settings.value("spectrum/combox_dev","").toString();
	ui->combox_dev->setEditText(combox_dev);

	const double doubleSpinBox_spr = settings.value("spectrum/doubleSpinBox_spr",10).toDouble();
	ui->doubleSpinBox_spr->setValue(doubleSpinBox_spr);
	//Sample Rate
	ui->plotter->setSampleRate(doubleSpinBox_spr*1000000);

	const double doubleSpinBox_center = settings.value("spectrum/doubleSpinBox_center",0).toDouble();
	ui->doubleSpinBox_center->setValue(doubleSpinBox_center);
	//中心频率
	ui->plotter->setCenterFreq(doubleSpinBox_center * 1000000);
	//选择频率
	ui->plotter->setDemodCenterFreq(doubleSpinBox_center*1000000);
	ui->plotter->setHiLowCutFrequencies(-1000000,1000000);

	ui->plotter->setSpanFreq(doubleSpinBox_spr*1000000);
	//选择带宽
	ui->plotter->setMaxBandiwdth(doubleSpinBox_spr*1000000);

	const int spinBox_fftUpdate = settings.value("spectrum/spinBox_fftUpdate",20).toInt();
	ui->spinBox_fftUpdate->setValue(spinBox_fftUpdate);

	const int comboBox_fftSize = settings.value("spectrum/comboBox_fftSize",6).toInt();
	ui->comboBox_fftSize->setCurrentIndex(comboBox_fftSize);

	const bool checkBox_rxagc = settings.value("spectrum/checkBox_rxagc",true).toBool();
	ui->checkBox_rxagc->setChecked(checkBox_rxagc);

	m_nFFTSize = (1<<comboBox_fftSize) * 128;
	if (m_nFFTSize>65536)
		m_nFFTSize = 65536;
	if (m_nFFTSize<128)
		m_nFFTSize = 128;

	const int comboBox_atn = settings.value("spectrum/comboBox_atn",0).toInt();
	ui->comboBox_atn->setCurrentIndex(comboBox_atn);

	const int spinBox_chan = settings.value("spectrum/spinBox_chan",0).toInt();
	ui->spinBox_chan->setValue(spinBox_chan);

	const int spinBox_gain = settings.value("spectrum/spinBox_gain",0).toInt();
	ui->spinBox_gain->setValue(spinBox_gain);

	const int spinBox_bw = settings.value("spectrum/spinBox_bw",0).toInt();
	ui->spinBox_bw->setValue(spinBox_bw);


	const double doubleSpinBox_range_max = settings.value("spectrum/doubleSpinBox_range_max",0).toInt();
	ui->doubleSpinBox_range_max->setValue(doubleSpinBox_range_max);

	const double doubleSpinBox_range_min = settings.value("spectrum/doubleSpinBox_range_min",-150).toInt();
	ui->doubleSpinBox_range_min->setValue(doubleSpinBox_range_min);

	const QString lineEdit_folder = settings.value("spectrum/lineEdit_folder","./").toString();
	ui->lineEdit_folder->setText(lineEdit_folder);

	const QString lineEdit_folder_play = settings.value("spectrum/lineEdit_folder_play","./").toString();
	ui->lineEdit_folder_play->setText(lineEdit_folder_play);

	const double doubleSpinBox_center_tx = settings.value("tx/doubleSpinBox_center_tx",1200).toDouble();
	ui->doubleSpinBox_center_tx->setValue(doubleSpinBox_center_tx);

	const int spinBox_chan_tx = settings.value("tx/spinBox_chan_tx",0).toInt();
	ui->spinBox_chan_tx->setValue(spinBox_chan_tx);

	const int spinBox_gain_tx = settings.value("tx/spinBox_gain_tx",0).toInt();
	ui->spinBox_gain_tx->setValue(spinBox_gain_tx);

	const int spinBox_bw_tx = settings.value("tx/spinBox_bw_tx",0).toInt();
	ui->spinBox_bw_tx->setValue(spinBox_bw_tx);

	const double doubleSpinBox_spr_tx = settings.value("tx/doubleSpinBox_spr_tx",10).toDouble();
	ui->doubleSpinBox_spr_tx->setValue(doubleSpinBox_spr_tx);

	const int spinBox_ui_maxheight = settings.value("ui/spinBox_ui_maxheight",1080).toInt();
	ui->spinBox_ui_maxheight->setValue(spinBox_ui_maxheight);

	const int spinBox_ui_maxwidth = settings.value("ui/spinBox_ui_maxwidth",1920).toInt();
	ui->spinBox_ui_maxwidth->setValue(spinBox_ui_maxwidth);

	const int spinBox_ui_percent_top = settings.value("ui/spinBox_ui_percent_top",50).toInt();
	ui->spinBox_ui_percent_top->setValue(spinBox_ui_percent_top);

	ui->plotter->setMaxPixmapSize(QSize(spinBox_ui_maxwidth,spinBox_ui_maxheight));

}
void specWidget::saveSettings()
{
	QSettings settings(QCoreApplication::applicationFilePath()+".ini", QSettings::IniFormat);
	const QString combox_dev = ui->combox_dev->lineEdit()->text();
	settings.setValue("spectrum/combox_dev",combox_dev);
	const double doubleSpinBox_spr = ui->doubleSpinBox_spr->value();
	settings.setValue("spectrum/doubleSpinBox_spr",doubleSpinBox_spr);
	const double doubleSpinBox_center = ui->doubleSpinBox_center->value();
	settings.setValue("spectrum/doubleSpinBox_center",doubleSpinBox_center);
	const int spinBox_fftUpdate = ui->spinBox_fftUpdate->value();
	settings.setValue("spectrum/spinBox_fftUpdate",spinBox_fftUpdate);
	const int comboBox_fftSize = ui->comboBox_fftSize->currentIndex();
	settings.setValue("spectrum/comboBox_fftSize",comboBox_fftSize);
	const int comboBox_atn = ui->comboBox_atn->currentIndex();
	settings.setValue("spectrum/comboBox_atn",comboBox_atn);
	const int spinBox_gain = ui->spinBox_gain->value();
	settings.setValue("spectrum/spinBox_gain",spinBox_gain);
	const int spinBox_bw = ui->spinBox_bw->value();
	settings.setValue("spectrum/spinBox_bw",spinBox_bw);
	const int spinBox_chan = ui->spinBox_chan->value();
	settings.setValue("spectrum/spinBox_chan",spinBox_chan);
	const double doubleSpinBox_range_max = ui->doubleSpinBox_range_max->value();
	settings.setValue("spectrum/doubleSpinBox_range_max",doubleSpinBox_range_max);
	const double doubleSpinBox_range_min = ui->doubleSpinBox_range_min->value();
	settings.setValue("spectrum/doubleSpinBox_range_min",doubleSpinBox_range_min);

	const QString lineEdit_folder = ui->lineEdit_folder->text();
	settings.setValue("spectrum/lineEdit_folder",lineEdit_folder);
	const QString lineEdit_folder_play = ui->lineEdit_folder_play->text();
	settings.setValue("spectrum/lineEdit_folder_play",lineEdit_folder_play);


	const double doubleSpinBox_center_tx = ui->doubleSpinBox_center_tx->value();
	settings.setValue("tx/doubleSpinBox_center_tx",doubleSpinBox_center_tx);

	const int spinBox_chan_tx = ui->spinBox_chan_tx->value();
	settings.setValue("tx/spinBox_chan_tx",spinBox_chan_tx);

	const int spinBox_gain_tx = ui->spinBox_gain_tx->value();
	settings.setValue("tx/spinBox_gain_tx",spinBox_gain_tx);

	const int spinBox_bw_tx = ui->spinBox_bw_tx->value();
	settings.setValue("tx/spinBox_bw_tx",spinBox_bw_tx);

	const bool checkBox_rxagc = ui->checkBox_rxagc->isChecked();
	settings.setValue("spectrum/checkBox_rxagc",checkBox_rxagc);

	const int spinBox_ui_maxheight = ui->spinBox_ui_maxheight->value();
	settings.setValue("ui/spinBox_ui_maxheight",spinBox_ui_maxheight);

	const int spinBox_ui_maxwidth = ui->spinBox_ui_maxwidth->value();
	settings.setValue("ui/spinBox_ui_maxwidth",spinBox_ui_maxwidth);

	const int spinBox_ui_percent_top = ui->spinBox_ui_percent_top->value();
	settings.setValue("ui/spinBox_ui_percent_top",spinBox_ui_percent_top);

	ui->plotter->setMaxPixmapSize(QSize(spinBox_ui_maxwidth,spinBox_ui_maxheight));
}


void specWidget::do_rx(bool start)
{
	if (!usrp)
	{
		ui->checkBox_rx->setChecked(false);
		return;
	}
	if (start)
	{
		stop_signal_called_rx = false;
		m_rx_channel = ui->spinBox_chan->value();
		initRx();
		ui->checkBox_rx->setChecked(true);
		ui->spinBox_chan->setEnabled(false);
		ui->doubleSpinBox_spr->setEnabled(false);
	}
	else
	{
		stop_signal_called_rx = true;
		freeRx();
		ui->checkBox_rx->setChecked(false);
		ui->spinBox_chan->setEnabled(true);
		ui->doubleSpinBox_spr->setEnabled(true);
	}

}
void specWidget::do_tx(bool start)
{
	if (!usrp)
	{
		ui->checkBox_tx->setChecked(false);

		return;
	}
	if (start)
	{
		stop_signal_called_tx = false;
		m_tx_channel = ui->spinBox_chan_tx->value();
		initTx();
		ui->checkBox_tx->setChecked(true);
		ui->spinBox_chan_tx->setEnabled(false);
		ui->doubleSpinBox_spr_tx->setEnabled(false);
	}
	else
	{
		stop_signal_called_tx = true;
		freeTx();
		ui->checkBox_tx->setChecked(false);
		ui->spinBox_chan_tx->setEnabled(true);
		ui->doubleSpinBox_spr_tx->setEnabled(true);
	}
}


void specWidget::initRx()
{
	long long bw = ui->spinBox_bw->value()*1000;
	setRxRate(ui->doubleSpinBox_spr->value()*1e6);
	bw = set_rx_bandwidth(bw);
	ui->spinBox_bw->setValue(bw/1000);
	setCenterFreq(ui->plotter->getCenterFreq());
	QString atn = ui->comboBox_atn->currentText();
	if (atn.size())
		set_rx_atn(atn.toStdString());
	set_rx_agc(ui->checkBox_rxagc->isChecked());
	on_spinBox_gain_valueChanged(ui->spinBox_gain->value());
	m_rxth->setRunner([&](void){
		run_RxIO();
	});

	if (!ui->checkBox_rx->isChecked())
		return;
	//保存文件
	m_strFolder = ui->lineEdit_folder->text();
	m_rx_points = 0;
	save_count = 0;

	m_bSaveToFile = ui->checkBox_save->isChecked();
	double dfreq = ui->doubleSpinBox_center->value();
	double spr = ui->doubleSpinBox_spr->value();
	m_saveth->setRunner([&,dfreq,spr](void){
		QFile fOut;
		const size_t batchsave = 65536;
		while (!stop_signal_called_rx)
		{
			if (save_count + m_rxblock_size < m_rx_points && save_count + batchsave < m_rx_points)
			{
				size_t stasp = (save_count)  % m_rx_bufsz;
				size_t endsp = (save_count +batchsave)  % m_rx_bufsz;
				save_count += batchsave;
				if (!m_bSaveToFile)
				{
					QThread::msleep(10);
					continue;
				}
				if (endsp < batchsave)
					memcpy(&m_data_iq_rx[m_rx_bufsz], m_data_iq_rx, endsp * 2 * sizeof(short) );

				if (fOut.isOpen())
				{
					if (fOut.size()>=1024*1024*1024)
						fOut.close();
				}
				if (!fOut.isOpen())
				{
					QDir dir;
					dir.mkpath(m_strFolder);
					QDateTime dtm = QDateTime::currentDateTime();
					QString sdtm = dtm.toString("yyyy_MM_dd_HH_mm_ss.zzz");
					QString fm = m_strFolder + "/";
					fm += QString("%1MHz_%2Sps_%3.iq.sc16Intel.pcm").arg(dfreq,0,'f',6)
							.arg(spr,0,'f',6).arg(sdtm);
					fOut.setFileName(fm);
					if (!fOut.open(QIODevice::WriteOnly))
						m_bSaveToFile = false;
				}
				if (!m_bSaveToFile)
					continue;
				fOut.write((char *)m_data_iq_rx[stasp],batchsave * sizeof(short)*2);
			}
			else
				QThread::msleep(10);
		}
		if (fOut.isOpen())
			fOut.close();
	});
	m_rxth->start(QThread::TimeCriticalPriority);
	m_saveth->start();
}


void specWidget::freeRx()
{
	if (m_rxth->isRunning()||m_saveth->isRunning())
	{
		stop_signal_called_rx = true;
		m_rxth->wait();
		m_saveth->wait();
	}
}


void specWidget::initTx()
{
	long long bw = ui->spinBox_bw_tx->value()*1000;
	bw = set_tx_bandwidth(bw);
	ui->spinBox_bw_tx->setValue(bw/1000);
	set_tx_freq(ui->doubleSpinBox_center_tx->value()*1e6);
	set_tx_rate(ui->doubleSpinBox_spr_tx->value()*1e6);
	set_tx_gain(ui->spinBox_gain_tx->value(),ui->comboBox_tx_gainNames->currentText().toStdString().c_str());
	m_txth->setRunner([&](void){
		run_TxIO();
	});

	m_dataproduce_ok = false;
	read_count = m_rx_bufsz/2;
	m_tx_points = 0;
	//读取文件
	m_strFolderPlay = ui->lineEdit_folder_play->text();

	QDir cdir(m_strFolderPlay);
	QStringList lst_filter;
	lst_filter << "*.pcm";
	QFileInfoList lstFiles = cdir.entryInfoList(lst_filter,QDir::Files|QDir::Readable,QDir::Name);

	if (!ui->checkBox_tx->isChecked() || lstFiles.empty())
		return;

	m_readth->setRunner([&,lstFiles](void){
		QVector<QString> vec_fms;
		foreach (QFileInfo in, lstFiles)
		{
			vec_fms<<in.absoluteFilePath();
		}
		const int szFiles = vec_fms.size();
		int currfile = 0;

		QFile fIn;
		const size_t batchread = 65536;
		while (!stop_signal_called_tx)
		{
			if (m_tx_points + m_tx_bufsz/2 >= read_count )
			{
				if (!fIn.isOpen())
				{
					fIn.setFileName(vec_fms[currfile % szFiles]);
					if (false==fIn.open(QIODevice::ReadOnly))
					{
						fprintf (stderr,"File Can not be opened.");
						stop_signal_called_tx = true;
						continue;
					}
				}
				const size_t cur_begin = read_count % m_tx_bufsz;

				char * addr = (char *)&m_data_iq_tx[cur_begin][0];
				int real_size = fIn.read(addr, batchread * sizeof(short) * 2)/(sizeof(short) * 2);
				read_count += real_size;

				const size_t new_begin = read_count % m_tx_bufsz;

				if (new_begin < batchread)
					memcpy(m_data_iq_tx, &m_data_iq_tx[m_tx_bufsz],sizeof(short)*2*new_begin);

				if (real_size < batchread )
				{
					fIn.close();
					++currfile;
				}
			}
			else
			{
				if (!m_dataproduce_ok)
					m_dataproduce_ok = true;
				QThread::msleep(10);
			}
		}
		if (fIn.isOpen())
			fIn.close();
	});

	m_readth->start();
	while (!m_dataproduce_ok && ! stop_signal_called_tx)
		QThread::msleep(10);
	m_txth->start(QThread::TimeCriticalPriority);
}


void specWidget::freeTx()
{
	if (m_txth->isRunning() || m_readth->isRunning())
	{
		stop_signal_called_tx = true;
		m_txth->wait();
		m_readth->wait();
	}
}
void specWidget::initFFTW()
{
	m_pFFTIn = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * m_nFFTSize);
	m_pFFTOut = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * m_nFFTSize);
	m_pFFTPlan = fftw_plan_dft_1d(m_nFFTSize,m_pFFTIn,m_pFFTOut,FFTW_FORWARD,FFTW_ESTIMATE);
	for (int i=0;i<m_nFFTSize;++i)
	{
		m_dHammingWnd.push_back(0.54 - 0.46 * cos (2*3.1415927 * i / (m_nFFTSize-1)));
		m_dFFTAmp.push_back(0);
	}

}

void specWidget::freeFFTW()
{
	if (m_pFFTPlan)
	{
		fftw_destroy_plan(m_pFFTPlan);
		m_pFFTPlan = nullptr;
	}
	if (m_pFFTIn)
	{
		fftw_free(m_pFFTIn);
		m_pFFTIn = nullptr;
	}
	if (m_pFFTOut)
	{
		fftw_free(m_pFFTOut);
		m_pFFTOut = nullptr;
	}
	m_dHammingWnd.clear();
	m_dFFTAmp.clear();
}
void specWidget::appendWavComplex(const double (* pWav)[2], const int count, double voltage_ref)
{
	if (!m_pFFTIn || !m_pFFTOut || !m_pFFTPlan || m_dHammingWnd.size()!=m_nFFTSize
			|| m_dFFTAmp.size()!=m_nFFTSize)
		return;
	memset(m_pFFTIn,0,sizeof(fftw_complex)*m_nFFTSize);
	const int nFFTCp = m_nFFTSize<count?m_nFFTSize:count;
	for (long long i=0;i<nFFTCp ;++i)
	{
		long long nHammingIdx = i * m_nFFTSize / nFFTCp;
		m_pFFTIn[i][0] = pWav[i][0] * m_dHammingWnd[nHammingIdx];
		m_pFFTIn[i][1] = pWav[i][1] * m_dHammingWnd[nHammingIdx];
	}
	fftw_execute(m_pFFTPlan);
	const double minus = 10 *log(m_nFFTSize * voltage_ref * voltage_ref)/log(10);

	for (long i = 0; i< m_nFFTSize ;++i)
	{
		m_dFFTAmp[(i+m_nFFTSize/2) % m_nFFTSize] = 5 * log (m_pFFTOut[i][0] * m_pFFTOut[i][0] + m_pFFTOut[i][1] * m_pFFTOut[i][1])/log(10) - minus + m_dManuAdd;
	}

	ui->plotter-> setNewFftData(m_dFFTAmp.data(),m_nFFTSize);
}


void specWidget::timerEvent(QTimerEvent * e)
{
	static std::shared_ptr<double> ppbuf(new double [65536*16]);
	static double (*pBufIQ)[2] = (double (*)[2])ppbuf.get();
	if (e->timerId()==m_nTimerID )
	{
		if (ui->checkBox_rx->isChecked()==true)
		{
			double ref1v = 16384;
			size_t curr_red =(m_rx_points + m_rx_bufsz - m_nFFTSize) % m_rx_bufsz ;
			if (curr_red + m_nFFTSize <= m_rx_bufsz )
			{
				int i = 0;
				while (i < m_nFFTSize)
				{
					pBufIQ[i][0] = m_data_iq_rx[i + curr_red][0];
					pBufIQ[i][1] = m_data_iq_rx[i + curr_red][1];
					++i;
				}
				appendWavComplex(pBufIQ,m_nFFTSize,ref1v);

			}
			if (m_nCurrentCenter>=0 && m_nCurrentCenter < m_nFFTSize)
			{
				ui->sMeter->setLevel(m_dFFTAmp[m_nCurrentCenter]);
			}
		}
		static int ccct = 0;
		if (++ccct % 10==0)
		{
			size_t he = read_count - m_tx_points;
			ui->lcdNumber_tx->display((double)he/1024.0/1024.0);
			ui->lcdNumber_saveBehind->display((double)he);
			ui->lcdNumber_read->display(int(m_rx_points /1024 / 1024 ));
		}
	}

}


void specWidget::on_comboBox_fftSize_activated(int index)
{
	if (index)
		m_nFFTSize = 128 * (1<<index);
	if (m_nFFTSize>65536)
		m_nFFTSize = 65536;
	if (m_nFFTSize<128)
		m_nFFTSize = 128;
	if (usrp)
	{
		freeFFTW();
		initFFTW();
	}
	saveSettings();
}

void specWidget::on_doubleSpinBox_center_valueChanged(double arg1)
{
	if (arg1 * 1e6 != ui->freqCtrl->getFrequency())
	{
		ui->freqCtrl->setFrequency(arg1 * 1e6);
	}
}

void specWidget::on_spinBox_gain_valueChanged(int arg1)
{
	if (usrp)
		set_rx_gain(arg1,ui->comboBox_rx_gainNames->currentText().toStdString().c_str());
	//usrp->set_rx_agc(true,m_rx_channel);

}

void specWidget::on_doubleSpinBox_range_max_valueChanged(double arg1)
{
	ui->plotter->setWaterfallRange(ui->doubleSpinBox_range_min->value(),ui->doubleSpinBox_range_max->value());
	ui->plotter->setPandapterRange(ui->doubleSpinBox_range_min->value(),ui->doubleSpinBox_range_max->value());
}

void specWidget::on_doubleSpinBox_range_min_valueChanged(double arg1)
{
	ui->plotter->setPandapterRange(ui->doubleSpinBox_range_min->value(),ui->doubleSpinBox_range_max->value());
	ui->plotter->setWaterfallRange(ui->doubleSpinBox_range_min->value(),ui->doubleSpinBox_range_max->value());
}

void specWidget::on_comboBox_atn_currentIndexChanged(const QString &arg1)
{
	if (arg1.size())
	{
		if (usrp)
			set_rx_atn(arg1.toStdString());
	}
}

void specWidget::on_spinBox_chan_valueChanged(int arg1)
{
	m_rx_channel = arg1;
}

void specWidget::on_toolButton_br_clicked()
{
	QString str = QFileDialog::getExistingDirectory(this,tr("Output to"),ui->lineEdit_folder->text());
	if (str.length())
		ui->lineEdit_folder->setText(str);
}

void specWidget::on_checkBox_save_stateChanged(int arg1)
{
	m_bSaveToFile = arg1==0?false:true;
}

void specWidget::on_spinBox_bw_valueChanged(int arg1)
{
	double bw = arg1 * 1000;
	if (bw > ui->plotter->getSampleRate())
		bw = ui->plotter->getSampleRate();
	if (bw <0)
		bw = 0;
	bw = set_rx_bandwidth(bw);

}

void specWidget::on_toolButton_br_play_clicked()
{
	QString str = QFileDialog::getExistingDirectory(this,tr("Input from"),ui->lineEdit_folder_play->text());
	if (str.length())
		ui->lineEdit_folder_play->setText(str);
}

void specWidget::on_checkBox_tx_stateChanged(int arg1)
{
	m_bPlayFromFile = arg1==0?false:true;
}

void specWidget::on_doubleSpinBox_center_tx_valueChanged(double arg1)
{
	set_tx_freq(arg1 * 1e6);
}

void specWidget::on_spinBox_chan_tx_valueChanged(int arg1)
{
	m_tx_channel = arg1;

}

void specWidget::on_spinBox_gain_tx_valueChanged(int arg1)
{
	set_tx_gain(arg1,ui->comboBox_tx_gainNames->currentText().toStdString().c_str());
}

void specWidget::on_spinBox_bw_tx_valueChanged(int arg1)
{
	double bw = arg1 * 1000;
	bw = set_tx_bandwidth(bw);
}

void specWidget::on_pushButton_connect_toggled(bool checked)
{
	saveSettings();
	if (checked==false)
	{
		disconnect_usrp();
	}
	else
	{
		loadSettings();
		connect_usrp();
	}

}


void specWidget::on_checkBox_rx_toggled(bool checked)
{
	saveSettings();
	loadSettings();
	do_rx(checked);
}




void specWidget::on_doubleSpinBox_spr_tx_valueChanged(double arg1)
{
	set_tx_freq(arg1 * 1e6);
}


void specWidget::on_checkBox_tx_toggled(bool checked)
{
	saveSettings();
	loadSettings();
	do_tx(checked);
}


void specWidget::on_checkBox_rxagc_toggled(bool checked)
{
	set_rx_agc(checked);
}

void specWidget::on_spinBox_ui_percent_top_valueChanged(int arg1)
{
	ui->plotter->setPercent2DScreen(arg1);
}
