Merge branch 'next' of github.com:softwareradiosystems/srsLTE into next

master
Ismael Gomez 7 years ago
commit c04c147451

@ -599,7 +599,7 @@ int main(int argc, char **argv) {
} }
#ifndef DISABLE_RF #ifndef DISABLE_RF
if (prog_args.rf_gain < 0) { if (prog_args.rf_gain < 0 && !prog_args.input_file_name) {
srslte_rf_info_t *rf_info = srslte_rf_get_info(&rf); srslte_rf_info_t *rf_info = srslte_rf_get_info(&rf);
srslte_ue_sync_start_agc(&ue_sync, srslte_ue_sync_start_agc(&ue_sync,
srslte_rf_set_rx_gain_th_wrapper_, srslte_rf_set_rx_gain_th_wrapper_,

@ -43,7 +43,7 @@
#define SRSLTE_CQI_MAX_BITS 64 #define SRSLTE_CQI_MAX_BITS 64
#define SRSLTE_DIF_CQI_MAX_BITS 3 #define SRSLTE_DIF_CQI_MAX_BITS 3
#define SRSLTE_PMI_MAX_BITS 4 #define SRSLTE_PMI_MAX_BITS 4
#define SRSLTE_CQI_STR_MAX_CHAR 32 #define SRSLTE_CQI_STR_MAX_CHAR 64
typedef struct { typedef struct {
bool configured; bool configured;
@ -150,6 +150,9 @@ SRSLTE_API int srslte_cqi_format2_subband_pack(srslte_cqi_format2_subband_t *msg
SRSLTE_API int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], SRSLTE_API int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS],
srslte_cqi_value_t *value); srslte_cqi_value_t *value);
SRSLTE_API int srslte_cqi_value_tostring(srslte_cqi_value_t *value, char *buff, uint32_t buff_len);
SRSLTE_API int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], SRSLTE_API int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS],
srslte_cqi_hl_subband_t *msg); srslte_cqi_hl_subband_t *msg);

@ -45,7 +45,8 @@ namespace srslte {
class radio_multi : public radio class radio_multi : public radio
{ {
public: public:
radio_multi() {}
~radio_multi() {}
bool init_multi(uint32_t nof_rx_antennas, char *args = NULL, char *devname = NULL); bool init_multi(uint32_t nof_rx_antennas, char *args = NULL, char *devname = NULL);
bool rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time); bool rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
}; };

File diff suppressed because it is too large Load Diff

