Merging next into op_vs_opc and resolving conflicts.

master
Pedro Alvarez 7 years ago
commit f301bb6373

@ -599,7 +599,7 @@ int main(int argc, char **argv) {
}
#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_ue_sync_start_agc(&ue_sync,
srslte_rf_set_rx_gain_th_wrapper_,

@ -38,17 +38,19 @@ namespace srslte {
class srslte_nas_config_t
{
public:
srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "", std::string user_ = "", std::string pass_ = "")
srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "", std::string user_ = "", std::string pass_ = "", bool force_imsi_attach_ = false)
:lcid(lcid_),
apn(apn_),
user(user_),
pass(pass_)
pass(pass_),
force_imsi_attach(force_imsi_attach_)
{}
uint32_t lcid;
std::string apn;
std::string user;
std::string pass;
bool force_imsi_attach;
};

@ -274,8 +274,8 @@ public:
class s1ap_interface_rrc
{
public:
virtual void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu) = 0;
virtual void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec) = 0;
virtual void initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu) = 0;
virtual void initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec) = 0;
virtual void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu) = 0;
virtual bool user_exists(uint16_t rnti) = 0;
virtual bool user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio) = 0;

@ -43,7 +43,7 @@
#define SRSLTE_CQI_MAX_BITS 64
#define SRSLTE_DIF_CQI_MAX_BITS 3
#define SRSLTE_PMI_MAX_BITS 4
#define SRSLTE_CQI_STR_MAX_CHAR 32
#define SRSLTE_CQI_STR_MAX_CHAR 64
typedef struct {
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_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_cqi_hl_subband_t *msg);

@ -45,7 +45,8 @@ namespace srslte {
class radio_multi : public radio
{
public:
radio_multi() {}
~radio_multi() {}
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);
};

File diff suppressed because it is too large Load Diff

@ -37,7 +37,7 @@
#include "srslte/common/liblte_security.h"
#include "srslte/common/liblte_ssl.h"
#include "math.h"
#include <stdio.h>
/*******************************************************************************
DEFINES
*******************************************************************************/

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

