3 * Copyright 2009 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <vrt/quadradio.h>
31 #define MIN_IP_LOCAL_PORT 32768
32 #define MAX_IP_LOCAL_PORT 61000
34 #define ALL_DBOARDS 0xf
37 send_and_check(int fd, void *buf, size_t len)
39 int r = send(fd, buf, len, 0);
44 if ((size_t) r != len){
45 fprintf(stderr, "send: short return value. expected %zd, got %d\n", len, r);
52 vrt::quadradio::quadradio(const std::string &ip, size_t rx_bufsize)
53 : d_ctrl_fd(0), d_data_fd(0), d_data_port(0),
54 d_band_select(VRT_BAND_SEL_A), d_rx_antenna(0), d_attenuation0(0), d_attenuation1(0)//d_10dB_atten(true)
56 if (!open(ip.c_str()))
57 throw std::runtime_error("vrt::quadradio: failed to open " + ip + "\n");
59 d_rx = vrt::rx::make(data_socket_fd(), rx_bufsize);
60 set_test_signal(VRT_TEST_SIG_NORMAL);
63 vrt::quadradio::~quadradio()
69 vrt::quadradio::open(const char *ip)
71 return open_sockets(ip, control_port(),
72 &d_ctrl_fd, &d_ctrl_port_inaddr,
73 &d_data_fd, &d_data_port);
77 vrt::quadradio::start_streaming(int samples_per_pkt)
79 int rxdspno = 0; // FIXME make it the first param
81 return send_rx_command(d_ctrl_fd, rxdspno, true, d_ctrl_port_inaddr,
82 d_data_port, samples_per_pkt);
86 vrt::quadradio::stop_streaming()
88 int rxdspno = 0; // FIXME make it the first param
90 return send_stop_rx_command(d_ctrl_fd, rxdspno);
94 vrt::quadradio::set_center_freq(double target_freq){
95 if (target_freq < 700e6) return false;
96 if (target_freq <= 1.0e9) return set_band_select(VRT_BAND_SEL_A);
97 if (target_freq <= 1.5e9) return set_band_select(VRT_BAND_SEL_B);
98 if (target_freq <= 2.2e9) return set_band_select(VRT_BAND_SEL_C);
99 if (target_freq <= 3.0e9) return set_band_select(VRT_BAND_SEL_D);
104 vrt::quadradio::set_band_select(vrt_band_sel_t band){
105 d_band_select = band;
106 update_dboard_pins();
111 //vrt::quadradio::set_10dB_atten(bool on){
112 // d_10dB_atten = on;
113 // update_dboard_pins();
117 vrt::quadradio::select_rx_antenna(const std::string &ant){
118 if (ant == "rf") d_rx_antenna = 0;
119 else if (ant == "cal") d_rx_antenna = 1;
121 update_dboard_pins();
126 vrt::quadradio::set_attenuation0(int attenuation){
127 if (attenuation < 0 || attenuation > 31) return false;
128 d_attenuation0 = attenuation;
129 update_dboard_pins();
134 vrt::quadradio::set_attenuation1(int attenuation){
135 if (attenuation < 0 || attenuation > 31) return false;
136 d_attenuation1 = attenuation;
137 update_dboard_pins();
141 //bit reversal, length in bits
142 static int reverse_bits(int input, int len){
144 for (int i = 0; i < len; i++){
145 reversed += (input & (1<<i))?(1 << (len-i-1)):0;
151 vrt::quadradio::update_dboard_pins(void){
152 //convert the band ID to bits
154 switch (d_band_select){
155 case VRT_BAND_SEL_A: band_select = 3; break;
156 case VRT_BAND_SEL_B: band_select = 2; break;
157 case VRT_BAND_SEL_C: band_select = 1; break;
158 case VRT_BAND_SEL_D: band_select = 0; break;
159 default: band_select = 0;
161 //calculate the control bits
163 ((reverse_bits(d_attenuation0, 5) & 0x1f) << 10) | \
164 ((reverse_bits(~d_attenuation1, 5) & 0x1f) << 03) | \
165 ((band_select & 0x03) << 01) | \
166 ((d_rx_antenna & 0x01) << 00);
167 set_dboard_pins(ALL_DBOARDS, db_ctrl); // FIXME sets them all
171 vrt::quadradio::set_adc_gain(bool on){
172 set_hsadc_conf(ALL_DBOARDS, 0x14, on ? 0x90 : 0x80);
176 vrt::quadradio::set_dc_offset_comp(bool on){
178 set_hsadc_conf(ALL_DBOARDS, 0x1B, 0x80);
179 set_hsadc_conf(ALL_DBOARDS, 0x1A, 0x00); //bits 6:4 set time constant
181 else set_hsadc_conf(ALL_DBOARDS, 0x1B, 0x00);
185 vrt::quadradio::set_digital_gain(float gain){
186 int gain_q1 = static_cast<int>(round(gain*2.0));
187 set_hsadc_conf(ALL_DBOARDS, 0x17, gain_q1);
191 vrt::quadradio::set_test_signal(vrt_test_sig_t type){
192 set_hsadc_conf(ALL_DBOARDS, 0x16, type);
196 vrt::quadradio::open_sockets(const char *quad_radio_ip, int quad_radio_ctrl_port,
197 int *ctrl_fd_ptr, struct in_addr *ctrl_port_inaddr,
198 int *data_fd_ptr, int *data_port_ptr)
200 int ctrl_fd; // socket for control
201 int data_fd; // socket fd for data
202 int data_port; // our port number
205 // create a udp socket and connect it to the quad radio control port
208 ctrl_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
210 perror("socket: ctrl_fd");
214 struct sockaddr_in si_other;
215 memset(&si_other, 0, sizeof(si_other));
216 si_other.sin_family = AF_INET;
217 si_other.sin_port = htons(quad_radio_ctrl_port);
218 if (inet_pton(AF_INET, quad_radio_ip, &si_other.sin_addr) <= 0){
223 if (connect(ctrl_fd, (struct sockaddr *) &si_other, sizeof(si_other)) != 0){
228 // get our ip address associated with the interface connected to the control port
230 struct sockaddr_in si_me;
231 memset(&si_me, 0, sizeof(si_me));
232 socklen_t sockname_len = sizeof(si_me);
233 if (getsockname(ctrl_fd, (struct sockaddr *) &si_me, &sockname_len) != 0){
234 perror("getsockname");
237 *ctrl_port_inaddr = si_me.sin_addr;
241 const char *s = inet_ntop(si_me.sin_family, &si_me.sin_addr, buf, sizeof(buf));
246 // printf("our ip addr associated with ctrl port: %s\n", s);
250 // create a udp socket to use to receive data
253 data_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
255 perror("socket: data_fd");
259 // bind it to a local port on the interface that connects to the ctrl port.
260 // FIXME this assumes that interface connected to the control port and the
261 // interface connected to the data port are the same. If we're using
262 // both ethernet ports on the quad radio, this may not be the case.
265 for (int port = MIN_IP_LOCAL_PORT; port <= MAX_IP_LOCAL_PORT; port++){
266 struct sockaddr_in si_me;
267 memset(&si_me, 0, sizeof(si_me));
268 si_me.sin_family = AF_INET;
269 si_me.sin_port = htons(port);
270 si_me.sin_addr.s_addr = htonl(INADDR_ANY);
272 if (bind(data_fd, (struct sockaddr *) &si_me, sizeof(si_me)) == 0){ // found one!
278 if (data_port == -1){
279 fprintf(stderr, "failed to bind to a local port\n");
283 // printf("our data port = %d\n", data_port);
285 *ctrl_fd_ptr = ctrl_fd;
286 *data_fd_ptr = data_fd;
287 *data_port_ptr = data_port;
292 // ------------------------------------------------------------------------
295 vrt::quadradio::send_rx_command(int ctrl_fd, int rxdspno, bool start,
296 struct in_addr addr, int data_port,
300 cmd[0] = htonl(0); // verb: set
301 cmd[1] = htonl(0); // id: rx_streaming
302 cmd[2] = htonl(start ? 1: 0); // start or stop?
303 cmd[3] = addr.s_addr; // ip address to send data to (already network endian)
304 cmd[4] = htonl(data_port); // port to send data to
305 cmd[5] = htonl(samples_per_pkt);
306 cmd[6] = htonl(rxdspno); // the DSP pipeline to configure
308 return send_and_check(ctrl_fd, cmd, sizeof(cmd));
312 vrt::quadradio::send_stop_rx_command(int ctrl_fd, int rxdspno)
314 struct in_addr in_addr;
316 return send_rx_command(ctrl_fd, rxdspno, false, in_addr, 0, 0);
320 vrt::quadradio::set_dboard_pins(int dboard_bitmask, int v)
323 cmd[0] = htonl(0); // verb: set
324 cmd[1] = htonl(1); // id: dboard_pins
325 cmd[2] = htonl(dboard_bitmask);
326 cmd[3] = htonl(v); // value
328 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
332 vrt::quadradio::set_setting_reg(int regno, int value)
335 cmd[0] = htonl(0); // verb: set
336 cmd[1] = htonl(2); // id: SR
337 cmd[2] = htonl(regno);
338 cmd[3] = htonl(value);
340 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
344 vrt::quadradio::set_hsadc_conf(int dboard_bitmask, int regno, int value)
347 cmd[0] = htonl(0); // verb: set
348 cmd[1] = htonl(3); // id: HSADC_CONF
349 cmd[2] = htonl(dboard_bitmask);
350 cmd[3] = htonl(regno);
351 cmd[4] = htonl(value);
353 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
357 vrt::quadradio::set_lsdac(int dboard_bitmask, int which_dac, int value)
360 cmd[0] = htonl(0); // verb: set
361 cmd[1] = htonl(4); // id: LSDAC
362 cmd[2] = htonl(dboard_bitmask);
363 cmd[3] = htonl(which_dac);
364 cmd[4] = htonl(value);
366 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
370 vrt::quadradio::set_mem32(int addr, int value)
373 cmd[0] = htonl(0); // verb: set
374 cmd[1] = htonl(5); // id: MEM32
375 cmd[2] = htonl(addr);
376 cmd[3] = htonl(value);
378 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
382 vrt::quadradio::set_lo_freq(double freq)
384 uint64_t lo_freq = uint64_t(freq * (uint64_t(1)<<20)); //q20 format
386 cmd[0] = htonl(0); // verb: set
387 cmd[1] = htonl(6); // id: lo freq
388 cmd[2] = htonl((lo_freq >> 32) & 0xffffffff);
389 cmd[3] = htonl((lo_freq >> 0) & 0xffffffff);
391 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
395 vrt::quadradio::set_cal_freq(double freq)
397 uint64_t cal_freq = uint64_t(freq * (uint64_t(1)<<20)); //q20 format
399 cmd[0] = htonl(0); // verb: set
400 cmd[1] = htonl(7); // id: cal freq
401 cmd[2] = htonl((cal_freq >> 32) & 0xffffffff);
402 cmd[3] = htonl((cal_freq >> 0) & 0xffffffff);
404 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
408 vrt::quadradio::set_beamforming(int32_t gains[8]){
410 cmd[0] = htonl(0); // verb: set
411 cmd[1] = htonl(8); // id: beamformin
412 for (int i = 0; i < 8; i++){
413 //printf("%d\n", gains[i]);
414 cmd[i+2] = htonl(gains[i]);
416 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
420 vrt::quadradio::set_cal_enb(bool enb)
423 cmd[0] = htonl(0); // verb: set
424 cmd[1] = htonl(9); // id: cal enb
427 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));