uhd_io_cpp.cpp 11.4 KB
Newer Older
M
manjaro 已提交
1 2 3 4 5
/*
 * Copyright 2015 Ettus Research LLC
 * Copyright 2018 Ettus Research, a National Instruments Company
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
M
manjaro 已提交
6
 * 丁劲犇修改 2021
M
manjaro 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 */

#include <uhd/types/tune_request.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/thread.hpp>
#include <chrono>
#include <complex>
#include <csignal>
#include <fstream>
#include <iostream>
#include <thread>
#include <vector>
using uhd::tune_request_t;
using uhd::tx_streamer;
using uhd::usrp::multi_usrp;
using uhd::rx_streamer;
using std::thread;
using std::cerr;
using std::endl;

static bool stop_signal_called = false;
void sigint_handler(int code){
	(void)code;
	stop_signal_called = true;
}
M
manjaro 已提交
33 34 35 36
/*!
 * \brief The tag_channelOptions struct
 * 通道配置参数
 */
M
manjaro 已提交
37
struct tag_channelOptions{
M
manjaro 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51
	std::string type = "sc16";		//样点类型,为上位机上类型: fc64, fc32, or sc16
	std::string ant = "TX/RX";		//天线选取,B210 有 TX/RX 或者 RX2两个
	std::string subdev;				//子设备,本例子没有配置
	std::string wirefmt;			//内部类型 (sc8 or sc16),是片上处理的类型
	size_t channel = 0;				//通道号,可以是0(左侧)或者1(右侧)
	size_t spb	=	10000;			//缓冲大小,太小会丢包,太大会超时
	double rate = 61.44e6/2;		//采样率,单位Hz
	double freq = 1.0e9;			//射频频率,单位Hz
	double gain = 55;				//射频增益,单位dB
	double bw   = rate;				//滤波带宽,默认为采样窗口
	double lo_offset = 0;			//LO偏移,单位 Hz (缺省)
	bool   int_n_mod = false;		//int-n 模式(本例不配置)
	bool   docheck = true;			//在开始前执行检查
	double setup_time = 1.0;		//rx配置检查时间,可选。
M
manjaro 已提交
52
};
M
manjaro 已提交
53
//通道检查函数
M
manjaro 已提交
54 55 56
bool check_tx_status(const std::string & ref, multi_usrp::sptr usrp);
bool check_rx_status(const std::string & ref, multi_usrp::sptr usrp,const tag_channelOptions & op);

M
manjaro 已提交
57 58 59 60
/*!
 * 范例吞吐函数,使用环形队列保持跟随收发
 */
template <class FMT = short>
M
manjaro 已提交
61 62 63 64 65 66
void do_io(
		const tag_channelOptions & oprx,
		const tag_channelOptions & optx,
		rx_streamer::sptr rx,
		tx_streamer::sptr tx)
{
M
manjaro 已提交
67
	//初始化队列
M
manjaro 已提交
68
	std::vector< std::shared_ptr< FMT > > vec_buffer;
M
manjaro 已提交
69
	std::vector< int > vec_buffersz;
M
manjaro 已提交
70 71
	const int bufsz = 65536;
	for (int i=0;i<bufsz;++i)
M
manjaro 已提交
72 73 74 75 76
	{
		vec_buffer.push_back(std::shared_ptr< FMT > (new FMT[oprx.spb * 2]));
		vec_buffersz.push_back(0);
	}
	//收发计数
M
manjaro 已提交
77
	long long rx_count = 0, tx_count = 0;
M
manjaro 已提交
78
	//接收线程
M
manjaro 已提交
79 80 81 82 83 84 85 86 87
	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(oprx.spb);
		stream_cmd.stream_now = true;
		stream_cmd.time_spec  = uhd::time_spec_t();
		rx->issue_stream_cmd(stream_cmd);
		while (!stop_signal_called)
		{
M
manjaro 已提交
88
			vec_buffersz[rx_count % bufsz] = rx->recv((void *)(vec_buffer[rx_count % bufsz].get()),oprx.spb,md_rx,0.1,false);
M
manjaro 已提交
89 90 91 92 93 94 95 96 97
			++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 ;
		}
	};
M
manjaro 已提交
98
	//发射线程