@ -66,7 +66,7 @@ int srslte_timestamp_sub(srslte_timestamp_t *t, time_t full_secs, double frac_se
t->frac_secs -= frac_secs;
t->full_secs -= full_secs;
if(t->frac_secs < 0){
t->frac_secs = 1-t->frac_secs;
t->frac_secs = t->frac_secs + 1;
t->full_secs--;
}
if(t->full_secs < 0)

@ -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)
{
// 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++) {
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));
@ -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)
{
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_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,
uint16_t rnti, uint32_t sf_idx)
{
srslte_dci_msg_t dci_msg;
srslte_dci_msg_t dci_msg = {};
bool rnti_is_user = true;
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,
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);
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;
}
/*******************************************************
* 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 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 "rf_soapy_imp.h"
#include "srslte/phy/rf/rf.h"
#include "rf_helper.h"
#include <SoapySDR/Device.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 {
char *devname;
SoapySDRKwargs args;
SoapySDRDevice *device;
SoapySDRRange *ranges;
SoapySDRStream *rxStream;
SoapySDRStream *txStream;
bool tx_stream_active;
bool rx_stream_active;
srslte_rf_info_t info;
char *devname;
SoapySDRKwargs args;
SoapySDRDevice *device;
SoapySDRRange *ranges;
SoapySDRStream *rxStream;
SoapySDRStream *txStream;
bool tx_stream_active;
bool rx_stream_active;
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;
@ -61,31 +82,31 @@ int soapy_error(void *h)
void rf_soapy_get_freq_range(void *h)
{
// not supported
}
void rf_soapy_suppress_handler(const char *x)
{
// not supported
// not supported
}
void rf_soapy_msg_handler(const char *msg)
{
// not supported
// not supported
}
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)
{
// 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)
{
printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n");
// not supported
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
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)
{
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");
return SRSLTE_ERROR;
}
char* devname = NULL;
char* devname = DEVNAME_NONE;
for (size_t i = 0; i < length; i++) {
printf("Soapy has found device #%d: ", (int)i);
for (size_t j = 0; j < soapy_args[i].size; 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")){
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");
@ -228,39 +256,46 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
handler->tx_stream_active = false;
handler->rx_stream_active = false;
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");
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());
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");
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());
return SRSLTE_ERROR;
}
}
handler->tx_mtu = SoapySDRDevice_getStreamMTU(handler->device, handler->txStream);
}
// list device sensors
size_t sensor_length;
char** sensors;
sensors = SoapySDRDevice_listSensors(handler->device, &sensor_length);
size_t list_length;
char** list;
list = SoapySDRDevice_listSensors(handler->device, &list_length);
printf("Available device sensors: \n");
for(int i = 0; i < sensor_length; i++) {
printf(" - %s\n", sensors[i]);
for(int i = 0; i < list_length; i++) {
printf(" - %s\n", list[i]);
}
// 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");
for(int i = 0; i < sensor_length; i++) {
printf(" - %s\n", sensors[i]);
for(int i = 0; i < list_length; 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 rx_range = SoapySDRDevice_getGainRange(handler->device, SOAPY_SDR_RX, 0);
handler->info.min_tx_gain = tx_range.minimum;
@ -268,6 +303,99 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
handler->info.min_rx_gain = rx_range.minimum;
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);
}
// log level
const char loglevel_arg[] = "loglevel=";
char loglevel_str[64] = {0};
char *loglevel_ptr = strstr(args, loglevel_arg);
if (loglevel_ptr) {
copy_subdev_string(loglevel_str, loglevel_ptr + strlen(loglevel_arg));
if (strcmp(loglevel_str, "error") == 0) {
SoapySDR_setLogLevel(SOAPY_SDR_ERROR);
}
remove_substring(args, loglevel_arg);
remove_substring(args, loglevel_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);
}
// 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;
}
@ -293,14 +421,25 @@ int rf_soapy_close(void *h)
SoapySDRDevice_unmake(handler->device);
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;
}
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 +453,75 @@ bool rf_soapy_is_master_clock_dynamic(void *h)
double rf_soapy_set_rx_srate(void *h, double rate)
{
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) {
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);
#endif
if (rx_stream_active) {
rf_soapy_start_rx_stream(handler, true);
}
return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0);
}
double rf_soapy_set_tx_srate(void *h, double rate)
{
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) {
printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError());
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 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);
#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 +552,14 @@ double rf_soapy_set_tx_gain(void *h, double gain)
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 SoapySDRDevice_getGain(handler->device, SOAPY_SDR_RX, 0);
}
double rf_soapy_get_tx_gain(void *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 +582,10 @@ double rf_soapy_set_rx_freq(void *h, double freq)
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);
// Todo: expose antenna setting
if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_RX, 0, "LNAH") != 0) {
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);
// wait until LO is locked
rf_soapy_rx_wait_lo_locked(handler);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
}
@ -410,13 +599,7 @@ double rf_soapy_set_tx_freq(void *h, double freq)
return SRSLTE_ERROR;
}
// Todo: expose antenna name in arguments
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);
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);
}
@ -439,42 +622,59 @@ int rf_soapy_recv_with_time_multi(void *h,
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
int flags; //flags set by receive operation
int num_channels = 1; // temp
const long timeoutUs = 1000000; // arbitrarily chosen
const long timeoutUs = 400000; // arbitrarily chosen
int trials = 0;
int ret = 0;
long long timeNs; //timestamp for receive buffer
int n = 0;
#if PRINT_RX_STATS
printf("rx: nsamples=%d rx_mtu=%zd\n", nsamples, handler->rx_mtu);
#endif
do {
size_t rx_samples = nsamples;
if (rx_samples > nsamples - n){
rx_samples = nsamples - n;
}
size_t rx_samples = 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; i<num_channels; i++){
cf_t *data_c = (cf_t*) data[i];
buffs_ptr[i] = &data_c[n];
}
ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr, rx_samples, &flags, &timeNs, timeoutUs);
if(ret < 0) {
// continue when getting overflows
if (ret == SOAPY_SDR_OVERFLOW) {
fprintf(stderr, "O");
fflush(stderr);
continue;
} else {
return SRSLTE_ERROR;
}
if (ret == SOAPY_SDR_OVERFLOW || (ret > 0 && (flags & SOAPY_SDR_END_ABRUPT) != 0)) {
handler->num_overflows++;
fprintf(stderr, "O");
fflush(stderr);
continue;
} else
if (ret == SOAPY_SDR_TIMEOUT) {
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
if (secs != NULL && frac_secs != NULL) {
// update rx time only for first segment
if (secs != NULL && frac_secs != NULL && n == 0) {
*secs = timeNs / 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;
trials++;
} while (n < nsamples && trials < 100);
@ -522,65 +722,103 @@ int rf_soapy_send_timed_multi(void *h,
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t *) h;
int flags = 0;
const long timeoutUs = 2000; // arbitrarily chosen
const long timeoutUs = 100000; // arbitrarily chosen
long long timeNs = 0;
int trials = 0;
int ret = 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) {
rf_soapy_start_tx_stream(h);
}
if (is_start_of_burst && is_end_of_burst) {
flags |= SOAPY_SDR_ONE_PACKET;
}
if (is_end_of_burst) {
flags |= SOAPY_SDR_END_BURST;
}
// Convert initial tx time
if (has_time_spec) {
flags |= SOAPY_SDR_HAS_TIME;
timeNs = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000);
//printf("time_spec: secs=%d, frac_secs=%lf timeNs=%lld\n", secs, frac_secs, timeNs);
}
do {
#if USE_TX_MTU
size_t tx_samples = MIN(nsamples - n, handler->tx_mtu);
#else
size_t tx_samples = nsamples;
if (tx_samples > nsamples - n) {
tx_samples = nsamples - n;
}
#endif
ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, (const void *)data, tx_samples, &flags, timeNs, timeoutUs);
if (ret == SOAPY_SDR_TIMEOUT) {
printf("L");
continue;
// (re-)set stream flags
flags = 0;
if (is_start_of_burst && is_end_of_burst) {
flags |= SOAPY_SDR_ONE_PACKET;
}
if (ret == SOAPY_SDR_OVERFLOW) {
printf("O");
continue;
if (is_end_of_burst) {
flags |= SOAPY_SDR_END_BURST;
}
if (ret == SOAPY_SDR_UNDERFLOW) {
printf("U");
continue;
// only set time flag for first tx
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) {
fprintf(stderr, "Error during writeStream\n");
exit(-1);
return SRSLTE_ERROR;
// An error has occured
switch (ret) {
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++;
} while (n < nsamples && trials < 100);
if (n != nsamples) {
fprintf(stderr, "Couldn't write all samples.\n");
return SRSLTE_ERROR;
fprintf(stderr, "Couldn't write all samples after %d trials.\n", trials);
}
return ret;
return n;
}

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

@ -32,7 +32,7 @@
#include "srslte/srslte.h"
#include "rf_uhd_imp.h"
#include "srslte/phy/rf/rf.h"
#include "rf_helper.h"
#include "uhd_c_api.h"
#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);
}
#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)
{
if (h) {
@ -807,7 +782,7 @@ int rf_uhd_recv_with_time_multi(void *h,
rxd_samples = 0;
uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr,
num_rx_samples, md, 1.0, false, &rxd_samples);
num_rx_samples, md, 0.1, false, &rxd_samples);
if (error) {
fprintf(stderr, "Error receiving from UHD: %d\n", error);
log_rx_error(handler);
@ -917,7 +892,7 @@ int rf_uhd_send_timed_multi(void *h,
buffs_ptr[i] = buff;
}
uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr,
tx_samples, &handler->tx_md, 3.0, &txd_samples);
tx_samples, &handler->tx_md, 0.1, &txd_samples);
if (error) {
fprintf(stderr, "Error sending to UHD: %d\n", error);
goto unlock;
@ -939,7 +914,7 @@ int rf_uhd_send_timed_multi(void *h,
uhd_tx_metadata_set_has_time_spec(&handler->tx_md, is_start_of_burst);
uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst);
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 3.0, &txd_samples);
uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples);
if (error) {
fprintf(stderr, "Error sending to UHD: %d\n", error);
goto unlock;

@ -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);
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)) {
fprintf(stderr, "Error unpacking DCI\n");
return SRSLTE_ERROR;

@ -23,3 +23,5 @@ if(RF_FOUND)
target_link_libraries(srslte_radio srslte_rf)
install(TARGETS srslte_radio DESTINATION ${LIBRARY_DIR})
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")) {
burst_preamble_sec = blade_default_burst_preamble_sec;
} 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));
}
@ -81,7 +81,9 @@ bool radio::is_init() {
void radio::stop()
{
srslte_rf_close(&rf_device);
if (is_initialized) {
srslte_rf_close(&rf_device);
}
}
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;
}

@ -277,7 +277,7 @@ uint32_t rlc_am::get_buffer_state()
// check if pollRetx timer expired (Section 5.2.2.3 in TS 36.322)
if (poll_retx()) {
// if both tx and retx buffer are empty, retransmit next PDU to be ack'ed
log->info("Poll reTx timer expired (lcid=%d)\n", lcid);
log->debug("Poll reTx timer expired (lcid=%d)\n", lcid);
if ((tx_window.size() > 0 && retx_queue.size() == 0 && tx_sdu_queue.size() == 0)) {
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it = tx_window.find(vt_s - 1);
if (it != tx_window.end()) {

@ -71,7 +71,7 @@ class gtpu
{
public:
bool init(std::string gtp_bind_addr_, std::string mme_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_);
bool init(std::string gtp_bind_addr_, std::string mme_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_, bool enable_mbsfn = false);
void stop();
// gtpu_interface_rrc
@ -90,9 +90,9 @@ private:
bool running;
bool run_enable;
bool mch_running;
bool mch_running;
bool mch_run_enable;
bool _enable_mbsfn;
std::string gtp_bind_addr;
std::string mme_addr;
srsenb::pdcp_interface_gtpu *pdcp;

@ -251,6 +251,8 @@ public:
struct timeval t_last_activity;
LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM establishment_cause;
// S-TMSI for this UE
bool has_tmsi;
uint32_t m_tmsi;

@ -72,8 +72,8 @@ public:
void run_thread();
// RRC interface
void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu);
void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec);
void initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu);
void initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec);
void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu);
bool user_exists(uint16_t rnti);
bool user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio);
@ -128,7 +128,7 @@ private:
bool handle_s1setupfailure(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg);
bool handle_erabsetuprequest(LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg);
bool send_initialuemessage(uint16_t rnti, srslte::byte_buffer_t *pdu, bool has_tmsi, uint32_t m_tmsi=0, uint8_t mmec=0);
bool send_initialuemessage(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu, bool has_tmsi, uint32_t m_tmsi=0, uint8_t mmec=0);
bool send_ulnastransport(uint16_t rnti, srslte::byte_buffer_t *pdu);
bool send_uectxtreleaserequest(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT *cause);
bool send_uectxtreleasecomplete(uint16_t rnti, uint32_t mme_ue_id, uint32_t enb_ue_id);

@ -219,7 +219,7 @@ bool enb::init(all_args_t *args_)
pdcp.init(&rlc, &rrc, &gtpu, &pdcp_log);
rrc.init(&rrc_cfg, &phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &rrc_log);
s1ap.init(args->enb.s1ap, &rrc, &s1ap_log);
gtpu.init(args->enb.s1ap.gtp_bind_addr, args->enb.s1ap.mme_addr, &pdcp, &gtpu_log);
gtpu.init(args->enb.s1ap.gtp_bind_addr, args->enb.s1ap.mme_addr, &pdcp, &gtpu_log, args->expert.enable_mbsfn);
started = true;
return true;

@ -39,10 +39,10 @@
using namespace std;
// Enable this to log SI
//#define LOG_THIS(a) 1
#define LOG_THIS(a) 1
// Enable this one to skip SI-RNTI
#define LOG_THIS(rnti) (rnti != 0xFFFF)
//#define LOG_THIS(rnti) (rnti != 0xFFFF)
/* Define GUI-related things */