@ -81,7 +81,6 @@ thread_pool::thread_pool(uint32_t max_workers_) :
status(max_workers_), status(max_workers_),
cvar(max_workers_), cvar(max_workers_),
mutex(max_workers_) mutex(max_workers_)
{ {
max_workers = max_workers_; max_workers = max_workers_;
for (uint32_t i=0;i<max_workers;i++) { for (uint32_t i=0;i<max_workers;i++) {

@ -388,7 +388,7 @@ void srslte_enb_dl_put_mbsfn_base(srslte_enb_dl_t *q, uint32_t tti)
void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q) void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q)
{ {
// TODO: PAPR control // TODO: PAPR control
float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft[0].symbol_sz); float norm_factor = 0.05f / sqrt(q->cell.nof_prb);
for (int i = 0; i < q->cell.nof_ports; i++) { for (int i = 0; i < q->cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&q->ifft[i]); srslte_ofdm_tx_sf(&q->ifft[i]);
srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
@ -397,7 +397,7 @@ void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q)
void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q) void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q)
{ {
float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft_mbsfn.symbol_sz); float norm_factor = 0.05f / sqrt(q->cell.nof_prb);
srslte_ofdm_tx_sf(&q->ifft_mbsfn); srslte_ofdm_tx_sf(&q->ifft_mbsfn);
srslte_vec_sc_prod_cfc(q->ifft_mbsfn.out_buffer, norm_factor, q->ifft_mbsfn.out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); srslte_vec_sc_prod_cfc(q->ifft_mbsfn.out_buffer, norm_factor, q->ifft_mbsfn.out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
} }
@ -416,7 +416,7 @@ int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant,
srslte_dci_format_t format, srslte_dci_location_t location, srslte_dci_format_t format, srslte_dci_location_t location,
uint16_t rnti, uint32_t sf_idx) uint16_t rnti, uint32_t sf_idx)
{ {
srslte_dci_msg_t dci_msg; srslte_dci_msg_t dci_msg = {};
bool rnti_is_user = true; bool rnti_is_user = true;
if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) { if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) {
@ -436,7 +436,7 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant,
srslte_dci_location_t location, srslte_dci_location_t location,
uint16_t rnti, uint32_t sf_idx) uint16_t rnti, uint32_t sf_idx)
{ {
srslte_dci_msg_t dci_msg; srslte_dci_msg_t dci_msg = {};
srslte_dci_msg_pack_pusch(grant, &dci_msg, q->cell.nof_prb); srslte_dci_msg_pack_pusch(grant, &dci_msg, q->cell.nof_prb);
if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) { if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) {

@ -234,6 +234,87 @@ int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_
return -1; return -1;
} }
/*******************************************************
* TO STRING FUNCTIONS *
*******************************************************/
static int srslte_cqi_format2_wideband_tostring(srslte_cqi_format2_wideband_t *msg, char *buff, uint32_t buff_len) {
int n = 0;
n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->wideband_cqi);
if (msg->pmi_present) {
if (msg->rank_is_not_one) {
n += snprintf(buff + n, buff_len - n, ", diff_cqi=%d", msg->spatial_diff_cqi);
}
n += snprintf(buff + n, buff_len - n, ", pmi=%d", msg->pmi);
}
return n;
}
static int srslte_cqi_format2_subband_tostring(srslte_cqi_format2_subband_t *msg, char *buff, uint32_t buff_len) {
int n = 0;
n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->subband_cqi);
n += snprintf(buff + n, buff_len - n, ", label=%d", msg->subband_label);
return n;
}
static int srslte_cqi_ue_subband_tostring(srslte_cqi_ue_subband_t *msg, char *buff, uint32_t buff_len) {
int n = 0;
n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->wideband_cqi);
n += snprintf(buff + n, buff_len - n, ", diff_cqi=%d", msg->subband_diff_cqi);
n += snprintf(buff + n, buff_len - n, ", L=%d", msg->L);
return n;
}
static int srslte_cqi_hl_subband_tostring(srslte_cqi_hl_subband_t *msg, char *buff, uint32_t buff_len) {
int n = 0;
n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->wideband_cqi_cw0);
n += snprintf(buff + n, buff_len - n, ", diff=%d", msg->subband_diff_cqi_cw0);
if (msg->rank_is_not_one) {
n += snprintf(buff + n, buff_len - n, ", cqi1=%d", msg->wideband_cqi_cw1);
n += snprintf(buff + n, buff_len - n, ", diff1=%d", msg->subband_diff_cqi_cw1);
}
if (msg->pmi_present) {
n += snprintf(buff + n, buff_len - n, ", pmi=%d", msg->pmi);
}
n += snprintf(buff + n, buff_len - n, ", N=%d", msg->N);
return n;
}
int srslte_cqi_value_tostring(srslte_cqi_value_t *value, char *buff, uint32_t buff_len) {
int ret = -1;
switch (value->type) {
case SRSLTE_CQI_TYPE_WIDEBAND:
ret = srslte_cqi_format2_wideband_tostring(&value->wideband, buff, buff_len);
break;
case SRSLTE_CQI_TYPE_SUBBAND:
ret = srslte_cqi_format2_subband_tostring(&value->subband, buff, buff_len);
break;
case SRSLTE_CQI_TYPE_SUBBAND_UE:
ret = srslte_cqi_ue_subband_tostring(&value->subband_ue, buff, buff_len);
break;
case SRSLTE_CQI_TYPE_SUBBAND_HL:
ret = srslte_cqi_hl_subband_tostring(&value->subband_hl, buff, buff_len);
break;
default:
/* Do nothing */;
}
return ret;
}
int srslte_cqi_size(srslte_cqi_value_t *value) { int srslte_cqi_size(srslte_cqi_value_t *value) {
int size = 0; int size = 0;

@ -0,0 +1,52 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
// A bunch of helper functions to process device arguments
#define REMOVE_SUBSTRING_WITHCOMAS(S, TOREMOVE) \
remove_substring(S, TOREMOVE ",");\
remove_substring(S, TOREMOVE ", ");\
remove_substring(S, "," TOREMOVE);\
remove_substring(S, ", " TOREMOVE);\
remove_substring(S, TOREMOVE)
static void remove_substring(char *s,const char *toremove) {
while((s=strstr(s,toremove))) {
memmove(s,s+strlen(toremove),1+strlen(s+strlen(toremove)));
}
}
static void copy_subdev_string(char *dst, char *src) {
int n = 0;
size_t len = strlen(src);
/* Copy until end of string or comma */
while (n < len && src[n] != '\0' && src[n] != ',') {
dst[n] = src[n];
n++;
}
dst[n] = '\0';
}

@ -32,21 +32,42 @@
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "rf_soapy_imp.h" #include "rf_soapy_imp.h"
#include "srslte/phy/rf/rf.h" #include "rf_helper.h"
#include <SoapySDR/Device.h> #include <SoapySDR/Device.h>
#include <SoapySDR/Formats.h> #include <SoapySDR/Formats.h>
#include <SoapySDR/Time.h>
#include <SoapySDR/Logger.h>
#include <Types.h>
#define USE_TX_MTU 0
#define SET_RF_BW 1
#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 { typedef struct {
char *devname; char *devname;
SoapySDRKwargs args; SoapySDRKwargs args;
SoapySDRDevice *device; SoapySDRDevice *device;
SoapySDRRange *ranges; SoapySDRRange *ranges;
SoapySDRStream *rxStream; SoapySDRStream *rxStream;
SoapySDRStream *txStream; SoapySDRStream *txStream;
bool tx_stream_active; bool tx_stream_active;
bool rx_stream_active; bool rx_stream_active;
srslte_rf_info_t info; srslte_rf_info_t info;
double tx_rate;
size_t rx_mtu, tx_mtu;
uint32_t num_time_errors;
uint32_t num_lates;
uint32_t num_overflows;
uint32_t num_underflows;
uint32_t num_other_errors;
uint32_t num_stream_curruption;
} rf_soapy_handler_t; } rf_soapy_handler_t;
@ -61,31 +82,31 @@ int soapy_error(void *h)
void rf_soapy_get_freq_range(void *h) void rf_soapy_get_freq_range(void *h)
{ {
// not supported
} }
void rf_soapy_suppress_handler(const char *x) void rf_soapy_suppress_handler(const char *x)
{ {
// not supported // not supported
} }
void rf_soapy_msg_handler(const char *msg) void rf_soapy_msg_handler(const char *msg)
{ {
// not supported // not supported
} }
void rf_soapy_suppress_stdout(void *h) void rf_soapy_suppress_stdout(void *h)
{ {
// not supported // not supported
} }
void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler) void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler)
{ {
// not supported // not supported
} }
@ -109,14 +130,19 @@ bool rf_soapy_rx_wait_lo_locked(void *h)
void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal) void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal)
{ {
printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n"); rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
// not supported double actual_bw = SoapySDRDevice_getBandwidth(handler->device, SOAPY_SDR_TX, 0);
char str_buf[25];
snprintf(str_buf, sizeof(str_buf), "%f", actual_bw);
if (SoapySDRDevice_writeSetting(handler->device, "CALIBRATE_TX", str_buf)) {
printf("Error calibrating Rx\n");
}
} }
void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal) void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal)
{ {
printf("TODO: implement rf_soapy_set_rx_cal()\n"); // not supported
} }
@ -202,13 +228,15 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
printf("No Soapy devices found.\n"); printf("No Soapy devices found.\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
char* devname = NULL; char* devname = DEVNAME_NONE;
for (size_t i = 0; i < length; i++) { for (size_t i = 0; i < length; i++) {
printf("Soapy has found device #%d: ", (int)i); printf("Soapy has found device #%d: ", (int)i);
for (size_t j = 0; j < soapy_args[i].size; j++) { for (size_t j = 0; j < soapy_args[i].size; j++) {
printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]); printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]);
if(!strcmp(soapy_args[i].keys[j],"name") && !strcmp(soapy_args[i].vals[j], "LimeSDR-USB")){ if(!strcmp(soapy_args[i].keys[j],"name") && !strcmp(soapy_args[i].vals[j], "LimeSDR-USB")){
devname = DEVNAME_LIME; devname = DEVNAME_LIME;
} else if (!strcmp(soapy_args[i].keys[j],"name") && !strcmp(soapy_args[i].vals[j], "LimeSDR Mini")){
devname = DEVNAME_LIME_MINI;
} }
} }
printf("\n"); printf("\n");
@ -228,39 +256,46 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
handler->tx_stream_active = false; handler->tx_stream_active = false;
handler->rx_stream_active = false; handler->rx_stream_active = false;
handler->devname = devname; handler->devname = devname;
if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_RX) > 0){
// 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);
if(SoapySDRDevice_getNumChannels(handler->device, SOAPY_SDR_RX) > 0){
printf("Setting up RX stream\n"); printf("Setting up RX stream\n");
if(SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { if(SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
printf("Rx setupStream fail: %s\n", SoapySDRDevice_lastError()); printf("Rx setupStream fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
handler->rx_mtu = SoapySDRDevice_getStreamMTU(handler->device, handler->rxStream);
} }
if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_TX) > 0){ if(SoapySDRDevice_getNumChannels(handler->device, SOAPY_SDR_TX) > 0){
printf("Setting up TX stream\n"); printf("Setting up TX stream\n");
if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
printf("Tx setupStream fail: %s\n", SoapySDRDevice_lastError()); printf("Tx setupStream fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
handler->tx_mtu = SoapySDRDevice_getStreamMTU(handler->device, handler->txStream);
} }
// list device sensors // list device sensors
size_t sensor_length; size_t list_length;
char** sensors; char** list;
sensors = SoapySDRDevice_listSensors(handler->device, &sensor_length); list = SoapySDRDevice_listSensors(handler->device, &list_length);
printf("Available device sensors: \n"); printf("Available device sensors: \n");
for(int i = 0; i < sensor_length; i++) { for(int i = 0; i < list_length; i++) {
printf(" - %s\n", sensors[i]); printf(" - %s\n", list[i]);
} }
// list channel sensors // list channel sensors
sensors = SoapySDRDevice_listChannelSensors(handler->device, SOAPY_SDR_RX, 0, &sensor_length); list = SoapySDRDevice_listChannelSensors(handler->device, SOAPY_SDR_RX, 0, &list_length);
printf("Available sensors for RX channel 0: \n"); printf("Available sensors for RX channel 0: \n");
for(int i = 0; i < sensor_length; i++) { for(int i = 0; i < list_length; i++) {
printf(" - %s\n", sensors[i]); printf(" - %s\n", list[i]);
} }
/* Set static radio info */ // Set static radio info
SoapySDRRange tx_range = SoapySDRDevice_getGainRange(handler->device, SOAPY_SDR_TX, 0); SoapySDRRange tx_range = SoapySDRDevice_getGainRange(handler->device, SOAPY_SDR_TX, 0);
SoapySDRRange rx_range = SoapySDRDevice_getGainRange(handler->device, SOAPY_SDR_RX, 0); SoapySDRRange rx_range = SoapySDRDevice_getGainRange(handler->device, SOAPY_SDR_RX, 0);
handler->info.min_tx_gain = tx_range.minimum; handler->info.min_tx_gain = tx_range.minimum;
@ -268,6 +303,87 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
handler->info.min_rx_gain = rx_range.minimum; handler->info.min_rx_gain = rx_range.minimum;
handler->info.max_rx_gain = rx_range.maximum; handler->info.max_rx_gain = rx_range.maximum;
// Check device arguments
if (args) {
// config file
const char config_arg[] = "config=";
char config_str[64] = {0};
char *config_ptr = strstr(args, config_arg);
if (config_ptr) {
copy_subdev_string(config_str, config_ptr + strlen(config_arg));
printf("Loading config file %s\n", config_str);
SoapySDRDevice_writeSetting(handler->device, "LOAD_CONFIG", config_str);
remove_substring(args, config_arg);
remove_substring(args, config_str);
}
// rx antenna
const char rx_ant_arg[] = "rxant=";
char rx_ant_str[64] = {0};
char *rx_ant_ptr = strstr(args, rx_ant_arg);
if (rx_ant_ptr) {
copy_subdev_string(rx_ant_str, rx_ant_ptr + strlen(rx_ant_arg));
printf("Setting Rx antenna to %s\n", rx_ant_str);
if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_RX, 0, rx_ant_str) != 0) {
fprintf(stderr, "Failed to set Rx antenna.\n");
}
remove_substring(args, rx_ant_arg);
remove_substring(args, rx_ant_str);
}
// tx antenna
const char tx_ant_arg[] = "txant=";
char tx_ant_str[64] = {0};
char *tx_ant_ptr = strstr(args, tx_ant_arg);
if (tx_ant_ptr) {
copy_subdev_string(tx_ant_str, tx_ant_ptr + strlen(tx_ant_arg));
printf("Setting Tx antenna to %s\n", tx_ant_str);
if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_TX, 0, tx_ant_str) != 0) {
fprintf(stderr, "Failed to set Tx antenna.\n");
}
remove_substring(args, tx_ant_arg);
remove_substring(args, tx_ant_str);
}
}
// receive one subframe to allow for transceiver calibration
if (strstr(devname, "lime")) {
// set default tx gain and leave some time to calibrate tx
rf_soapy_set_tx_gain(handler, 45);
rf_soapy_set_rx_gain(handler, 35);
cf_t dummy_buffer[1920];
cf_t *dummy_buffer_array[SRSLTE_MAX_PORTS];
dummy_buffer_array[0] = 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);
usleep(10000);
//SoapySDR_setLogLevel(SOAPY_SDR_ERROR);
}
// list gains and AGC mode
bool has_agc = SoapySDRDevice_hasGainMode(handler->device, SOAPY_SDR_RX, 0);
list = SoapySDRDevice_listGains(handler->device, SOAPY_SDR_RX, 0, &list_length);
printf("State of gain elements for Rx channel 0 (AGC %s):\n", has_agc ? "supported":"not supported");
for(int i = 0; i < list_length; i++) {
printf(" - %s: %.2f dB\n", list[i], SoapySDRDevice_getGainElement(handler->device, SOAPY_SDR_RX, 0, list[i]));
}
has_agc = SoapySDRDevice_hasGainMode(handler->device, SOAPY_SDR_TX, 0);
printf("State of gain elements for Tx channel 0 (AGC %s):\n", has_agc ? "supported":"not supported");
for(int i = 0; i < list_length; i++) {
printf(" - %s: %.2f dB\n", list[i], SoapySDRDevice_getGainElement(handler->device, SOAPY_SDR_TX, 0, list[i]));
}
// print actual antenna configuration
char *ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_RX, 0);
printf("Rx antenna set to %s\n", ant);
ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_TX, 0);
printf("Tx antenna set to %s\n", ant);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -293,14 +409,25 @@ int rf_soapy_close(void *h)
SoapySDRDevice_unmake(handler->device); SoapySDRDevice_unmake(handler->device);
free(handler); free(handler);
// print statistics
if (handler->num_lates) printf("#lates=%d\n", handler->num_lates);
if (handler->num_overflows) printf("#overflows=%d\n", handler->num_overflows);
if (handler->num_underflows) printf("#underflows=%d\n", handler->num_underflows);
if (handler->num_time_errors) printf("#time_errors=%d\n", handler->num_time_errors);
if (handler->num_other_errors) printf("#other_errors=%d\n", handler->num_other_errors);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
void rf_soapy_set_master_clock_rate(void *h, double rate) void rf_soapy_set_master_clock_rate(void *h, double rate)
{ {
// Allow the soapy to automatically set the appropriate clock rate rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setMasterClockRate(handler->device, rate) != 0) {
printf("rf_soapy_set_master_clock_rate Rx fail: %s\n", SoapySDRDevice_lastError());
}
printf("Set master clock rate to %.2f MHz\n", SoapySDRDevice_getMasterClockRate(handler->device)/1e6);
} }
@ -314,21 +441,75 @@ bool rf_soapy_is_master_clock_dynamic(void *h)
double rf_soapy_set_rx_srate(void *h, double rate) double rf_soapy_set_rx_srate(void *h, double rate)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
// Restart streaming, as the Lime seems to have problems reconfiguring the sample rate during streaming
bool rx_stream_active = handler->rx_stream_active;
if (rx_stream_active) {
rf_soapy_stop_rx_stream(handler);
}
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) {
printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError()); printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; 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;
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);
#endif
if (rx_stream_active) {
rf_soapy_start_rx_stream(handler, true);
}
return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0); return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0);
} }
double rf_soapy_set_tx_srate(void *h, double rate) double rf_soapy_set_tx_srate(void *h, double rate)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
// stop/start streaming during rate reconfiguration
bool rx_stream_active = handler->rx_stream_active;
if (handler->rx_stream_active) {
rf_soapy_stop_rx_stream(handler);
}
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) {
printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError()); printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0);
#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 to the actual sampling rate but make sure to stay within device boundaries
double bw = rate;
bw = MIN(rate, bw_range->maximum);
bw = MAX(rate, bw_range->minimum);
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);
#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;
} }
@ -359,14 +540,14 @@ double rf_soapy_set_tx_gain(void *h, double gain)
double rf_soapy_get_rx_gain(void *h) double rf_soapy_get_rx_gain(void *h)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_RX,0); return SoapySDRDevice_getGain(handler->device, SOAPY_SDR_RX, 0);
} }
double rf_soapy_get_tx_gain(void *h) double rf_soapy_get_tx_gain(void *h)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_TX,0); return SoapySDRDevice_getGain(handler->device, SOAPY_SDR_TX, 0);
} }
@ -389,14 +570,10 @@ double rf_soapy_set_rx_freq(void *h, double freq)
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
printf("Tuned Rx to %.2f MHz\n", SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0)/1e6);
// Todo: expose antenna setting // wait until LO is locked
if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_RX, 0, "LNAH") != 0) { rf_soapy_rx_wait_lo_locked(handler);
fprintf(stderr, "Failed to set Rx antenna.\n");
}
char *ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_RX, 0);
printf("Rx antenna set to %s\n", ant);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0); return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
} }
@ -410,13 +587,7 @@ double rf_soapy_set_tx_freq(void *h, double freq)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Todo: expose antenna name in arguments printf("Tuned Tx to %.2f MHz\n", SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0)/1e6);
if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_TX, 0, "BAND1") != 0) {
fprintf(stderr, "Failed to set Tx antenna.\n");
}
char *ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_TX, 0);
printf("Tx antenna set to %s\n", ant);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0); return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0);
} }
@ -439,42 +610,59 @@ int rf_soapy_recv_with_time_multi(void *h,
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
int flags; //flags set by receive operation int flags; //flags set by receive operation
int num_channels = 1; // temp int num_channels = 1; // temp
const long timeoutUs = 1000000; // arbitrarily chosen const long timeoutUs = 400000; // arbitrarily chosen
int trials = 0; int trials = 0;
int ret = 0; int ret = 0;
long long timeNs; //timestamp for receive buffer long long timeNs; //timestamp for receive buffer
int n = 0; int n = 0;
#if PRINT_RX_STATS
printf("rx: nsamples=%d rx_mtu=%zd\n", nsamples, handler->rx_mtu);
#endif
do { do {
size_t rx_samples = nsamples; size_t rx_samples = MIN(nsamples - n, handler->rx_mtu);
#if PRINT_RX_STATS
if (rx_samples > nsamples - n){ printf(" - rx_samples=%zd\n", rx_samples);
rx_samples = nsamples - n; #endif
}
void *buffs_ptr[4]; void *buffs_ptr[4];
for (int i=0; i<num_channels; i++){ for (int i=0; i<num_channels; i++){
cf_t *data_c = (cf_t*) data[i]; cf_t *data_c = (cf_t*) data[i];
buffs_ptr[i] = &data_c[n]; buffs_ptr[i] = &data_c[n];
} }
ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr, rx_samples, &flags, &timeNs, timeoutUs); ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr, rx_samples, &flags, &timeNs, timeoutUs);
if(ret < 0) { if (ret == SOAPY_SDR_OVERFLOW || (ret > 0 && (flags & SOAPY_SDR_END_ABRUPT) != 0)) {
// continue when getting overflows handler->num_overflows++;
if (ret == SOAPY_SDR_OVERFLOW) { fprintf(stderr, "O");
fprintf(stderr, "O"); fflush(stderr);
fflush(stderr); continue;
continue; } else
} else { if (ret == SOAPY_SDR_TIMEOUT) {
return SRSLTE_ERROR; handler->num_time_errors++;
} fprintf(stderr, "T");
fflush(stderr);
continue;
} else
if (ret < 0) {
// unspecific error
printf("SoapySDRDevice_readStream returned %d: %s\n", ret, SoapySDR_errToStr(ret));
handler->num_other_errors++;
} }
// update rx time // update rx time only for first segment
if (secs != NULL && frac_secs != NULL) { if (secs != NULL && frac_secs != NULL && n == 0) {
*secs = timeNs / 1e9; *secs = timeNs / 1e9;
*frac_secs = (timeNs % 1000000000)/1e9; *frac_secs = (timeNs % 1000000000)/1e9;
//printf("rx_time: secs=%d, frac_secs=%lf timeNs=%lld\n", *secs, *frac_secs, timeNs); //printf("rx_time: secs=%lld, frac_secs=%lf timeNs=%llu\n", *secs, *frac_secs, timeNs);
} }
#if PRINT_RX_STATS
printf(" - rx: %d/%zd\n", ret, rx_samples);
#endif
n += ret; n += ret;
trials++; trials++;
} while (n < nsamples && trials < 100); } while (n < nsamples && trials < 100);
@ -522,65 +710,103 @@ int rf_soapy_send_timed_multi(void *h,
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t *) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t *) h;
int flags = 0; int flags = 0;
const long timeoutUs = 2000; // arbitrarily chosen const long timeoutUs = 100000; // arbitrarily chosen
long long timeNs = 0; long long timeNs = 0;
int trials = 0; int trials = 0;
int ret = 0; int ret = 0;
int n = 0; int n = 0;
#if PRINT_TX_STATS
printf("tx: namples=%d, mtu=%zd\n", nsamples, handler->tx_mtu);
#endif
if (!handler->tx_stream_active) { if (!handler->tx_stream_active) {
rf_soapy_start_tx_stream(h); rf_soapy_start_tx_stream(h);
} }
if (is_start_of_burst && is_end_of_burst) { // Convert initial tx time
flags |= SOAPY_SDR_ONE_PACKET;
}
if (is_end_of_burst) {
flags |= SOAPY_SDR_END_BURST;
}
if (has_time_spec) { if (has_time_spec) {
flags |= SOAPY_SDR_HAS_TIME;
timeNs = secs * 1000000000; timeNs = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000); timeNs = timeNs + (frac_secs * 1000000000);
//printf("time_spec: secs=%d, frac_secs=%lf timeNs=%lld\n", secs, frac_secs, timeNs);
} }
do { do {
#if USE_TX_MTU
size_t tx_samples = MIN(nsamples - n, handler->tx_mtu);
#else
size_t tx_samples = nsamples; size_t tx_samples = nsamples;
if (tx_samples > nsamples - n) { if (tx_samples > nsamples - n) {
tx_samples = nsamples - n; tx_samples = nsamples - n;
} }
#endif
ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, (const void *)data, tx_samples, &flags, timeNs, timeoutUs); // (re-)set stream flags
if (ret == SOAPY_SDR_TIMEOUT) { flags = 0;
printf("L"); if (is_start_of_burst && is_end_of_burst) {
continue; flags |= SOAPY_SDR_ONE_PACKET;
} }
if (ret == SOAPY_SDR_OVERFLOW) {
printf("O"); if (is_end_of_burst) {
continue; flags |= SOAPY_SDR_END_BURST;
} }
if (ret == SOAPY_SDR_UNDERFLOW) {
printf("U"); // only set time flag for first tx
continue; if(has_time_spec && n == 0) {
flags |= SOAPY_SDR_HAS_TIME;
}
#if PRINT_TX_STATS
printf(" - tx_samples=%zd at timeNs=%llu flags=%d\n", tx_samples, timeNs, flags);
#endif
ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, (const void *)data, tx_samples, &flags, timeNs, timeoutUs);
if (ret >= 0) {
// Tx was ok
#if PRINT_TX_STATS
printf(" - tx: %d/%zd\n", ret, tx_samples);
#endif
// Advance tx time
if (has_time_spec && ret < nsamples) {
long long adv = SoapySDR_ticksToTimeNs(ret, handler->tx_rate);
#if PRINT_TX_STATS
printf(" - tx: timeNs_old=%llu, adv=%llu, timeNs_new=%llu, tx_rate=%f\n", timeNs, adv, timeNs+adv, handler->tx_rate);
#endif
timeNs += adv;
}
n += ret;
} }
else
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error during writeStream\n"); // An error has occured
exit(-1); switch (ret) {
return SRSLTE_ERROR; case SOAPY_SDR_TIMEOUT:
handler->num_lates++;
printf("L");
break;
case SOAPY_SDR_STREAM_ERROR:
handler->num_stream_curruption++;
printf("E");
break;
case SOAPY_SDR_TIME_ERROR:
handler->num_time_errors++;
printf("T");
break;
case SOAPY_SDR_UNDERFLOW:
handler->num_underflows++;
printf("U");
break;
default:
fprintf(stderr, "Error during writeStream\n");
exit(-1);
return SRSLTE_ERROR;
}
} }
n += ret;
trials++; trials++;
} while (n < nsamples && trials < 100); } while (n < nsamples && trials < 100);
if (n != nsamples) { if (n != nsamples) {
fprintf(stderr, "Couldn't write all samples.\n"); fprintf(stderr, "Couldn't write all samples after %d trials.\n", trials);
return SRSLTE_ERROR;
} }
return ret; return n;
} }