M
manjaro 已提交
99 100 101 102
	auto thcall_tx = [&]()->void{
		uhd::tx_metadata_t md_tx;
		md_tx.end_of_burst   = false;
		md_tx.start_of_burst = false;
M
manjaro 已提交
103
		long long last_tx = -1;
M
manjaro 已提交
104 105
		while (!stop_signal_called)
		{
M
manjaro 已提交
106 107 108 109 110 111 112
			//等待一会数据,以便TX可以保持跟随。也可以不设置,这样开始时会争夺。
			if (rx_count<100)
				continue;
			if (last_tx==tx_count)
				cerr<<"Blocked!"<<endl;
			const size_t samples_sent = tx->send((void *)(vec_buffer[tx_count % bufsz].get()),vec_buffersz[tx_count % bufsz],md_tx,0.1);
			last_tx = tx_count;
M
manjaro 已提交
113 114 115 116 117 118 119
			if (tx_count<rx_count)
				++tx_count;
			if (samples_sent != optx.spb)
				cerr<<"The tx_stream timed out sending " << optx.spb << " samples ("  << samples_sent << " sent)." << endl;
		}
	};

M
manjaro 已提交
120 121
	//启动线程
	thread rx_thread(thcall_rx);	
M
manjaro 已提交
122 123
	thread tx_thread(thcall_tx);
	std::cout<<"Press ^C to Stop."<<endl;
M
manjaro 已提交
124
	//主线程不断打印状态
M
manjaro 已提交
125 126 127 128 129
	while (!stop_signal_called)
	{
		cerr<<"RX" << rx_count<< " TX " << tx_count<<"\r";
		std::this_thread::sleep_for(std::chrono::milliseconds(400));
	}
M
manjaro 已提交
130
	//退出
M
manjaro 已提交
131 132 133 134 135 136 137 138
	rx_thread.join();
	tx_thread.join();

}