@ -34,7 +34,7 @@ using namespace srslte;
namespace srsenb {
bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_interface_gtpu* pdcp_, srslte::log* gtpu_log_)
bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_interface_gtpu* pdcp_, srslte::log* gtpu_log_, bool enable_mbsfn)
{
pdcp = pdcp_;
gtpu_log = gtpu_log_;
@ -95,11 +95,13 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
//Setup M1-u
init_m1u(gtpu_log_);
mch_lcid_counter = 1;
_enable_mbsfn = enable_mbsfn;
// Setup a thread to receive packets from the src socket
start(THREAD_PRIO);
pthread_create(&mch_thread ,NULL ,mch_thread_routine , this);
if(_enable_mbsfn){
mch_lcid_counter = 1;
pthread_create(&mch_thread ,NULL ,mch_thread_routine , this);
}
return true;
}
@ -224,8 +226,9 @@ void gtpu::stop()
}
}
wait_thread_finish();
pthread_join(mch_thread, NULL);
if(_enable_mbsfn) {
pthread_join(mch_thread, NULL);
}
}
if (snk_fd) {

@ -1043,6 +1043,7 @@ void rrc::ue::handle_rrc_con_req(LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *msg)
m_tmsi = msg->ue_id.s_tmsi.m_tmsi;
has_tmsi = true;
}
establishment_cause = msg->cause;
send_connection_setup();
state = RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE;
}
@ -1069,9 +1070,9 @@ void rrc::ue::handle_rrc_con_setup_complete(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE
parent->mac->phy_config_enabled(rnti, true);
if(has_tmsi) {
parent->s1ap->initial_ue(rnti, pdu, m_tmsi, mmec);
parent->s1ap->initial_ue(rnti, (LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM)establishment_cause, pdu, m_tmsi, mmec);
} else {
parent->s1ap->initial_ue(rnti, pdu);
parent->s1ap->initial_ue(rnti, (LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM)establishment_cause, pdu);
}
state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE;
}

