From 3405a1bff655d9c9fd0fe054743ba3e9388075c9 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 19 Mar 2019 20:58:44 +0100 Subject: [PATCH] add multi-channel support for soapy --- lib/src/phy/rf/rf_soapy_imp.c | 256 ++++++++++++++++++---------------- lib/src/phy/rf/rf_soapy_imp.h | 4 +- 2 files changed, 136 insertions(+), 124 deletions(-) diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 05aa5e541..b0c3d5e69 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -48,9 +48,6 @@ #define PRINT_RX_STATS 0 #define PRINT_TX_STATS 0 -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - typedef struct { char *devname; SoapySDRKwargs args; @@ -63,6 +60,8 @@ typedef struct { srslte_rf_info_t info; double tx_rate; size_t rx_mtu, tx_mtu; + size_t num_rx_channels; + size_t num_tx_channels; srslte_rf_error_handler_t soapy_error_handler; @@ -191,7 +190,7 @@ void rf_soapy_register_error_handler(void *h, srslte_rf_error_handler_t new_hand char* rf_soapy_devname(void* h) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - return handler->devname; + return handler->devname; } @@ -224,7 +223,7 @@ int rf_soapy_start_rx_stream(void *h, bool now) if(SoapySDRDevice_activateStream(handler->device, handler->rxStream, SOAPY_SDR_HAS_TIME | SOAPY_SDR_END_BURST, 0, 0) != 0) return SRSLTE_ERROR; handler->rx_stream_active = true; - } + } return SRSLTE_SUCCESS; } @@ -235,8 +234,8 @@ int rf_soapy_start_tx_stream(void *h) if(handler->tx_stream_active == false){ if(SoapySDRDevice_activateStream(handler->device, handler->txStream, 0, 0, 0) != 0) return SRSLTE_ERROR; - handler->tx_stream_active = true; - } + handler->tx_stream_active = true; + } return SRSLTE_SUCCESS; } @@ -246,7 +245,7 @@ int rf_soapy_stop_rx_stream(void *h) rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; if (SoapySDRDevice_deactivateStream(handler->device, handler->rxStream, 0, 0) != 0) return SRSLTE_ERROR; - + handler->rx_stream_active = false; return SRSLTE_SUCCESS; } @@ -288,13 +287,11 @@ float rf_soapy_get_rssi(void *h) return 0.0; } - -//TODO: add multi-channel support -int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) +int rf_soapy_open_multi(char* args, void** h, uint32_t num_requested_channels) { size_t length; const SoapySDRKwargs *soapy_args = SoapySDRDevice_enumerate(NULL, &length); - + if (length == 0) { printf("No Soapy devices found.\n"); return SRSLTE_ERROR; @@ -312,13 +309,13 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) } printf("\n"); } - + SoapySDRDevice *sdr = SoapySDRDevice_make(&(soapy_args[0])); if (sdr == NULL) { printf("Failed to create Soapy object\n"); return SRSLTE_ERROR; } - + // create handler rf_soapy_handler_t *handler = (rf_soapy_handler_t*) malloc(sizeof(rf_soapy_handler_t)); bzero(handler, sizeof(rf_soapy_handler_t)); @@ -328,38 +325,44 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) handler->rx_stream_active = false; handler->devname = devname; - // init rx/tx rate to lowest LTE rate to avoid decimation warnings - rf_soapy_set_rx_srate(handler, 1.92e6); - rf_soapy_set_tx_srate(handler, 1.92e6); - - size_t channels = SoapySDRDevice_getNumChannels(handler->device, SOAPY_SDR_RX); - - if((channels > 0) && (nof_rx_antennas > 0)){ - printf("Setting up RX stream\n"); - size_t numChannels = channels; - if (channels > nof_rx_antennas) { - numChannels = nof_rx_antennas; - } - size_t rx_channels[numChannels]; - for(int i = 0 ; i < numChannels ; i++) { + // Setup Rx streamer + size_t num_available_channels = SoapySDRDevice_getNumChannels(handler->device, SOAPY_SDR_RX); + if ((num_available_channels > 0) && (num_requested_channels > 0)) { + handler->num_rx_channels = SRSLTE_MIN(num_available_channels, num_requested_channels); + size_t rx_channels[handler->num_rx_channels]; + for (int i = 0; i < handler->num_rx_channels; i++) { rx_channels[i] = i; } - if(SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, rx_channels, numChannels, NULL) != 0) { + printf("Setting up Rx stream with %zd channel(s)\n", handler->num_rx_channels); + if (SoapySDRDevice_setupStream(handler->device, &handler->rxStream, SOAPY_SDR_RX, SOAPY_SDR_CF32, rx_channels, + handler->num_rx_channels, NULL) != 0) { printf("Rx setupStream fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } handler->rx_mtu = SoapySDRDevice_getStreamMTU(handler->device, handler->rxStream); } - if(SoapySDRDevice_getNumChannels(handler->device, SOAPY_SDR_TX) > 0){ - printf("Setting up TX stream\n"); - if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { + // Setup Tx streamer + num_available_channels = SoapySDRDevice_getNumChannels(handler->device, SOAPY_SDR_TX); + if ((num_available_channels > 0) && (num_requested_channels > 0)) { + handler->num_tx_channels = SRSLTE_MIN(num_available_channels, num_requested_channels); + size_t tx_channels[handler->num_tx_channels]; + for (int i = 0; i < handler->num_tx_channels; i++) { + tx_channels[i] = i; + } + printf("Setting up Tx stream with %zd channel(s)\n", handler->num_tx_channels); + if (SoapySDRDevice_setupStream(handler->device, &handler->txStream, SOAPY_SDR_TX, SOAPY_SDR_CF32, tx_channels, + handler->num_tx_channels, NULL) != 0) { printf("Tx setupStream fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } handler->tx_mtu = SoapySDRDevice_getStreamMTU(handler->device, handler->txStream); } + // init rx/tx rate to lowest LTE rate to avoid decimation warnings + rf_soapy_set_rx_srate(handler, 1.92e6); + rf_soapy_set_tx_srate(handler, 1.92e6); + // list device sensors size_t list_length; char** list; @@ -370,10 +373,12 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) } // list channel sensors - list = SoapySDRDevice_listChannelSensors(handler->device, SOAPY_SDR_RX, 0, &list_length); - printf("Available sensors for RX channel 0: \n"); - for(int i = 0; i < list_length; i++) { - printf(" - %s\n", list[i]); + for (uint32_t i = 0; i < handler->num_rx_channels; ++i) { + list = SoapySDRDevice_listChannelSensors(handler->device, SOAPY_SDR_RX, i, &list_length); + printf("Available sensors for Rx channel %d: \n", i); + for (int i = 0; i < list_length; i++) { + printf(" - %s\n", list[i]); + } } // Set static radio info @@ -444,8 +449,8 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) bool start_async_thread = true; if (args) { if (strstr(args, "silent")) { - REMOVE_SUBSTRING_WITHCOMAS(args, "silent"); - start_async_thread = false; + REMOVE_SUBSTRING_WITHCOMAS(args, "silent"); + start_async_thread = false; } } #endif @@ -458,7 +463,9 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) cf_t dummy_buffer[1920]; cf_t *dummy_buffer_array[SRSLTE_MAX_PORTS]; - dummy_buffer_array[0] = dummy_buffer; + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + dummy_buffer_array[i] = dummy_buffer; + } rf_soapy_start_rx_stream(handler, true); rf_soapy_recv_with_time_multi(handler, (void**)dummy_buffer_array, 1920, false, NULL, NULL); rf_soapy_stop_rx_stream(handler); @@ -523,7 +530,7 @@ int rf_soapy_close(void *h) rf_soapy_stop_tx_stream(handler); SoapySDRDevice_closeStream(handler->device, handler->txStream); } - + if (handler->rx_stream_active) { rf_soapy_stop_rx_stream(handler); SoapySDRDevice_closeStream(handler->device, handler->rxStream); @@ -570,31 +577,34 @@ double rf_soapy_set_rx_srate(void *h, double rate) rf_soapy_stop_rx_stream(handler); } - if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { - printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; - } + for (uint32_t i = 0; i < handler->num_rx_channels; i++) { + if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, i, rate) != 0) { + printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } #if SET_RF_BW - // Set bandwidth close to current rate - size_t bw_length; - SoapySDRRange *bw_range = SoapySDRDevice_getBandwidthRange(handler->device, SOAPY_SDR_RX, 0, &bw_length); - double bw = rate * 0.75; - bw = MIN(bw, bw_range->maximum); - bw = MAX(bw, bw_range->minimum); - bw = MAX(bw, 2.5e6); // For the Lime to avoid warnings - if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_RX, 0, bw) != 0) { - printf("setBandwidth fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; - } - printf("Set Rx bandwidth to %.2f MHz\n", SoapySDRDevice_getBandwidth(handler->device, SOAPY_SDR_RX, 0)/1e6); + // Set bandwidth close to current rate + size_t bw_length; + SoapySDRRange* bw_range = SoapySDRDevice_getBandwidthRange(handler->device, SOAPY_SDR_RX, 0, &bw_length); + double bw = rate * 0.75; + bw = SRSLTE_MIN(bw, bw_range->maximum); + bw = SRSLTE_MAX(bw, bw_range->minimum); + bw = SRSLTE_MAX(bw, 2.5e6); // For the Lime to avoid warnings + if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_RX, i, bw) != 0) { + printf("setBandwidth fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + printf("Set Rx bandwidth to %.2f MHz\n", SoapySDRDevice_getBandwidth(handler->device, SOAPY_SDR_RX, i) / 1e6); #endif + } if (rx_stream_active) { rf_soapy_start_rx_stream(handler, true); } - return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0); + // retrun sample rate of first channel + return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX, 0); } double rf_soapy_set_tx_srate(void *h, double rate) @@ -607,30 +617,33 @@ double rf_soapy_set_tx_srate(void *h, double rate) rf_soapy_stop_rx_stream(handler); } - if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { - printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; - } + for (uint32_t i = 0; i < handler->num_tx_channels; i++) { + if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, i, rate) != 0) { + printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } #if SET_RF_BW - size_t bw_length; - SoapySDRRange *bw_range = SoapySDRDevice_getBandwidthRange(handler->device, SOAPY_SDR_TX, 0, &bw_length); - // try to set the BW a bit narrower than sampling rate to prevent aliasing but make sure to stay within device boundaries - double bw = rate * 0.75; - bw = MAX(bw, bw_range->minimum); - bw = MIN(bw, bw_range->maximum); - if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_TX, 0, bw) != 0) { - printf("setBandwidth fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; - } - printf("Set Tx bandwidth to %.2f MHz\n", SoapySDRDevice_getBandwidth(handler->device, SOAPY_SDR_TX, 0)/1e6); + size_t bw_length; + SoapySDRRange* bw_range = SoapySDRDevice_getBandwidthRange(handler->device, SOAPY_SDR_TX, i, &bw_length); + // try to set the BW a bit narrower than sampling rate to prevent aliasing but make sure to stay within device + // boundaries + double bw = rate * 0.75; + bw = SRSLTE_MAX(bw, bw_range->minimum); + bw = SRSLTE_MIN(bw, bw_range->maximum); + if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_TX, i, bw) != 0) { + printf("setBandwidth fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + printf("Set Tx bandwidth to %.2f MHz\n", SoapySDRDevice_getBandwidth(handler->device, SOAPY_SDR_TX, i) / 1e6); #endif - + } if (rx_stream_active) { rf_soapy_start_rx_stream(handler, true); } handler->tx_rate = SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX, 0); + return handler->tx_rate; } @@ -638,10 +651,12 @@ double rf_soapy_set_tx_srate(void *h, double rate) double rf_soapy_set_rx_gain(void *h, double gain) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_RX, 0, gain) != 0) - { - printf("setGain fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; + + for (uint32_t i = 0; i < handler->num_rx_channels; i++) { + if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_RX, i, gain) != 0) { + printf("setGain fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } } return rf_soapy_get_rx_gain(h); } @@ -650,22 +665,23 @@ double rf_soapy_set_rx_gain(void *h, double gain) double rf_soapy_set_tx_gain(void *h, double gain) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_TX, 0, gain) != 0) - { - printf("setGain fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; + for (uint32_t i = 0; i < handler->num_tx_channels; i++) { + if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_TX, i, gain) != 0) { + printf("setGain fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } } return rf_soapy_get_tx_gain(h); } - +// Return gain of first channel double rf_soapy_get_rx_gain(void *h) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; return SoapySDRDevice_getGain(handler->device, SOAPY_SDR_RX, 0); } - +// Return gain of first channel double rf_soapy_get_tx_gain(void *h) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; @@ -687,30 +703,30 @@ srslte_rf_info_t * rf_soapy_get_info(void *h) double rf_soapy_set_rx_freq(void *h, double freq) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_RX, 0, freq, NULL) != 0) - { - printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; + + for (uint32_t i = 0; i < handler->num_rx_channels; i++) { + if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_RX, i, freq, NULL) != 0) { + printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } } - printf("Tuned Rx to %.2f MHz\n", SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0)/1e6); // wait until LO is locked rf_soapy_rx_wait_lo_locked(handler); + // Return actual frequency for channel 0 return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0); } double rf_soapy_set_tx_freq(void *h, double freq) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_TX, 0, freq, NULL) != 0) - { - printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; + for (uint32_t i = 0; i < handler->num_tx_channels; i++) { + if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_TX, i, freq, NULL) != 0) { + printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } } - - printf("Tuned Tx to %.2f MHz\n", SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0)/1e6); - return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0); } @@ -730,10 +746,9 @@ int rf_soapy_recv_with_time_multi(void *h, double *frac_secs) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - int flags; //flags set by receive operation - int num_channels = 1; // temp + int flags = 0; // flags set by receive operation const long timeoutUs = 400000; // arbitrarily chosen - + int trials = 0; int ret = 0; long long timeNs; //timestamp for receive buffer @@ -744,13 +759,13 @@ int rf_soapy_recv_with_time_multi(void *h, #endif do { - size_t rx_samples = MIN(nsamples - n, handler->rx_mtu); + size_t rx_samples = SRSLTE_MIN(nsamples - n, handler->rx_mtu); #if PRINT_RX_STATS printf(" - rx_samples=%zd\n", rx_samples); #endif - void *buffs_ptr[4]; - for (int i=0; itx_mtu); + size_t tx_samples = SRSLTE_MIN(nsamples - n, handler->tx_mtu); #else size_t tx_samples = nsamples; if (tx_samples > nsamples - n) { diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index da4143e76..de8242501 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -35,9 +35,7 @@ SRSLTE_API int rf_soapy_open(char *args, void **handler); -SRSLTE_API int rf_soapy_open_multi(char *args, - void **handler, - uint32_t nof_rx_antennas); +SRSLTE_API int rf_soapy_open_multi(char* args, void** handler, uint32_t num_requested_channels); SRSLTE_API char* rf_soapy_devname(void *h);