int UHD_SAFE_MAIN(int /*argc*/, char* /*argv*/[])
{
M
manjaro 已提交
139
	//1.创建一个设备,可以不填写,则使用第一台设备。
M
manjaro 已提交
140
	std::string args ("");
M
manjaro 已提交
141
	//2.设置时钟参考 (internal, external, mimo)
M
manjaro 已提交
142 143 144 145 146
	std::string ref = "internal";
	cerr << "Creating the usrp device with: "  << args  <<"..."<< endl;
	multi_usrp::sptr usrp = multi_usrp::make(args);
	usrp->set_clock_source(ref);

M
manjaro 已提交
147
	//3.配置发射
M
manjaro 已提交
148
	tag_channelOptions tx_op;
M
manjaro 已提交
149 150 151 152 153
	tx_op.channel = 0;
	tx_op.freq = 89e6;
	tx_op.bw = 200e3;
	tx_op.gain=70;
	//3.1子设备配置(默认)
M
manjaro 已提交
154 155 156
	if (tx_op.subdev.size())
		usrp->set_tx_subdev_spec(tx_op.subdev);
	cerr << "TX Using Device: " << usrp->get_pp_string() << endl;
M
manjaro 已提交
157
	//3.2速率配置
M
manjaro 已提交
158 159 160
	cerr << "Setting TX Rate: " <<  (tx_op.rate / 1e6) << "Msps..." << endl;
	usrp->set_tx_rate(tx_op.rate);
	cerr << "Actual TX Rate: " << usrp->get_tx_rate() / 1e6 << "Msps..." << endl;
M
manjaro 已提交
161
	//3.3中心频率配置
M
manjaro 已提交
162 163 164 165 166 167 168
	cerr << "Setting TX Freq: "  << (tx_op.freq / 1e6) <<"MHz..." << endl;
	cerr << "Setting TX LO Offset: " << (tx_op.lo_offset / 1e6) << "MHz..." <<endl;
	tune_request_t tune_request_tx = tune_request_t(tx_op.freq, tx_op.lo_offset);
	if (tx_op.int_n_mod)
		tune_request_tx.args = uhd::device_addr_t("mode_n=integer");
	usrp->set_tx_freq(tune_request_tx);
	cerr << "Actual TX Freq: " <<  (usrp->get_tx_freq() / 1e6) << "MHz..." << endl;
M
manjaro 已提交
169
	//3.4增益配置
M
manjaro 已提交
170 171 172
	cerr << "Setting TX Gain: " << tx_op.gain <<" dB..." << endl;
	usrp->set_tx_gain(tx_op.gain);
	cerr << "Actual TX Gain: " << usrp->get_tx_gain() << " dB..." << endl;
M
manjaro 已提交
173
	//3.5模拟前端滤波器带宽配置
M
manjaro 已提交
174 175 176
	cerr << "Setting TX Bandwidth: " << (tx_op.bw / 1e6) << "MHz..."  << endl;
	usrp->set_tx_bandwidth(tx_op.bw);
	cerr << "Actual TX Bandwidth: " << usrp->get_tx_bandwidth() / 1e6 << "MHz..." << endl;
M
manjaro 已提交
177
	//3.6指定天线
M
manjaro 已提交
178 179 180
	if (tx_op.ant.size())
		usrp->set_tx_antenna(tx_op.ant);

M
manjaro 已提交
181
	//4.配置接收
M
manjaro 已提交
182 183 184
	tag_channelOptions rx_op;
	rx_op.ant = "RX2";
	rx_op.channel = 0;
M
manjaro 已提交
185 186 187 188
	rx_op.bw = 200e3;
	rx_op.freq = 107.7e6;
	rx_op.gain = 50;
	//4.1 子设备
M
manjaro 已提交
189 190 191
	if (rx_op.subdev.size())
		usrp->set_rx_subdev_spec(rx_op.subdev);
	cerr << "RX Using Device: " << usrp->get_pp_string() << endl;
M
manjaro 已提交
192
	//4.2 采样率
M
manjaro 已提交
193 194 195
	cerr << "Setting RX Rate: " <<  (rx_op.rate / 1e6) << "Msps..." << endl;
	usrp->set_rx_rate(rx_op.rate);
	cerr << "Actual RX Rate: " << usrp->get_rx_rate() / 1e6 << "Msps..." << endl;
M
manjaro 已提交
196
	//4.3 中心频率
M
manjaro 已提交
197 198 199 200 201 202 203
	cerr << "Setting RX Freq: "  << (rx_op.freq / 1e6) <<"MHz..." << endl;
	cerr << "Setting RX LO Offset: " << (rx_op.lo_offset / 1e6) << "MHz..." <<endl;
	tune_request_t tune_request_rx = tune_request_t(rx_op.freq, rx_op.lo_offset);
	if (rx_op.int_n_mod)
		tune_request_rx.args = uhd::device_addr_t("mode_n=integer");
	usrp->set_rx_freq(tune_request_rx);
	cerr << "Actual RX Freq: " <<  (usrp->get_rx_freq() / 1e6) << "MHz..." << endl;
M
manjaro 已提交
204
	//4.4 增益
M
manjaro 已提交
205 206 207
	cerr << "Setting RX Gain: " << rx_op.gain <<" dB..." << endl;
	usrp->set_rx_gain(rx_op.gain);
	cerr << "Actual RX Gain: " << usrp->get_rx_gain() << " dB..." << endl;
M
manjaro 已提交
208
	//4.5 前端模拟滤波带宽
M
manjaro 已提交
209 210 211
	cerr << "Setting RX Bandwidth: " << (rx_op.bw / 1e6) << "MHz..."  << endl;
	usrp->set_rx_bandwidth(rx_op.bw);
	cerr << "Actual RX Bandwidth: " << usrp->get_rx_bandwidth() / 1e6 << "MHz..." << endl;
M
manjaro 已提交
212
	//4.6 选择天线
M
manjaro 已提交
213 214 215
	if (rx_op.ant.size())
		usrp->set_rx_antenna(rx_op.ant);

M
manjaro 已提交
216 217 218 219 220 221
	//5 检查状态
	if (tx_op.docheck)	check_tx_status(ref,usrp);
	if (rx_op.docheck)	check_rx_status(ref,usrp,rx_op);

	//6.创建流对象实例
	//6.1 发射
M
manjaro 已提交
222 223 224 225 226
	std::vector<size_t> channel_nums_tx;
	uhd::stream_args_t stream_args_tx(tx_op.type, tx_op.wirefmt);
	channel_nums_tx.push_back(tx_op.channel);
	stream_args_tx.channels             = channel_nums_tx;
	tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args_tx);