@ -174,22 +174,22 @@ void s1ap::build_tai_cgi()
/*******************************************************************************
/* RRC interface
********************************************************************************/
void s1ap::initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu)
void s1ap::initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu)
{
ue_ctxt_map[rnti].eNB_UE_S1AP_ID = next_eNB_UE_S1AP_ID++;
ue_ctxt_map[rnti].stream_id = 1;
ue_ctxt_map[rnti].release_requested = false;
enbid_to_rnti_map[ue_ctxt_map[rnti].eNB_UE_S1AP_ID] = rnti;
send_initialuemessage(rnti, pdu, false);
send_initialuemessage(rnti, cause, pdu, false);
}
void s1ap::initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec)
void s1ap::initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec)
{
ue_ctxt_map[rnti].eNB_UE_S1AP_ID = next_eNB_UE_S1AP_ID++;
ue_ctxt_map[rnti].stream_id = 1;
ue_ctxt_map[rnti].release_requested = false;
enbid_to_rnti_map[ue_ctxt_map[rnti].eNB_UE_S1AP_ID] = rnti;
send_initialuemessage(rnti, pdu, true, m_tmsi, mmec);
send_initialuemessage(rnti, cause, pdu, true, m_tmsi, mmec);
}
void s1ap::write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu)
@ -609,7 +609,7 @@ bool s1ap::handle_s1setupfailure(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg)
/* S1AP message senders
********************************************************************************/
bool s1ap::send_initialuemessage(uint16_t rnti, srslte::byte_buffer_t *pdu, bool has_tmsi, uint32_t m_tmsi, uint8_t mmec)
bool s1ap::send_initialuemessage(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::byte_buffer_t *pdu, bool has_tmsi, uint32_t m_tmsi, uint8_t mmec)
{
if(!mme_connected) {
return false;
@ -662,7 +662,7 @@ bool s1ap::send_initialuemessage(uint16_t rnti, srslte::byte_buffer_t *pdu, bool
// RRC Establishment Cause
initue->RRC_Establishment_Cause.ext = false;
initue->RRC_Establishment_Cause.e = LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_MO_SIGNALLING;
initue->RRC_Establishment_Cause.e = cause;
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending InitialUEMessage for RNTI:0x%x", rnti);
@ -939,7 +939,7 @@ bool s1ap::send_initial_ctxt_setup_failure(uint16_t rnti)
fail->Cause.choice.radioNetwork.ext = false;
fail->Cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_UNSPECIFIED;
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&buf);
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf);
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending InitialContextSetupFailure for RNTI:0x%x", rnti);
ssize_t n_sent = sctp_sendmsg(socket_fd, buf->msg, buf->N_bytes,

@ -78,31 +78,19 @@ public:
uint32_t get_next_mme_ue_s1ap_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 get_enb_ctx(uint16_t sctp_stream);
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_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_mme_ue_s1ap_id(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);
//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);
s1ap_args_t m_s1ap_args;
@ -127,16 +115,11 @@ private:
int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs;
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<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_m_tmsi;

@ -390,7 +390,7 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
return false;
}
gen_rand(rand);
security_milenage_f2345( k,
opc,
rand,
@ -534,7 +534,7 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
mcc,
mnc,
k_asme);
m_hss_log->debug("User MCC : %x MNC : %x \n", mcc, mnc);
m_hss_log->debug_hex(k_asme, 32, "User k_asme : ");
@ -668,7 +668,7 @@ bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx)
m_hss_log->info("User not found. IMSI: %015lu\n",imsi);
return false;
}
*ue_ctx = ue_ctx_it->second;
return true;
}
@ -701,6 +701,7 @@ hss::get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint le
return;
}
std::string
hss::hex_string(uint8_t *hex, int size)
{
@ -712,4 +713,15 @@ hss::hex_string(uint8_t *hex, int size)
}
return ss.str();
}
/*
uint64_t
string_to_imsi()
{
uint64_t imsi = 0;
for(int i=0;i<=14;i++){
imsi += attach_req.eps_mobile_id.imsi[i]*std::pow(10,14-i);
}
return imsi;
}
*/
} //namespace srsepc