@ -28,7 +28,9 @@
#include <stdint.h> #include <stdint.h>
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf.h"
#define DEVNAME_NONE "none"
#define DEVNAME_LIME "lime" #define DEVNAME_LIME "lime"
#define DEVNAME_LIME_MINI "lime_mini"
SRSLTE_API int rf_soapy_open(char *args, SRSLTE_API int rf_soapy_open(char *args,
void **handler); void **handler);

@ -32,7 +32,7 @@
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "rf_uhd_imp.h" #include "rf_uhd_imp.h"
#include "srslte/phy/rf/rf.h" #include "rf_helper.h"
#include "uhd_c_api.h" #include "uhd_c_api.h"
#define HAVE_ASYNC_THREAD 1 #define HAVE_ASYNC_THREAD 1
@ -320,31 +320,6 @@ int rf_uhd_open(char *args, void **h)
return rf_uhd_open_multi(args, h, 1); return rf_uhd_open_multi(args, h, 1);
} }
#define REMOVE_SUBSTRING_WITHCOMAS(S, TOREMOVE) \
remove_substring(S, TOREMOVE ",");\
remove_substring(S, TOREMOVE ", ");\
remove_substring(S, "," TOREMOVE);\
remove_substring(S, ", " TOREMOVE);\
remove_substring(S, TOREMOVE)
static void remove_substring(char *s,const char *toremove)
{
while((s=strstr(s,toremove))) {
memmove(s,s+strlen(toremove),1+strlen(s+strlen(toremove)));
}
}
static void copy_subdev_string(char *dst, char *src) {
int n = 0;
size_t len = strlen(src);
/* Copy until end of string or comma */
while (n < len && src[n] != '\0' && src[n] != ',') {
dst[n] = src[n];
n++;
}
dst[n] = '\0';
}
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
{ {
if (h) { if (h) {

@ -491,6 +491,9 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q,
int found_dci = srslte_ue_dl_find_dl_dci(q, tm, cfi, sf_idx, rnti, &dci_msg); int found_dci = srslte_ue_dl_find_dl_dci(q, tm, cfi, sf_idx, rnti, &dci_msg);
if (found_dci == 1) { if (found_dci == 1) {
INFO("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti=%d\n", srslte_dci_format_string(dci_msg.format),
q->current_rnti, q->last_location.ncce, (1<<q->last_location.L), tti);
if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) { if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) {
fprintf(stderr, "Error unpacking DCI\n"); fprintf(stderr, "Error unpacking DCI\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;

@ -23,3 +23,5 @@ if(RF_FOUND)
target_link_libraries(srslte_radio srslte_rf) target_link_libraries(srslte_radio srslte_rf)
install(TARGETS srslte_radio DESTINATION ${LIBRARY_DIR}) install(TARGETS srslte_radio DESTINATION ${LIBRARY_DIR})
endif(RF_FOUND) endif(RF_FOUND)
add_subdirectory(test)

@ -59,7 +59,7 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels)
} else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) {
burst_preamble_sec = blade_default_burst_preamble_sec; burst_preamble_sec = blade_default_burst_preamble_sec;
} else { } else {
burst_preamble_sec = 0; burst_preamble_sec = 0;
printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device));
} }
@ -81,7 +81,9 @@ bool radio::is_init() {
void radio::stop() void radio::stop()
{ {
srslte_rf_close(&rf_device); if (is_initialized) {
srslte_rf_close(&rf_device);
}
} }
void radio::reset() void radio::reset()

@ -0,0 +1,26 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
if(RF_FOUND)
add_executable(benchmark_radio benchmark_radio.cc)
target_link_libraries(benchmark_radio srslte_radio)
endif(RF_FOUND)

@ -0,0 +1,182 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <unistd.h>
#include "srslte/srslte.h"
#include "srslte/radio/radio_multi.h"
using namespace srslte;
std::string device_args = "auto";
double freq = 2630e6;
uint32_t nof_ports = 1;
double srate = 1.92e6; /* Hz */
double duration = 0.01; /* in seconds, 10 ms by default */
cf_t *buffers[SRSLTE_MAX_PORTS];
bool tx_enable = false;
void usage(char *prog) {
printf("Usage: %s [rpstvh]\n", prog);
printf("\t-f Carrier frequency in Hz [Default %f]\n", freq);
printf("\t-a Arguments for first radio [Default %s]\n", device_args.c_str());
printf("\t-p number of ports 1-%d [Default %d]\n", SRSLTE_MAX_PORTS, nof_ports);
printf("\t-s sampling rate [Default %.0f]\n", srate);
printf("\t-t duration in seconds [Default %.3f]\n", duration);
printf("\t-x enable transmit [Default %s]\n", (tx_enable) ? "enabled" : "disabled");
printf("\t-v Set srslte_verbose to info (v) or debug (vv) [Default none]\n");
printf("\t-h show this message\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "foabcderpstvhmxw")) != -1) {
switch (opt) {
case 'f':
freq = atof(argv[optind]);
break;
case 'a':
device_args = std::string(argv[optind]);
break;
case 'p':
nof_ports = (uint32_t) atoi(argv[optind]);
break;
case 's':
srate = atof(argv[optind]);
break;
case 't':
duration = atof(argv[optind]);
break;
case 'x':
tx_enable ^= true;
break;
case 'v':
srslte_verbose++;
break;
case 'h':
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char **argv)
{
int ret = SRSLTE_ERROR;
srslte::radio_multi *radio_h = NULL;
srslte_timestamp_t ts_rx = {}, ts_tx = {};
/* Parse args */
parse_args(argc, argv);
uint32_t nof_samples = (uint32_t) (duration * srate);
uint32_t frame_size = (uint32_t) (srate / 1000.0); /* 1 ms at srate */
uint32_t nof_frames = (uint32_t) ceil(nof_samples / frame_size);
radio_h = new radio_multi();
if (!radio_h) {
fprintf(stderr, "Error: Calling radio_multi constructor\n");
goto clean_exit;
}
for (uint32_t p = 0; p < SRSLTE_MAX_PORTS; p++) {
buffers[p] = NULL;
}
for (uint32_t p = 0; p < nof_ports; p++) {
buffers[p] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * frame_size);
if (!buffers[p]) {
fprintf(stderr, "Error: Allocating buffer (%d)\n", p);
goto clean_exit;
}
}
/* Initialise instances */
printf("Initialising instances...\n");
if (!radio_h->init((char*)device_args.c_str(), NULL, nof_ports)) {
fprintf(stderr, "Error: Calling radio_multi constructor\n");
goto clean_exit;
}
radio_h->set_rx_freq(freq);
/* Set radio */
printf("Setting radio...\n");
if (srate < 10e6) {
radio_h->set_master_clock_rate(4 * srate);
} else {
radio_h->set_master_clock_rate(srate);
}
radio_h->set_rx_srate(srate);
if (tx_enable) {
radio_h->set_tx_srate(srate);
}
/* Receive */
printf("Initial receive for aligning radios...\n");
radio_h->rx_now(buffers, frame_size, &ts_rx);
printf("Start capturing %d frames of %d samples...\n", nof_frames, frame_size);
for (uint32_t i = 0; i < nof_frames; i++) {
frame_size = SRSLTE_MIN(frame_size, nof_samples);
radio_h->rx_now(buffers, frame_size, &ts_rx);
if (tx_enable) {
srslte_timestamp_copy(&ts_tx, &ts_rx);
srslte_timestamp_add(&ts_tx, 0, 0.004);
radio_h->tx_single(buffers[0], frame_size, ts_tx);
}
nof_samples -= frame_size;
}
printf("Finished streaming ...\n");
ret = SRSLTE_SUCCESS;
clean_exit:
printf("Tearing down...\n");
radio_h->stop();
for (uint32_t p = 0; p < nof_ports; p++) {
if (buffers[p]) {
free(buffers[p]);
}
}
if (ret) {
printf("Failed!\n");
} else {
printf("Ok!\n");
}
return ret;
}

@ -78,31 +78,19 @@ public:
uint32_t get_next_mme_ue_s1ap_id(); uint32_t get_next_mme_ue_s1ap_id();
enb_ctx_t* find_enb_ctx(uint16_t enb_id); enb_ctx_t* find_enb_ctx(uint16_t enb_id);
void add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo* enb_sri); void add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo* enb_sri);
void get_enb_ctx(uint16_t sctp_stream);
bool add_ue_ctx_to_imsi_map(ue_ctx_t *ue_ctx); bool add_ue_ctx_to_imsi_map(ue_ctx_t *ue_ctx);
bool add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx_t *ue_ctx); bool add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx_t *ue_ctx);
bool add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id);
ue_ctx_t* find_ue_ctx_from_imsi(uint64_t imsi); ue_ctx_t* find_ue_ctx_from_imsi(uint64_t imsi);
ue_ctx_t* find_ue_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id); ue_ctx_t* find_ue_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id);
bool release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id); bool release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id);
void release_ues_ecm_ctx_in_enb(uint16_t enb_id); void release_ues_ecm_ctx_in_enb(int32_t enb_assoc);
bool delete_ue_ctx(uint64_t imsi); bool delete_ue_ctx(uint64_t imsi);
//ue_ctx_t* find_ue_ctx(uint32_t mme_ue_s1ap_id);
//void add_new_ue_ctx(const ue_ctx_t &ue_ctx);
//void add_new_ue_emm_ctx(const ue_emm_ctx_t &ue_emm_ctx);
//void add_new_ue_ecm_ctx(const ue_ecm_ctx_t &ue_ecm_ctx);
//ue_emm_ctx_t* find_ue_emm_ctx_from_imsi(uint64_t imsi);
//ue_ecm_ctx_t* find_ue_ecm_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id);
//bool delete_ue_emm_ctx(uint64_t imsi);
//bool delete_ue_ecm_ctx(uint32_t mme_ue_s1ap_id);
//void delete_ues_ecm_ctx_in_enb(uint16_t enb_id);
//void store_tmp_ue_emm_ctx(const ue_emm_ctx_t &ue_ecm_ctx);
//bool get_tmp_ue_emm_ctx(uint32_t mme_ue_s1ap_id, ue_emm_ctx_t* ue_emm_ptr);
uint32_t allocate_m_tmsi(uint64_t imsi); uint32_t allocate_m_tmsi(uint64_t imsi);
s1ap_args_t m_s1ap_args; s1ap_args_t m_s1ap_args;
@ -127,16 +115,11 @@ private:
int m_s1mme; int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs; std::map<uint16_t, enb_ctx_t*> m_active_enbs;
std::map<int32_t, uint16_t> m_sctp_to_enb_id; std::map<int32_t, uint16_t> m_sctp_to_enb_id;
std::map<uint16_t,std::set<uint32_t> > m_enb_id_to_ue_ids; std::map<int32_t,std::set<uint32_t> > m_enb_assoc_to_ue_ids;
std::map<uint64_t, ue_ctx_t*> m_imsi_to_ue_ctx; std::map<uint64_t, ue_ctx_t*> m_imsi_to_ue_ctx;
std::map<uint32_t, ue_ctx_t*> m_mme_ue_s1ap_id_to_ue_ctx; std::map<uint32_t, ue_ctx_t*> m_mme_ue_s1ap_id_to_ue_ctx;
//std::map<uint64_t, ue_emm_ctx_t*> m_imsi_to_ue_emm_ctx;
//std::map<uint32_t, ue_ecm_ctx_t*> m_mme_ue_s1ap_id_to_ue_ecm_ctx;
//std::map<int32_t,ue_emm_ctx_t*> m_mme_ue_s1ap_id_to_tmp_ue_emm_ctx;
uint32_t m_next_mme_ue_s1ap_id; uint32_t m_next_mme_ue_s1ap_id;
uint32_t m_next_m_tmsi; uint32_t m_next_m_tmsi;

