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(0), 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 return send_rx_command(d_ctrl_fd, true, d_ctrl_port_inaddr,
80 d_data_port, samples_per_pkt, 0);
84 vrt::quadradio::stop_streaming()
86 return send_stop_rx_command(d_ctrl_fd);
90 vrt::quadradio::set_center_freq(double target_freq){
91 if (target_freq < 700e6) return false;
92 if (target_freq <= 1.0e9) return set_band_select("A");
93 if (target_freq <= 1.5e9) return set_band_select("B");
94 if (target_freq <= 2.2e9) return set_band_select("C");
95 if (target_freq <= 3.0e9) return set_band_select("D");
100 vrt::quadradio::set_band_select(const std::string &band){
101 if (band == "A") d_band_select = 3;
102 else if (band == "B") d_band_select = 2;
103 else if (band == "C") d_band_select = 1;
104 else if (band == "D") d_band_select = 0;
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){
153 ((reverse_bits(d_attenuation0, 5) & 0x1f) << 10) | \
154 ((reverse_bits(~d_attenuation1, 5) & 0x1f) << 03) | \
155 ((d_band_select & 0x03) << 01) | \
156 ((d_rx_antenna & 0x01) << 00);
157 set_dboard_pins(ALL_DBOARDS, db_ctrl); // FIXME sets them all
161 vrt::quadradio::set_adc_gain(bool on){
162 set_hsadc_conf(ALL_DBOARDS, 0x14, on ? 0x90 : 0x80);
166 vrt::quadradio::set_dc_offset_comp(bool on){
168 set_hsadc_conf(ALL_DBOARDS, 0x1B, 0x80);
169 set_hsadc_conf(ALL_DBOARDS, 0x1A, 0x00); //bits 6:4 set time constant
171 else set_hsadc_conf(ALL_DBOARDS, 0x1B, 0x00);
175 vrt::quadradio::set_digital_gain(float gain){
176 int gain_q1 = static_cast<int>(round(gain*2.0));
177 set_hsadc_conf(ALL_DBOARDS, 0x17, gain_q1);
181 vrt::quadradio::set_test_signal(vrt_test_sig_t type){
182 set_hsadc_conf(ALL_DBOARDS, 0x16, type);
186 vrt::quadradio::open_sockets(const char *quad_radio_ip, int quad_radio_ctrl_port,
187 int *ctrl_fd_ptr, struct in_addr *ctrl_port_inaddr,
188 int *data_fd_ptr, int *data_port_ptr)
190 int ctrl_fd; // socket for control
191 int data_fd; // socket fd for data
192 int data_port; // our port number
195 // create a udp socket and connect it to the quad radio control port
198 ctrl_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
200 perror("socket: ctrl_fd");
204 struct sockaddr_in si_other;
205 memset(&si_other, 0, sizeof(si_other));
206 si_other.sin_family = AF_INET;
207 si_other.sin_port = htons(quad_radio_ctrl_port);
208 if (inet_pton(AF_INET, quad_radio_ip, &si_other.sin_addr) <= 0){
213 if (connect(ctrl_fd, (struct sockaddr *) &si_other, sizeof(si_other)) != 0){
218 // get our ip address associated with the interface connected to the control port
220 struct sockaddr_in si_me;
221 memset(&si_me, 0, sizeof(si_me));
222 socklen_t sockname_len = sizeof(si_me);
223 if (getsockname(ctrl_fd, (struct sockaddr *) &si_me, &sockname_len) != 0){
224 perror("getsockname");
227 *ctrl_port_inaddr = si_me.sin_addr;
231 const char *s = inet_ntop(si_me.sin_family, &si_me.sin_addr, buf, sizeof(buf));
236 // printf("our ip addr associated with ctrl port: %s\n", s);
240 // create a udp socket to use to receive data
243 data_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
245 perror("socket: data_fd");
249 // bind it to a local port on the interface that connects to the ctrl port.
250 // FIXME this assumes that interface connected to the control port and the
251 // interface connected to the data port are the same. If we're using
252 // both ethernet ports on the quad radio, this may not be the case.
255 for (int port = MIN_IP_LOCAL_PORT; port <= MAX_IP_LOCAL_PORT; port++){
256 struct sockaddr_in si_me;
257 memset(&si_me, 0, sizeof(si_me));
258 si_me.sin_family = AF_INET;
259 si_me.sin_port = htons(port);
260 si_me.sin_addr.s_addr = htonl(INADDR_ANY);
262 if (bind(data_fd, (struct sockaddr *) &si_me, sizeof(si_me)) == 0){ // found one!
268 if (data_port == -1){
269 fprintf(stderr, "failed to bind to a local port\n");
273 // printf("our data port = %d\n", data_port);
275 *ctrl_fd_ptr = ctrl_fd;
276 *data_fd_ptr = data_fd;
277 *data_port_ptr = data_port;
282 // ------------------------------------------------------------------------
285 vrt::quadradio::send_rx_command(int ctrl_fd, bool start,
286 struct in_addr addr, int data_port,
287 int samples_per_pkt, int siggen_param)
290 cmd[0] = htonl(0); // verb: set
291 cmd[1] = htonl(0); // id: rx_streaming
292 cmd[2] = htonl(start ? 1: 0); // start or stop?
293 cmd[3] = addr.s_addr; // ip address to send data to (already network endian)
294 cmd[4] = htonl(data_port); // port to send data to
295 cmd[5] = htonl(samples_per_pkt);
296 cmd[6] = htonl(siggen_param);
298 return send_and_check(ctrl_fd, cmd, sizeof(cmd));
302 vrt::quadradio::send_stop_rx_command(int ctrl_fd)
304 struct in_addr in_addr;
306 return send_rx_command(ctrl_fd, false, in_addr, 0, 0, 0);
310 vrt::quadradio::set_dboard_pins(int dboard_bitmask, int v)
313 cmd[0] = htonl(0); // verb: set
314 cmd[1] = htonl(1); // id: dboard_pins
315 cmd[2] = htonl(dboard_bitmask);
316 cmd[3] = htonl(v); // value
318 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
322 vrt::quadradio::set_setting_reg(int regno, int value)
325 cmd[0] = htonl(0); // verb: set
326 cmd[1] = htonl(2); // id: SR
327 cmd[2] = htonl(regno);
328 cmd[3] = htonl(value);
330 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
334 vrt::quadradio::set_hsadc_conf(int dboard_bitmask, int regno, int value)
337 cmd[0] = htonl(0); // verb: set
338 cmd[1] = htonl(3); // id: HSADC_CONF
339 cmd[2] = htonl(dboard_bitmask);
340 cmd[3] = htonl(regno);
341 cmd[4] = htonl(value);
343 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
347 vrt::quadradio::set_lsdac(int dboard_bitmask, int which_dac, int value)
350 cmd[0] = htonl(0); // verb: set
351 cmd[1] = htonl(4); // id: LSDAC
352 cmd[2] = htonl(dboard_bitmask);
353 cmd[3] = htonl(which_dac);
354 cmd[4] = htonl(value);
356 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
360 vrt::quadradio::set_mem32(int addr, int value)
363 cmd[0] = htonl(0); // verb: set
364 cmd[1] = htonl(5); // id: MEM32
365 cmd[2] = htonl(addr);
366 cmd[3] = htonl(value);
368 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
372 vrt::quadradio::set_lo_freq(double freq)
374 uint64_t lo_freq = uint64_t(freq * (uint64_t(1)<<20)); //q20 format
376 cmd[0] = htonl(0); // verb: set
377 cmd[1] = htonl(6); // id: lo freq
378 cmd[2] = htonl((lo_freq >> 32) & 0xffffffff);
379 cmd[3] = htonl((lo_freq >> 0) & 0xffffffff);
381 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
385 vrt::quadradio::set_cal_freq(double freq)
387 uint64_t cal_freq = uint64_t(freq * (uint64_t(1)<<20)); //q20 format
389 cmd[0] = htonl(0); // verb: set
390 cmd[1] = htonl(7); // id: cal freq
391 cmd[2] = htonl((cal_freq >> 32) & 0xffffffff);
392 cmd[3] = htonl((cal_freq >> 0) & 0xffffffff);
394 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));
398 vrt::quadradio::set_beamforming(int32_t gains[8]){
400 cmd[0] = htonl(0); // verb: set
401 cmd[1] = htonl(8); // id: beamformin
402 for (int i = 0; i < 8; i++){
403 //printf("%d\n", gains[i]);
404 cmd[i+2] = htonl(gains[i]);
406 return send_and_check(d_ctrl_fd, cmd, sizeof(cmd));