@ -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));
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_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;
}
@ -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);
//Delete connected UEs ctx
release_ues_ecm_ctx_in_enb(enb_id);
release_ues_ecm_ctx_in_enb(assoc_id);
//Delete eNB
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;
}
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*
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
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
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();
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);
ue_ecm_ctx_t *ecm_ctx = &ue_ctx->second->ecm_ctx;
m_s1ap_log->info("Releasing UE ECM context. UE-MME S1AP Id: %d\n", ecm_ctx->mme_ue_s1ap_id);
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);
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->mme_ue_s1ap_id = 0;
ecm_ctx->enb_ue_s1ap_id = 0;
m_s1ap_log->console("No UEs to be released\n");
} else {
while(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);
ue_emm_ctx_t *emm_ctx = &ue_ctx->second->emm_ctx;
ue_ecm_ctx_t *ecm_ctx = &ue_ctx->second->ecm_ctx;
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;
}
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);
if(ue_set == m_enb_id_to_ue_ids.end())
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_assoc_to_ue_ids.end())
{
m_s1ap_log->error("Could not find the eNB's UEs.\n");
return false;

@ -372,7 +372,7 @@ s1ap_nas_transport::handle_nas_attach_request(uint32_t enb_ue_s1ap_id,
//Get attach type from attach request
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->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);
@ -514,6 +514,7 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
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_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_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, emm_ctx->security_ctxt.eksi, autn, rand);
@ -626,6 +627,7 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_ue_s1ap_id,
ue_ctx_t *new_ctx = new 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_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);
*reply_flag = true;
@ -675,6 +677,7 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_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_to_enb_set(enb_sri->sinfo_assoc_id,ecm_ctx->mme_ue_s1ap_id);
//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);

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

