diff --git a/srslte/examples/usrp_txrx.c b/srslte/examples/usrp_txrx.c index 87d283800..668a3b56d 100644 --- a/srslte/examples/usrp_txrx.c +++ b/srslte/examples/usrp_txrx.c @@ -39,7 +39,8 @@ uint32_t nof_prb = 25; uint32_t nof_frames = 20; -float tone_offset_hz = 0; +int time_adv_samples = 0; +float tone_offset_hz = 1e6; float rf_rx_gain=40, rf_tx_gain=40, rf_freq=2.4e9; char *rf_args=""; char *output_filename = NULL; @@ -51,14 +52,15 @@ void usage(char *prog) { printf("\t-f RF TX/RX frequency [Default %.2f MHz]\n", rf_freq/1e6); printf("\t-g RF RX gain [Default %.1f dB]\n", rf_rx_gain); printf("\t-G RF TX gain [Default %.1f dB]\n", rf_tx_gain); - printf("\t-t Single tone offset (Hz) [Default %f]\n", tone_offset_hz); + printf("\t-t Single tone offset (Hz) [Default %f]\n", tone_offset_hz); + printf("\t-T Time advance samples [Default %d]\n", time_adv_samples); printf("\t-i File name to read signal from [Default single tone]\n"); printf("\t-p Number of UL RB [Default %d]\n", nof_prb); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "ioafgpt")) != -1) { + while ((opt = getopt(argc, argv, "ioafgGptT")) != -1) { switch (opt) { case 'a': rf_args = argv[optind]; @@ -72,6 +74,9 @@ void parse_args(int argc, char **argv) { case 't': tone_offset_hz = atof(argv[optind]); break; + case 'T': + time_adv_samples = atoi(argv[optind]); + break; case 'f': rf_freq = atof(argv[optind]); break; @@ -97,32 +102,38 @@ void parse_args(int argc, char **argv) { usage(argv[0]); exit(-1); } + if (time_adv_samples < 0) { + printf("Time advance must be positive\n"); + usage(argv[0]); + exit(-1); + } } int main(int argc, char **argv) { parse_args(argc, argv); uint32_t flen = srslte_sampling_freq_hz(nof_prb)/1000; - uint32_t nsamples_adv = 3000; - + cf_t *rx_buffer = malloc(sizeof(cf_t)*flen*nof_frames); if (!rx_buffer) { perror("malloc"); exit(-1); } - cf_t *tx_buffer = malloc(sizeof(cf_t)*(flen+nsamples_adv)); + cf_t *tx_buffer = malloc(sizeof(cf_t)*(flen+time_adv_samples)); if (!tx_buffer) { perror("malloc"); exit(-1); } - bzero(tx_buffer, sizeof(cf_t)*(flen+nsamples_adv)); + bzero(tx_buffer, sizeof(cf_t)*(flen+time_adv_samples)); cf_t *zeros = calloc(sizeof(cf_t),flen); if (!zeros) { perror("calloc"); exit(-1); } + + float time_adv_sec = (float) time_adv_samples/srslte_sampling_freq_hz(nof_prb); // Send through RF rf_t rf; @@ -141,20 +152,23 @@ int main(int argc, char **argv) { } rf_set_rx_srate(&rf, (double) srate); rf_set_tx_srate(&rf, (double) srate); - + + printf("Subframe len: %d samples\n", flen); + printf("Time advance: %f us\n",time_adv_sec*1e6); printf("Set TX/RX rate: %.2f MHz\n", (float) srate / 1000000); - printf("Set RX gain: %.1f dB\n", rf_set_rx_gain(&rf, rf_rx_gain)); - printf("Set TX gain: %.1f dB\n", rf_set_tx_gain(&rf, rf_tx_gain)); + printf("Set RX gain: %.1f dB\n", rf_set_rx_gain(&rf, rf_rx_gain)); + printf("Set TX gain: %.1f dB\n", rf_set_tx_gain(&rf, rf_tx_gain)); printf("Set TX/RX freq: %.2f MHz\n", rf_set_rx_freq(&rf, rf_freq) / 1000000); + rf_set_tx_freq(&rf, rf_freq); sleep(1); if (input_filename) { - srslte_vec_load_file(input_filename, &tx_buffer[nsamples_adv], flen*sizeof(cf_t)); + srslte_vec_load_file(input_filename, &tx_buffer[time_adv_samples], flen*sizeof(cf_t)); } else { - for (int i=0;idev, + BLADERF_MODULE_RX, + BLADERF_FORMAT_SC16_Q11_META, + num_buffers, + buffer_size_rx, + num_transfers, + timeout_ms); + if (status != 0) { + fprintf(stderr, "Failed to configure RX sync interface: %s\n", bladerf_strerror(status)); + return status; + } + status = bladerf_sync_config(handler->dev, + BLADERF_MODULE_TX, + BLADERF_FORMAT_SC16_Q11_META, + num_buffers, + buffer_size_tx, + num_transfers, + timeout_ms); + if (status != 0) { + fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); + return status; + } + status = bladerf_enable_module(handler->dev, BLADERF_MODULE_RX, true); + if (status != 0) { + fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); + return status; + } + status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, true); + if (status != 0) { + fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status)); + return status; + } + handler->stream_enabled = true; + return 0; } int rf_blade_stop_rx_stream(void *h) { + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + int status = bladerf_enable_module(handler->dev, BLADERF_MODULE_RX, false); + if (status != 0) { + fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); + return status; + } + status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, false); + if (status != 0) { + fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status)); + return status; + } + handler->stream_enabled = false; + return 0; } void rf_blade_flush_buffer(void *h) { } -bool rf_blade_has_rssi(void *h) { +bool rf_blade_has_rssi(void *h) +{ + return false; } -float rf_blade_get_rssi(void *h) { +float rf_blade_get_rssi(void *h) +{ + return 0; } double rf_blade_set_rx_gain_th(void *h, double gain) { + return rf_blade_set_rx_gain(h, gain); } -void rf_blade_set_tx_rx_gain_offset(void *h, double offset) { -} - -/* This thread listens for set_rx_gain commands to the USRP */ -static void* thread_gain_fcn(void *h) { +void rf_blade_set_tx_rx_gain_offset(void *h, double offset) +{ } int rf_blade_open(char *args, void **h, bool create_thread_gain, bool tx_gain_same_rx) { + *h = NULL; + + rf_blade_handler_t *handler = (rf_blade_handler_t*) malloc(sizeof(rf_blade_handler_t)); + if (!handler) { + perror("malloc"); + return -1; + } + *h = handler; + + printf("Opening bladeRF...\n"); + int status = bladerf_open(&handler->dev, NULL); + if (status) { + fprintf(stderr, "Unable to open device: %s\n", bladerf_strerror(status)); + return status; + } + + //bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_VERBOSE); + + /* Configure the gains of the RX LNA and RX VGA1*/ + status = bladerf_set_lna_gain(handler->dev, BLADERF_LNA_GAIN_MAX); + if (status != 0) { + fprintf(stderr, "Failed to set RX LNA gain: %s\n", bladerf_strerror(status)); + return status; + } + status = bladerf_set_rxvga1(handler->dev, 25); + if (status != 0) { + fprintf(stderr, "Failed to set RX VGA1 gain: %s\n", bladerf_strerror(status)); + return status; + } + status = bladerf_set_txvga1(handler->dev, -10); + if (status != 0) { + fprintf(stderr, "Failed to set TX VGA1 gain: %s\n", bladerf_strerror(status)); + return status; + } + handler->stream_enabled = false; + return 0; } int rf_blade_close(void *h) { + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + bladerf_close(handler->dev); + return 0; } -void rf_blade_set_master_clock_rate(void *h, double rate) { +void rf_blade_set_master_clock_rate(void *h, double rate) +{ } -bool rf_blade_is_master_clock_dynamic(void *h) { +bool rf_blade_is_master_clock_dynamic(void *h) +{ + return true; } double rf_blade_set_rx_srate(void *h, double freq) { + uint32_t bw; + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + int status = bladerf_set_sample_rate(handler->dev, BLADERF_MODULE_RX, (uint32_t) freq, &handler->rx_rate); + if (status != 0) { + fprintf(stderr, "Failed to set samplerate = %u: %s\n", (uint32_t) freq, bladerf_strerror(status)); + return -1; + } + status = bladerf_set_bandwidth(handler->dev, BLADERF_MODULE_RX, handler->rx_rate, &bw); + if (status != 0) { + fprintf(stderr, "Failed to set bandwidth = %u: %s\n", handler->rx_rate, bladerf_strerror(status)); + return -1; + } + return (double) handler->rx_rate; } double rf_blade_set_tx_srate(void *h, double freq) { + uint32_t bw; + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + int status = bladerf_set_sample_rate(handler->dev, BLADERF_MODULE_TX, (uint32_t) freq, &handler->tx_rate); + if (status != 0) { + fprintf(stderr, "Failed to set samplerate = %u: %s\n", (uint32_t) freq, bladerf_strerror(status)); + return -1; + } + status = bladerf_set_bandwidth(handler->dev, BLADERF_MODULE_TX, handler->tx_rate, &bw); + if (status != 0) { + fprintf(stderr, "Failed to set bandwidth = %u: %s\n", handler->tx_rate, bladerf_strerror(status)); + return -1; + } + return (double) handler->tx_rate; } double rf_blade_set_rx_gain(void *h, double gain) { + int status; + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + status = bladerf_set_rxvga2(handler->dev, (int) gain); + if (status != 0) { + fprintf(stderr, "Failed to set RX VGA2 gain: %s\n", bladerf_strerror(status)); + return -1; + } + return rf_blade_get_rx_gain(h); } double rf_blade_set_tx_gain(void *h, double gain) { + int status; + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + status = bladerf_set_txvga2(handler->dev, (int) gain); + if (status != 0) { + fprintf(stderr, "Failed to set TX VGA2 gain: %s\n", bladerf_strerror(status)); + return -1; + } + return rf_blade_get_tx_gain(h); } double rf_blade_get_rx_gain(void *h) { + int status; + int gain; + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + status = bladerf_get_rxvga2(handler->dev, &gain); + if (status != 0) { + fprintf(stderr, "Failed to get RX VGA2 gain: %s\n", + bladerf_strerror(status)); + return -1; + } + return gain; } double rf_blade_get_tx_gain(void *h) { + int status; + int gain; + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + status = bladerf_get_txvga2(handler->dev, &gain); + if (status != 0) { + fprintf(stderr, "Failed to get TX VGA2 gain: %s\n", + bladerf_strerror(status)); + return -1; + } + return gain; } double rf_blade_set_rx_freq(void *h, double freq) { + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + int status = bladerf_set_frequency(handler->dev, BLADERF_MODULE_RX, (uint32_t) freq); + if (status != 0) { + fprintf(stderr, "Failed to set samplerate = %u: %s\n", + (uint32_t) freq, bladerf_strerror(status)); + return -1; + } + return freq; } double rf_blade_set_tx_freq(void *h, double freq) { + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + int status = bladerf_set_frequency(handler->dev, BLADERF_MODULE_TX, (uint32_t) freq); + if (status != 0) { + fprintf(stderr, "Failed to set samplerate = %u: %s\n", + (uint32_t) freq, bladerf_strerror(status)); + return -1; + } + + /* Apply manual IQ correction for 2.5-2.6G */ + if (freq > 2.5e9 && freq < 2.6e9) { + bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_FPGA_PHASE, 184); + bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_FPGA_GAIN, 20); + } + + return freq; } +static void timestamp_to_secs(uint32_t rate, uint64_t timestamp, time_t *secs, double *frac_secs) { + double totalsecs = (double) timestamp/rate; + time_t secs_i = (time_t) totalsecs; + if (secs) { + *secs = secs_i; + } + if (frac_secs) { + *frac_secs = totalsecs-secs_i; + } +} -void rf_blade_get_time(void *h, time_t *secs, double *frac_secs) { +static void secs_to_timestamps(uint32_t rate, time_t secs, double frac_secs, uint64_t *timestamp) { + double totalsecs = (double) secs + frac_secs; + if (timestamp) { + *timestamp = rate * totalsecs; + } +} + +void rf_blade_get_time(void *h, time_t *secs, double *frac_secs) +{ + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + struct bladerf_metadata meta; + + int status = bladerf_get_timestamp(handler->dev, BLADERF_MODULE_RX, &meta.timestamp); + if (status != 0) { + fprintf(stderr, "Failed to get current RX timestamp: %s\n", + bladerf_strerror(status)); + } + timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs); } int rf_blade_recv_with_time(void *h, @@ -137,6 +362,35 @@ int rf_blade_recv_with_time(void *h, time_t *secs, double *frac_secs) { + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + struct bladerf_metadata meta; + int status; + + memset(&meta, 0, sizeof(meta)); + meta.flags = BLADERF_META_FLAG_RX_NOW; + + if (2*nsamples > CONVERT_BUFFER_SIZE) { + fprintf(stderr, "RX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); + return -1; + } + status = bladerf_sync_rx(handler->dev, handler->rx_buffer, nsamples, &meta, 0); + if (status) { + fprintf(stderr, "RX failed: %s\n\n", bladerf_strerror(status)); + exit(-1); + return -1; + } else if (meta.status & BLADERF_META_STATUS_OVERRUN) { + fprintf(stderr, "Overrun detected in scheduled RX. " + "%u valid samples were read.\n\n", meta.actual_count); + } + + timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs); + uint64_t rx_timestamp, rx_timestamp2, tx_timestamp; + bladerf_get_timestamp(handler->dev, BLADERF_MODULE_RX, &rx_timestamp); + bladerf_get_timestamp(handler->dev, BLADERF_MODULE_RX, &rx_timestamp2); + bladerf_get_timestamp(handler->dev, BLADERF_MODULE_TX, &tx_timestamp); + srslte_vec_convert_if(handler->rx_buffer, data, 2048, 2*nsamples); + + return nsamples; } int rf_blade_send_timed(void *h, @@ -149,5 +403,40 @@ int rf_blade_send_timed(void *h, bool is_start_of_burst, bool is_end_of_burst) { + rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + struct bladerf_metadata meta; + int status; + + if (2*nsamples > CONVERT_BUFFER_SIZE) { + fprintf(stderr, "TX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); + return -1; + } + + srslte_vec_convert_fi(data, handler->tx_buffer, 2048, 2*nsamples); + + memset(&meta, 0, sizeof(meta)); + if (is_start_of_burst) { + if (has_time_spec) { + secs_to_timestamps(handler->tx_rate, secs, frac_secs, &meta.timestamp); + } else { + meta.flags |= BLADERF_META_FLAG_TX_NOW; + } + meta.flags |= BLADERF_META_FLAG_TX_BURST_START; + } + if (is_end_of_burst) { + meta.flags |= BLADERF_META_FLAG_TX_BURST_END; + } + uint64_t dev_timestamp; + status = bladerf_get_timestamp(handler->dev, BLADERF_MODULE_TX, &dev_timestamp); + if (status != 0) { + fprintf(stderr, "Failed to get current RX timestamp: %s\n", + bladerf_strerror(status)); + } + status = bladerf_sync_tx(handler->dev, handler->tx_buffer, nsamples, &meta, 0); + if (status != 0) { + fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); + return status; + } + return nsamples; } diff --git a/srslte/lib/utils/src/vector.c b/srslte/lib/utils/src/vector.c index 2071d5265..d826f0164 100644 --- a/srslte/lib/utils/src/vector.c +++ b/srslte/lib/utils/src/vector.c @@ -241,7 +241,7 @@ void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len) { #ifndef HAVE_VOLK_CONVERT_IF_FUNCTION int i; for (i=0;i