@ -299,7 +299,7 @@ s1ap::add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo *en
memcpy(enb_ptr,&enb_ctx,sizeof(enb_ctx_t)); memcpy(enb_ptr,&enb_ctx,sizeof(enb_ctx_t));
m_active_enbs.insert(std::pair<uint16_t,enb_ctx_t*>(enb_ptr->enb_id,enb_ptr)); m_active_enbs.insert(std::pair<uint16_t,enb_ctx_t*>(enb_ptr->enb_id,enb_ptr));
m_sctp_to_enb_id.insert(std::pair<int32_t,uint16_t>(enb_sri->sinfo_assoc_id, enb_ptr->enb_id)); m_sctp_to_enb_id.insert(std::pair<int32_t,uint16_t>(enb_sri->sinfo_assoc_id, enb_ptr->enb_id));
m_enb_id_to_ue_ids.insert(std::pair<uint16_t,std::set<uint32_t> >(enb_ptr->enb_id,ue_set)); m_enb_assoc_to_ue_ids.insert(std::pair<int32_t,std::set<uint32_t> >(enb_sri->sinfo_assoc_id,ue_set));
return; return;
} }
@ -335,7 +335,7 @@ s1ap::delete_enb_ctx(int32_t assoc_id)
m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_id); m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
//Delete connected UEs ctx //Delete connected UEs ctx
release_ues_ecm_ctx_in_enb(enb_id); release_ues_ecm_ctx_in_enb(assoc_id);
//Delete eNB //Delete eNB
delete it_ctx->second; delete it_ctx->second;
@ -397,6 +397,27 @@ s1ap::add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx_t *ue_ctx)
return true; return true;
} }
bool
s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
{
std::map<int32_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
if(ues_in_enb == m_enb_assoc_to_ue_ids.end())
{
m_s1ap_log->error("Could not find eNB from eNB SCTP association %d",enb_assoc);
return false;
}
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.find(mme_ue_s1ap_id);
if(ue_id != ues_in_enb->second.end())
{
m_s1ap_log->error("UE with MME UE S1AP Id already exists %d",mme_ue_s1ap_id);
return false;
}
ues_in_enb->second.insert(mme_ue_s1ap_id);
m_s1ap_log->debug("Added UE with MME-UE S1AP Id %d to eNB with association %d\n", mme_ue_s1ap_id, enb_assoc);
return true;
}
ue_ctx_t* ue_ctx_t*
s1ap::find_ue_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id) s1ap::find_ue_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
{ {
@ -426,21 +447,34 @@ s1ap::find_ue_ctx_from_imsi(uint64_t imsi)
} }
void void
s1ap::release_ues_ecm_ctx_in_enb(uint16_t enb_id) s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
{ {
m_s1ap_log->console("Releasing UEs context\n");
//delete UEs ctx //delete UEs ctx
std::map<uint16_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_id_to_ue_ids.find(enb_id); std::map<int32_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin(); std::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin();
while(ue_id != ues_in_enb->second.end() ) if(ue_id == ues_in_enb->second.end())
{ {
std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx = m_mme_ue_s1ap_id_to_ue_ctx.find(*ue_id); m_s1ap_log->console("No UEs to be released\n");
ue_ecm_ctx_t *ecm_ctx = &ue_ctx->second->ecm_ctx; } else {
m_s1ap_log->info("Releasing UE ECM context. UE-MME S1AP Id: %d\n", ecm_ctx->mme_ue_s1ap_id); while(ue_id != ues_in_enb->second.end() )
m_s1ap_log->console("Releasing UE ECM context. UE-MME S1AP Id: %d\n", ecm_ctx->mme_ue_s1ap_id); {
ues_in_enb->second.erase(ecm_ctx->mme_ue_s1ap_id); std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx = m_mme_ue_s1ap_id_to_ue_ctx.find(*ue_id);
ecm_ctx->state = ECM_STATE_IDLE; ue_emm_ctx_t *emm_ctx = &ue_ctx->second->emm_ctx;
ecm_ctx->mme_ue_s1ap_id = 0; ue_ecm_ctx_t *ecm_ctx = &ue_ctx->second->ecm_ctx;
ecm_ctx->enb_ue_s1ap_id = 0;
m_s1ap_log->info("Releasing UE context. IMSI: %015lu, UE-MME S1AP Id: %d\n", emm_ctx->imsi, ecm_ctx->mme_ue_s1ap_id);
if(emm_ctx->state == EMM_STATE_REGISTERED)
{
m_mme_gtpc->send_delete_session_request(emm_ctx->imsi);
emm_ctx->state = EMM_STATE_DEREGISTERED;
}
m_s1ap_log->console("Releasing UE ECM context. UE-MME S1AP Id: %d\n", ecm_ctx->mme_ue_s1ap_id);
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->mme_ue_s1ap_id = 0;
ecm_ctx->enb_ue_s1ap_id = 0;
ues_in_enb->second.erase(ue_id++);
}
} }
} }
@ -463,8 +497,8 @@ s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
return false; return false;
} }
uint16_t enb_id = it->second; uint16_t enb_id = it->second;
std::map<uint16_t,std::set<uint32_t> >::iterator ue_set = m_enb_id_to_ue_ids.find(enb_id); std::map<int32_t,std::set<uint32_t> >::iterator ue_set = m_enb_assoc_to_ue_ids.find(ecm_ctx->enb_sri.sinfo_assoc_id);
if(ue_set == m_enb_id_to_ue_ids.end()) if(ue_set == m_enb_assoc_to_ue_ids.end())
{ {
m_s1ap_log->error("Could not find the eNB's UEs.\n"); m_s1ap_log->error("Could not find the eNB's UEs.\n");
return false; return false;

@ -371,7 +371,7 @@ s1ap_nas_transport::handle_nas_attach_request(uint32_t enb_ue_s1ap_id,
//Get attach type from attach request //Get attach type from attach request
if(attach_req.eps_mobile_id.type_of_id == LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI) if(attach_req.eps_mobile_id.type_of_id == LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI)
{ {
m_s1ap_log->console("Attach Request -- IMSI-style attach request\n"); m_s1ap_log->console("Attach Request -- IMSI-style attach request\n");
m_s1ap_log->info("Attach Request -- IMSI-style attach request\n"); m_s1ap_log->info("Attach Request -- IMSI-style attach request\n");
handle_nas_imsi_attach_request(enb_ue_s1ap_id, attach_req, pdn_con_req, reply_buffer, reply_flag, enb_sri); handle_nas_imsi_attach_request(enb_ue_s1ap_id, attach_req, pdn_con_req, reply_buffer, reply_flag, enb_sri);
@ -510,6 +510,7 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
memcpy(new_ctx,&ue_ctx,sizeof(ue_ctx_t)); memcpy(new_ctx,&ue_ctx,sizeof(ue_ctx_t));
m_s1ap->add_ue_ctx_to_imsi_map(new_ctx); m_s1ap->add_ue_ctx_to_imsi_map(new_ctx);
m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(new_ctx); m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(new_ctx);
m_s1ap->add_ue_to_enb_set(enb_sri->sinfo_assoc_id,ecm_ctx->mme_ue_s1ap_id);
//Pack NAS Authentication Request in Downlink NAS Transport msg //Pack NAS Authentication Request in Downlink NAS Transport msg
pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand); pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand);
@ -623,6 +624,7 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_ue_s1ap_id,
ue_ctx_t *new_ctx = new ue_ctx_t; ue_ctx_t *new_ctx = new ue_ctx_t;
memcpy(new_ctx,&ue_ctx,sizeof(ue_ctx_t)); memcpy(new_ctx,&ue_ctx,sizeof(ue_ctx_t));
m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(new_ctx); m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(new_ctx);
m_s1ap->add_ue_to_enb_set(enb_sri->sinfo_assoc_id,ecm_ctx->mme_ue_s1ap_id);
pack_identity_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); pack_identity_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id);
*reply_flag = true; *reply_flag = true;
@ -646,7 +648,7 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_ue_s1ap_id,
if(msg_valid == true && emm_ctx->state == EMM_STATE_DEREGISTERED) if(msg_valid == true && emm_ctx->state == EMM_STATE_DEREGISTERED)
{ {
m_s1ap_log->console("GUTI Attach Integrity valid. UL count %d, DL count %d\n",emm_ctx->security_ctxt.ul_nas_count, emm_ctx->security_ctxt.dl_nas_count); m_s1ap_log->console("GUTI Attach Integrity valid. UL count %d, DL count %d\n",emm_ctx->security_ctxt.ul_nas_count, emm_ctx->security_ctxt.dl_nas_count);
//Create new MME UE S1AP Identity //Create new MME UE S1AP Identity
emm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); emm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id();
ecm_ctx->mme_ue_s1ap_id = emm_ctx->mme_ue_s1ap_id; ecm_ctx->mme_ue_s1ap_id = emm_ctx->mme_ue_s1ap_id;
@ -672,7 +674,8 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_ue_s1ap_id,
//Store context based on MME UE S1AP id //Store context based on MME UE S1AP id
m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx); m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx);
m_s1ap->add_ue_to_enb_set(enb_sri->sinfo_assoc_id,ecm_ctx->mme_ue_s1ap_id);
//Re-generate K_eNB //Re-generate K_eNB
srslte::security_generate_k_enb(emm_ctx->security_ctxt.k_asme, emm_ctx->security_ctxt.ul_nas_count, emm_ctx->security_ctxt.k_enb); srslte::security_generate_k_enb(emm_ctx->security_ctxt.k_asme, emm_ctx->security_ctxt.ul_nas_count, emm_ctx->security_ctxt.k_enb);
m_s1ap_log->info("Generating KeNB with UL NAS COUNT: %d\n",emm_ctx->security_ctxt.ul_nas_count); m_s1ap_log->info("Generating KeNB with UL NAS COUNT: %d\n",emm_ctx->security_ctxt.ul_nas_count);