@ -39,6 +39,7 @@
#include "phy/phy.h"
#include "upper/usim.h"
#include "upper/rrc.h"
#include "upper/nas.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/logger.h"
@ -129,9 +130,7 @@ typedef struct {
usim_args_t usim;
rrc_args_t rrc;
std::string ue_category_str;
std::string apn_name;
std::string apn_user;
std::string apn_pass;
nas_args_t nas;
expert_args_t expert;
}all_args_t;

@ -39,6 +39,13 @@ using srslte::byte_buffer_t;
namespace srsue {
typedef struct {
std::string apn_name;
std::string apn_user;
std::string apn_pass;
bool force_imsi_attach;
} nas_args_t;
// EMM states (3GPP 24.302 v10.0.0)
typedef enum {
EMM_STATE_NULL = 0,

@ -84,9 +84,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"UECapabilityInformation message. Default 0xe6041000")
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
("nas.apn", bpo::value<string>(&args->apn_name)->default_value(""), "Set Access Point Name (APN) for data services")
("nas.user", bpo::value<string>(&args->apn_user)->default_value(""), "Username for CHAP authentication")
("nas.pass", bpo::value<string>(&args->apn_pass)->default_value(""), "Password for CHAP authentication")
("nas.apn", bpo::value<string>(&args->nas.apn_name)->default_value(""), "Set Access Point Name (APN) for data services")
("nas.user", bpo::value<string>(&args->nas.apn_user)->default_value(""), "Username for CHAP authentication")
("nas.pass", bpo::value<string>(&args->nas.apn_pass)->default_value(""), "Password for CHAP authentication")
("nas.force_imsi_attach", bpo::value<bool>(&args->nas.force_imsi_attach)->default_value(false), "Whether to always perform an IMSI attach")
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")

@ -1032,7 +1032,8 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
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])
@ -1082,7 +1083,6 @@ void phch_worker::set_uci_periodic_cqi()
compute_ri(NULL, NULL, NULL);
phy->last_pmi = (uint8_t) ue_dl.pmi[phy->last_ri % SRSLTE_MAX_LAYERS];
srslte_cqi_value_t cqi_report;
ZERO_OBJECT(cqi_report);
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);
}
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;
}
}
@ -1135,7 +1137,6 @@ void phch_worker::set_uci_aperiodic_cqi()
reported RI. For other transmission modes they are reported conditioned on rank 1.
*/
if (rnti_is_set) {
srslte_cqi_value_t cqi_report;
ZERO_OBJECT(cqi_report);
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
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};
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,
grant->n_prb[0], grant->n_prb[0] + grant->L_prb,
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_ri_len > 0 ? (uci_data.uci_ri ? ", ri=1" : ", ri=0") : "",
cfo * 15, timestr,
uci_data.uci_cqi_len > 0 ? ", cqi=" : "",
uci_data.uci_cqi_len > 0 ? cqi_str : "");
// 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 gain = set_power(tx_power);
char str_cqi[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);
char 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);
}
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,
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 > 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_cqi_len > 0 ? ", cqi=" : "",
uci_data.uci_cqi_len > 0 ? str_cqi : "",
uci_data.uci_cqi_len > 0 ? cqi_str : "",
uci_data.scheduling_request ? "yes" : "no",
cfo * 15, timestr);
}