M
manjaro 已提交
227
	// 6.2 接收
M
manjaro 已提交
228 229 230 231 232 233
	uhd::stream_args_t stream_args_rx(rx_op.type, rx_op.wirefmt);
	std::vector<size_t> channel_nums_rx;
	channel_nums_rx.push_back(rx_op.channel);
	stream_args_rx.channels             = channel_nums_rx;
	rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args_rx);

M
manjaro 已提交
234
	//开始收发循环
M
manjaro 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
	do_io<short>(rx_op,tx_op,rx_stream,tx_stream);

	// finished
	cerr << endl << "Done!" << endl << endl;

	return EXIT_SUCCESS;
}


bool check_tx_status(const std::string & ref, multi_usrp::sptr usrp)
{
	// Check Ref and LO Lock detect
	std::vector<std::string> sensor_names;
	sensor_names = usrp->get_tx_sensor_names(0);
	if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked")
			!= sensor_names.end()) {
		uhd::sensor_value_t lo_locked = usrp->get_tx_sensor("lo_locked", 0);
		cerr <<"Checking TX: "<< lo_locked.to_pp_string() << std::endl;
		UHD_ASSERT_THROW(lo_locked.to_bool());
	}
	sensor_names = usrp->get_mboard_sensor_names(0);
	if ((ref == "mimo")
			and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked")
				 != sensor_names.end())) {
		uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked", 0);
		std::cerr << "Checking TX: "<< mimo_locked.to_pp_string()  << std::endl;
		UHD_ASSERT_THROW(mimo_locked.to_bool());
	}
	if ((ref == "external")
			and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked")
				 != sensor_names.end())) {
		uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked", 0);
		std::cout << "Checking TX: %s ..."<< ref_locked.to_pp_string()  << std::endl;
		UHD_ASSERT_THROW(ref_locked.to_bool());
	}
	return true;
}
typedef std::function<uhd::sensor_value_t(const std::string&)> get_sensor_fn_t;
bool check_locked_sensor(std::vector<std::string> sensor_names,
	const char* sensor_name,
	get_sensor_fn_t get_sensor_fn,
	double setup_time)
{
	if (std::find(sensor_names.begin(), sensor_names.end(), sensor_name)
		== sensor_names.end())
		return false;

	auto setup_timeout = std::chrono::steady_clock::now()
						 + std::chrono::milliseconds(int64_t(setup_time * 1000));
	bool lock_detected = false;

	std::cerr << "Checking RX Waiting for: " << sensor_name;
	std::cerr.flush();

	while (true) {
		if (lock_detected and (std::chrono::steady_clock::now() > setup_timeout)) {
			std::cerr << " locked." << std::endl;
			break;
		}
		if (get_sensor_fn(sensor_name).to_bool()) {
			std::cerr << "+";
			std::cerr.flush();
			lock_detected = true;
		} else {
			if (std::chrono::steady_clock::now() > setup_timeout) {
				std::cerr << std::endl;
				std::cerr << "timed out waiting for consecutive locks on sensor : "<<sensor_name;
				return false;
			}
			std::cerr.flush();
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
	std::cout << std::endl;
	return true;
}

bool check_rx_status(const std::string & ref, multi_usrp::sptr usrp,const tag_channelOptions & op)
{
	// check Ref and LO Lock detect
	check_locked_sensor(usrp->get_rx_sensor_names(op.channel),
						"lo_locked",
						[usrp, op](const std::string& sensor_name) {
		return usrp->get_rx_sensor(sensor_name, op.channel);
	},
	op.setup_time);
	if (ref == "mimo") {
		check_locked_sensor(usrp->get_mboard_sensor_names(0),
							"mimo_locked",
							[usrp](const std::string& sensor_name) {
			return usrp->get_mboard_sensor(sensor_name);
		},
		op.setup_time);
	}
	if (ref == "external") {
		check_locked_sensor(usrp->get_mboard_sensor_names(0),
							"ref_locked",
							[usrp](const std::string& sensor_name) {
			return usrp->get_mboard_sensor(sensor_name);
		},
		op.setup_time);
	}
	return true;
}