@ -162,6 +162,7 @@ private:
srslte_ue_ul_t ue_ul; srslte_ue_ul_t ue_ul;
srslte_timestamp_t tx_time; srslte_timestamp_t tx_time;
srslte_uci_data_t uci_data; srslte_uci_data_t uci_data;
srslte_cqi_value_t cqi_report;
uint16_t ul_rnti; uint16_t ul_rnti;
// UL configuration parameters // UL configuration parameters

@ -1032,7 +1032,8 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
void phch_worker::reset_uci() void phch_worker::reset_uci()
{ {
bzero(&uci_data, sizeof(srslte_uci_data_t)); ZERO_OBJECT(uci_data);
ZERO_OBJECT(cqi_report);
} }
void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]) void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS])
@ -1082,7 +1083,6 @@ void phch_worker::set_uci_periodic_cqi()
compute_ri(NULL, NULL, NULL); compute_ri(NULL, NULL, NULL);
phy->last_pmi = (uint8_t) ue_dl.pmi[phy->last_ri % SRSLTE_MAX_LAYERS]; phy->last_pmi = (uint8_t) ue_dl.pmi[phy->last_ri % SRSLTE_MAX_LAYERS];
srslte_cqi_value_t cqi_report;
ZERO_OBJECT(cqi_report); ZERO_OBJECT(cqi_report);
if (period_cqi.format_is_subband) { if (period_cqi.format_is_subband) {
@ -1110,6 +1110,8 @@ void phch_worker::set_uci_periodic_cqi()
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db_cqi); Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db_cqi);
} }
uci_data.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); uci_data.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
uci_data.uci_ri = phy->last_ri;
uci_data.uci_ri_len = 0;
rar_cqi_request = false; rar_cqi_request = false;
} }
} }
@ -1135,7 +1137,6 @@ void phch_worker::set_uci_aperiodic_cqi()
reported RI. For other transmission modes they are reported conditioned on rank 1. reported RI. For other transmission modes they are reported conditioned on rank 1.
*/ */
if (rnti_is_set) { if (rnti_is_set) {
srslte_cqi_value_t cqi_report;
ZERO_OBJECT(cqi_report); ZERO_OBJECT(cqi_report);
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL;
@ -1289,11 +1290,13 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui
#endif #endif
char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = ""; char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = "";
srslte_cqi_to_str(uci_data.uci_cqi, uci_data.uci_cqi_len, cqi_str, SRSLTE_CQI_STR_MAX_CHAR); if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) {
srslte_cqi_value_tostring(&cqi_report, cqi_str, SRSLTE_CQI_STR_MAX_CHAR);
}
uint8_t dummy[2] = {0,0}; uint8_t dummy[2] = {0,0};
log_h->info_hex(payload, grant->mcs.tbs/8, log_h->info_hex(payload, grant->mcs.tbs/8,
"PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d%s%s%s, cfo=%.1f KHz%s%s%s\n", "PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d%s%s%s, cfo=%.1f KHz%s%s\n",
(tti + HARQ_DELAY_MS) % 10240, (tti + HARQ_DELAY_MS) % 10240,
grant->n_prb[0], grant->n_prb[0] + grant->L_prb, grant->n_prb[0], grant->n_prb[0] + grant->L_prb,
grant->mcs.tbs / 8, grant->mcs.idx, rv, grant->mcs.tbs / 8, grant->mcs.idx, rv,
@ -1301,7 +1304,6 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui
uci_data.uci_ack_len > 1 ? (uci_data.uci_ack_2 ? "1" : "0") : "", uci_data.uci_ack_len > 1 ? (uci_data.uci_ack_2 ? "1" : "0") : "",
uci_data.uci_ri_len > 0 ? (uci_data.uci_ri ? ", ri=1" : ", ri=0") : "", uci_data.uci_ri_len > 0 ? (uci_data.uci_ri ? ", ri=1" : ", ri=0") : "",
cfo * 15, timestr, cfo * 15, timestr,
uci_data.uci_cqi_len > 0 ? ", cqi=" : "",
uci_data.uci_cqi_len > 0 ? cqi_str : ""); uci_data.uci_cqi_len > 0 ? cqi_str : "");
// Store metrics // Store metrics
@ -1343,17 +1345,18 @@ void phch_worker::encode_pucch()
float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len); float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len);
float gain = set_power(tx_power); float gain = set_power(tx_power);
char str_cqi[SRSLTE_CQI_STR_MAX_CHAR] = ""; char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = "";
srslte_cqi_to_str(uci_data.uci_cqi, uci_data.uci_cqi_len, str_cqi, SRSLTE_CQI_STR_MAX_CHAR); if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) {
srslte_cqi_value_tostring(&cqi_report, cqi_str, SRSLTE_CQI_STR_MAX_CHAR);
}
Info("PUCCH: tti_tx=%d, n_pucch=%d, n_prb=%d, ack=%s%s%s%s%s, sr=%s, cfo=%.1f KHz%s\n", Info("PUCCH: tti_tx=%d, n_pucch=%d, n_prb=%d, ack=%s%s%s%s, sr=%s, cfo=%.1f KHz%s\n",
(tti + 4) % 10240, (tti + 4) % 10240,
ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb, ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb,
uci_data.uci_ack_len > 0 ? (uci_data.uci_ack ? "1" : "0") : "no", uci_data.uci_ack_len > 0 ? (uci_data.uci_ack ? "1" : "0") : "no",
uci_data.uci_ack_len > 1 ? (uci_data.uci_ack_2 ? "1" : "0") : "", uci_data.uci_ack_len > 1 ? (uci_data.uci_ack_2 ? "1" : "0") : "",
uci_data.uci_ri_len > 0 ? (uci_data.uci_ri ? ", ri=1" : ", ri=0") : "", uci_data.uci_ri_len > 0 ? (uci_data.uci_ri ? ", ri=1" : ", ri=0") : "",
uci_data.uci_cqi_len > 0 ? ", cqi=" : "", uci_data.uci_cqi_len > 0 ? cqi_str : "",
uci_data.uci_cqi_len > 0 ? str_cqi : "",
uci_data.scheduling_request ? "yes" : "no", uci_data.scheduling_request ? "yes" : "no",
cfo * 15, timestr); cfo * 15, timestr);
} }

Loading…
Cancel
Save