@ -210,7 +210,7 @@ bool ue::init(all_args_t *args_) {
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
srslte_nas_config_t nas_cfg(1, args->apn_name, args->apn_user, args->apn_pass); /* RB_ID_SRB1 */
srslte_nas_config_t nas_cfg(1, args->nas.apn_name, args->nas.apn_user, args->nas.apn_pass, args->nas.force_imsi_attach); /* RB_ID_SRB1 */
nas.init(usim, &rrc, &gw, &nas_log, nas_cfg);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
gw.set_netmask(args->expert.ip_netmask);

@ -1364,6 +1364,11 @@ bool nas::read_ctxt_file(nas_sec_ctxt *ctxt)
return false;
}
if (cfg.force_imsi_attach) {
nas_log->info("Skip reading context from file.\n");
return false;
}
file.open(".ctxt", std::ios::in);
if(file.is_open()) {
if(!readvar(file, "m_tmsi=", &ctxt->guti.m_tmsi)) {return false;}

@ -27,6 +27,7 @@
#include <iostream>
#include "srsue/hdr/upper/usim.h"
#include "srslte/common/log_filter.h"
#include <assert.h>
using namespace srsue;
@ -67,8 +68,6 @@ uint16 mnc = 93;
int main(int argc, char **argv)
{
srslte::log_filter usim_log("USIM");
usim_log.set_level(srslte::LOG_LEVEL_DEBUG);
usim_log.set_hex_limit(100000);
bool net_valid;
uint8_t res[16];
int res_len;
@ -79,18 +78,11 @@ int main(int argc, char **argv)
args.imei = "356092040793011";
args.imsi = "208930000000001";
args.k = "8BAF473F2F8FD09487CCCBD7097C6862";
args.using_op = false;
args.opc = "8e27b6af0e692e750f32667a3b14605d"; // OPc
args.using_op = true;
args.op = "11111111111111111111111111111111";
srsue::usim usim;
usim.init(&args, &usim_log);
if (usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, res, &res_len, k_asme) != AUTH_OK) {
printf("USIM test failed.\n");
return -1;
};
printf("USIM test ok.\n");
return 0;
assert(usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, res, &res_len, k_asme) == AUTH_OK);
}

