#include "uhd_device.h"
#include <QThread>
using uhd::tune_request_t;
using uhd::tx_streamer;
using uhd::usrp::multi_usrp;
using uhd::rx_streamer;
using std::cerr;
using std::endl;
using std::string;
using std::vector;
using std::shared_ptr;

uhd_io_thread::uhd_io_thread (std::function<void (void)> runner,QObject * p)
	:QThread(p)
	,m_runner(runner)

{

}
uhd_io_thread::uhd_io_thread (QObject * p)
	:QThread(p)

{

}

void uhd_io_thread::run()
{
	if (m_runner)
		m_runner();
}

uhd_device::uhd_device()
	:stop_signal_called(false)
	,streaming(false)
	,rx_count(0)
{
	for (int i=0;i<bufsz;++i)
	{
		vec_buffer.push_back(shared_ptr< short > (new short[m_spb_size * 2]));
		vec_buffersz.push_back(0);
		vec_buffer_tm.push_back(uhd::time_spec_t());
	}
}

uhd_device::uhd_device(const std::string &args)
	:stop_signal_called(false)
	,streaming(false)
	,m_dev_args (args)
	,rx_count(0)

{
	for (int i=0;i<bufsz;++i)
	{
		vec_buffer.push_back(shared_ptr< short > (new short[m_spb_size * 2]));
		vec_buffersz.push_back(0);
		vec_buffer_tm.push_back(uhd::time_spec_t());
	}
}
uhd_device::~uhd_device()
{
	stop_signal_called = true;
	while (streaming)
	{
		QThread::msleep(100);
	}

}

void uhd_device::setDevArgs(const std::string &args)
{
	this->m_dev_args = args;

}
std::string uhd_device::devArgs() const
{
	return m_dev_args;
}

bool uhd_device::open_device()
{
	string ref = "internal";
	usrp = multi_usrp::make(m_dev_args);
	if (!usrp)
		return false;
	usrp->set_clock_source(ref,multi_usrp::ALL_MBOARDS);
	//if (rx_op.subdev.size())
	//	usrp->set_rx_subdev_spec(rx_op.subdev,multi_usrp::ALL_MBOARDS);
	stop_signal_called = false;
	return usrp?true:false;
}

bool uhd_device::close_device()
{
	stop_signal_called = true;
	while (streaming)
	{
		QThread::msleep(1000);
	}
	usrp.reset();

	return true;
}

/*!
 * 范例落盘函数,使用环形队列保持跟随收发
 */
void uhd_device::run_IO()
{
	//创建流对象实例
	uhd::stream_args_t stream_args_rx("sc16", "sc16");
	stream_args_rx.channels.push_back(m_channel);
	rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args_rx);

	rx_count = 0;
	//接收线程
	auto thcall_rx = [&]()->void{
		uhd::rx_metadata_t md_rx;
		uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
		stream_cmd.num_samps  = size_t(m_spb_size);
		stream_cmd.stream_now = true;
		stream_cmd.time_spec  = uhd::time_spec_t();
		streaming = true;
		rx_stream->issue_stream_cmd(stream_cmd);
		while (!stop_signal_called)
		{
			vec_buffersz[rx_count % bufsz] = rx_stream->recv((void *)(vec_buffer[rx_count % bufsz].get()),m_spb_size,md_rx,0.1,false);
			//md_rx可以读取时戳
			vec_buffer_tm[rx_count % bufsz] = md_rx.time_spec;
			++rx_count;
			if (md_rx.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT)
				fputs("Time out.",stderr);
			else if (md_rx.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW)
				fputs("Over flow",stderr);				
			else if (md_rx.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE)
			{
				cerr << "Receiver error: "<< md_rx.strerror() << endl ;
				stop_signal_called = true;
			}
		}
		stream_cmd.stream_now = false;
		rx_stream->issue_stream_cmd(stream_cmd);
		streaming = false;
	};
	//启动线程
	uhd_io_thread * rx_thread = new uhd_io_thread(thcall_rx,0);
	rx_thread->start(QThread::HighestPriority);
	//主线程不断打印状态
	while (!stop_signal_called)
	{
		cerr<<"RX" << rx_count<<"\r";
		std::this_thread::sleep_for(std::chrono::milliseconds(400));
	}
	//退出
	rx_thread->wait();
	rx_thread->deleteLater();

}