@ -88,7 +88,7 @@ file_max_size = -1
#
# mode: USIM mode (soft/pcsc)
# algo: Authentication algorithm (xor/milenage)
# opc: 128-bit Operator Ciphered Variant Algorithm Configuration Field (hex)
# op: 128-bit Operator Variant Algorithm Configuration Field (hex)
# k: 128-bit subscriber key (hex)
# imsi: 15 digit International Mobile Subscriber Identity
# imei: 15 digit International Mobile Station Equipment Identity
@ -98,7 +98,7 @@ file_max_size = -1
[usim]
mode = soft
algo = xor
opc = 63BFA50EE6523365FF14C1F45F88737D
op = 63BFA50EE6523365FF14C1F45F88737D
k = 00112233445566778899aabbccddeeff
imsi = 001010123456789
imei = 353490069873319
@ -119,11 +119,16 @@ imei = 353490069873319
#####################################################################
# NAS configuration
#
# apn: Set Access Point Name (APN)
# apn: Set Access Point Name (APN)
# user: Username for CHAP authentication
# pass: Password for CHAP authentication
# force_imsi_attach: Whether to always perform an IMSI
#####################################################################
[nas]
# apn = internetinternet
#apn = internetinternet
#user = srsuser
#pass = srspass
#force_imsi_attach = false
[gui]
enable = false

Loading…
Cancel
Save