Merge branch 'next' into next_novolk

master
Ismael Gomez 7 years ago
commit 1dff82065b

@ -1,6 +1,11 @@
Change Log for Releases
==============================
## 17.09
* Added MIMO 2x2 in the PHY layer and srsUE (i.e. TM3/TM4)
* eMBMS support in the PHY layer
* Many bug-fixes and improved stability and performance in srsUE/srsENB
## 002.000.000
* Added fully functional srsENB to srsLTE code
* Merged srsUE code into srsLTE and reestructured PHY code

@ -15,12 +15,13 @@ srsLTE is released under the AGPLv3 license and uses software from the OpenLTE p
Common Features
---------------
* LTE Release 8 compliant
* LTE Release 8 compliant (with selected features of Release 9)
* FDD configuration
* Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz
* Transmission mode 1 (single antenna) and 2 (transmit diversity)
* Transmission mode 1 (single antenna), 2 (transmit diversity), 3 (CCD) and 4 (closed-loop spatial multiplexing)
* Frequency-based ZF and MMSE equalizer
* Highly optimized Turbo Decoder available in Intel SSE4.1/AVX (+100 Mbps) and standard C (+25 Mbps)
* Evolved multimedia broadcast and multicast service (eMBMS)
* Highly optimized Turbo Decoder available in Intel SSE4.1/AVX2 (+100 Mbps) and standard C (+25 Mbps)
* MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers
* Detailed log system with per-layer log levels and hex dumps
* MAC layer wireshark packet capture
@ -33,6 +34,7 @@ srsUE Features
* Cell search and synchronization procedure for the UE
* Soft USIM supporting Milenage and XOR authentication
* Virtual network interface *tun_srsue* created upon network attach
* +100 Mbps DL in 20 MHz MIMO TM4 configuration in i7 Quad-Core CPU.
* 75 Mbps DL in 20 MHz SISO configuration in i7 Quad-Core CPU.
* 36 Mbps DL in 10 MHz SISO configuration in i5 Dual-Core CPU.
@ -55,6 +57,8 @@ srsENB has been tested and validated with the following handsets:
* LG Nexus 5
* LG Nexus 4
* Motorola Moto G4 plus
* Huawei P9/P9lite
* Huawei dongles: E3276 and E398
Hardware
--------
@ -65,7 +69,7 @@ We have tested the following hardware:
* USRP B210
* USRP X300
* bladeRF
* limeSDR
* limeSDR (currently, only the PHY-layer examples, i.e., pdsch_enodeb/ue are supported)
Build Instructions
------------------

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
SET(SRSLTE_VERSION_MAJOR 002)
SET(SRSLTE_VERSION_MINOR 000)
SET(SRSLTE_VERSION_PATCH 000)
SET(SRSLTE_VERSION_MAJOR 17)
SET(SRSLTE_VERSION_MINOR 9)
SET(SRSLTE_VERSION_PATCH 0)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -113,7 +113,7 @@ inline bool mnc_to_string(uint16_t mnc, std::string *str)
*str += (mnc & 0x000F) + '0';
return true;
}
inline std::string plmn_id_to_c_str(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
inline std::string plmn_id_to_string(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
std::string mcc_str, mnc_str;
mnc_to_string(plmn_id.mnc, &mnc_str);
mcc_to_string(plmn_id.mcc, &mcc_str);

@ -44,12 +44,12 @@
#define SRSLTE_N_DRB 8
#define SRSLTE_N_RADIO_BEARERS 11
#define HARQ_DELAY_MS 6
#define HARQ_DELAY_MS 4
#define MSG3_DELAY_MS 6
#define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240)
#define TTI_RX_ACK(tti) ((tti+(2*HARQ_DELAY_MS))%10240)
#define TTIMOD_SZ 20
#define TTIMOD_SZ (((2*HARQ_DELAY_MS) < 10)?10:20)
#define TTIMOD(tti) (tti%TTIMOD_SZ)
#define ASYNC_DL_SCHED (HARQ_DELAY_MS <= 4)

@ -54,6 +54,7 @@ class usim_interface_nas
public:
virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0;
virtual void generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb,
uint16_t mcc,
@ -104,6 +105,7 @@ public:
virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0;
};
// NAS interface for UE
@ -140,6 +142,7 @@ class rrc_interface_phy
public:
virtual void in_sync() = 0;
virtual void out_of_sync() = 0;
virtual void earfcn_end() = 0;
virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0;
};

@ -66,7 +66,7 @@ uint8_t* pdu_queue::request(uint32_t len)
void pdu_queue::deallocate(uint8_t* pdu)
{
if (!pool.deallocate((pdu_t*) pdu)) {
log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n");
log_h->warning("Error deallocating from buffer pool in deallocate(): buffer not created in this pool.\n");
}
}
@ -92,7 +92,7 @@ bool pdu_queue::process_pdus()
callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp);
}
if (!pool.deallocate(pdu)) {
log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n");
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
}
cnt++;
have_data = true;

@ -232,6 +232,7 @@ int main(int argc, char **argv) {
srslte_vec_save_file(output_filename,buffer,11*flen*sizeof(cf_t));
srslte_rf_close(&rf);
srslte_prach_free(p);
free(p);

@ -177,7 +177,7 @@ static rf_dev_t dev_soapy = {
rf_soapy_recv_with_time,
rf_soapy_recv_with_time_multi,
rf_soapy_send_timed,
.srslte_rf_send_timed_multi = /* FIXME: Implement srslte_rf_send_timed_multi for Soapy SDR */ NULL,
.srslte_rf_send_timed_multi = rf_soapy_send_timed_multi,
rf_soapy_set_tx_cal,
rf_soapy_set_rx_cal
};

@ -88,12 +88,12 @@ void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t ne
}
char* rf_soapy_devname(void* h)
{
return "soapy";
}
bool rf_soapy_rx_wait_lo_locked(void *h)
{
printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n");
@ -155,7 +155,6 @@ int rf_soapy_stop_tx_stream(void *h)
if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0)
return SRSLTE_ERROR;
handler->tx_stream_active = false;
return SRSLTE_SUCCESS;
}
@ -175,7 +174,7 @@ void rf_soapy_flush_buffer(void *h)
bool rf_soapy_has_rssi(void *h)
{
printf("TODO: implement rf_soapy_has_rssi()\n");
// TODO: implement rf_soapy_has_rssi()
return false;
}
@ -199,9 +198,8 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
}
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("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]);
}
printf("\n");
@ -221,7 +219,6 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
handler->tx_stream_active = false;
handler->rx_stream_active = false;
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) {
@ -251,12 +248,12 @@ int rf_soapy_open(char *args, void **h)
int rf_soapy_close(void *h)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (handler->txStream) {
if (handler->tx_stream_active) {
rf_soapy_stop_tx_stream(handler);
SoapySDRDevice_closeStream(handler->device, handler->txStream);
}
if (handler->rxStream) {
if (handler->rx_stream_active) {
rf_soapy_stop_rx_stream(handler);
SoapySDRDevice_closeStream(handler->device, handler->rxStream);
}
@ -285,9 +282,15 @@ double rf_soapy_set_rx_srate(void *h, double rate)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) {
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError());
printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_RX, 0, rate) != 0) {
printf("setBandwidth Rx failed: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0);
}
@ -295,9 +298,15 @@ double rf_soapy_set_tx_srate(void *h, double rate)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) {
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError());
printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_TX, 0, rate) != 0) {
printf("setBandwidth Tx failed: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0);
}
@ -349,6 +358,14 @@ double rf_soapy_set_rx_freq(void *h, double freq)
return SRSLTE_ERROR;
}
// 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);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
}
@ -360,14 +377,25 @@ double rf_soapy_set_tx_freq(void *h, double freq)
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0);
// 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);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0);
}
void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs) {
void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs)
{
printf("Todo: implement rf_soapy_get_time()\n");
}
//TODO: add multi-channel support
int rf_soapy_recv_with_time_multi(void *h,
void **data,
@ -395,7 +423,7 @@ int rf_soapy_recv_with_time_multi(void *h,
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, 1000000);
ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr, rx_samples, &flags, &timeNs, 10000);
if(ret < 0) {
// continue when getting overflows
if (ret == SOAPY_SDR_OVERFLOW) {
@ -407,17 +435,23 @@ int rf_soapy_recv_with_time_multi(void *h,
}
}
// update rx time
if (secs != NULL && frac_secs != NULL) {
*secs = timeNs / 1e9;
*frac_secs = (timeNs % 1000000000)/1e9;
//printf("rx_time: secs=%d, frac_secs=%lf timeNs=%lld\n", *secs, *frac_secs, timeNs);
}
n += ret;
trials++;
} while (n < nsamples && trials < 100);
//*secs = timeNs / 1000000000;
//*frac_secs = (timeNs % 1000000000)/1000000000;
// printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs);
return n;
}
int rf_soapy_recv_with_time(void *h,
void *data,
uint32_t nsamples,
@ -439,40 +473,83 @@ int rf_soapy_send_timed(void *h,
bool is_start_of_burst,
bool is_end_of_burst)
{
void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem};
return rf_soapy_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
}
int flags;
long long timeNs;
// Todo: Check correct handling of flags, use RF metrics API, fix timed transmissions
int rf_soapy_send_timed_multi(void *h,
void *data[SRSLTE_MAX_PORTS],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t *) h;
int flags = 0;
const long timeoutUs = 2000; // arbitrarily chosen
long long timeNs = 0;
int trials = 0;
int ret = 0;
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
timeNs = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000);
int n = 0;
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;
}
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);
}
cf_t *data_c = (cf_t*) data;
do {
size_t tx_samples = nsamples;
if (tx_samples > nsamples - n) {
tx_samples = nsamples - n;
}
void *buff = (void*) &data_c[n];
const void *buffs_ptr[1] = {buff};
ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, buffs_ptr, tx_samples, &flags, timeNs, 10000);
if(ret < 0)
ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, (const void *)data, tx_samples, &flags, timeNs, timeoutUs);
if (ret == SOAPY_SDR_TIMEOUT) {
printf("L");
continue;
}
if (ret == SOAPY_SDR_OVERFLOW) {
printf("O");
continue;
}
if (ret == SOAPY_SDR_UNDERFLOW) {
printf("U");
continue;
}
if (ret < 0) {
fprintf(stderr, "Error during writeStream\n");
exit(-1);
return SRSLTE_ERROR;
}
n += ret;
trials++;
} while (n < nsamples && trials < 100);
if(ret != nsamples)
if (n != nsamples) {
fprintf(stderr, "Couldn't write all samples.\n");
return SRSLTE_ERROR;
}
return ret;
}

@ -116,3 +116,12 @@ SRSLTE_API int rf_soapy_send_timed(void *h,
bool is_start_of_burst,
bool is_end_of_burst);
int rf_soapy_send_timed_multi(void *h,
void *data[4],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);

@ -513,10 +513,10 @@ void rlc_um::reassemble_rx_sdus()
}
// Handle last segment
// Handle last segment
if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES ||
rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES ||
rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES) {
if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES &&
rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES &&
rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES)
{
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes);
rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes;

@ -100,7 +100,7 @@ filename = /tmp/enb.pcap
#
# filename: File path to use for log output. Can be set to stdout
# to print logs to standard output
git c#####################################################################
#####################################################################
[log]
all_level = info
all_hex_limit = 32

@ -619,6 +619,7 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
tbs, user->get_pending_dl_new_data(current_tti));
}
} else {
h->reset();
Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id());
}
}
@ -782,6 +783,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
user->get_locations(current_cfi, sf_idx),
aggr_level))
{
h->reset();
log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n",
rnti, h->get_id(), aggr_level);
sched_result->pusch[nof_dci_elems].needs_pdcch = false;

@ -29,6 +29,7 @@
#include <srslte/interfaces/sched_interface.h>
#include <srslte/phy/phch/pucch.h>
#include <srslte/srslte.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/srslte.h"
#include "srslte/common/pdu.h"
@ -699,10 +700,16 @@ uint32_t sched_ue::get_aggr_level(uint32_t nof_bits)
uint32_t l=0;
float max_coderate = srslte_cqi_to_coderate(dl_cqi);
float coderate = 99;
float factor=1.5;
uint32_t l_max = 3;
if (cell.nof_prb == 6) {
factor = 1.0;
l_max = 2;
}
do {
coderate = srslte_pdcch_coderate(nof_bits, l);
l++;
} while(l<3 && 1.5*coderate > max_coderate);
} while(l<l_max && factor*coderate > max_coderate);
Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate);
return l;
}

@ -91,10 +91,10 @@ public:
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
void plmn_search_end();
// UE interface
void attach_request();
void deattach_request();
private:

@ -177,8 +177,8 @@ private:
// PHY interface
void in_sync();
void out_of_sync();
void earfcn_end();
void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
// MAC interface

@ -61,6 +61,7 @@ public:
// NAS interface
void get_imsi_vec(uint8_t* imsi_, uint32_t n);
void get_imei_vec(uint8_t* imei_, uint32_t n);
int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
void generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb,
@ -119,6 +120,8 @@ private:
uint8_t k_asme[32];
uint8_t k_enb[32];
bool initiated;
};
} // namespace srsue

@ -307,7 +307,6 @@ void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::
void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
log_h->info("new_grant_ul_ack\n");
int tbs = ul_harq.get_current_tbs(tti);
ul_harq.new_grant_ul_ack(grant, ack, action);
if (!ack) {

@ -171,6 +171,7 @@ void phch_recv::radio_error() {
// Need to find a method to effectively reset radio, reloading the driver does not work
//radio_h->reset();
radio_h->stop();
fprintf(stdout, "Error while receiving samples. Restart srsUE\n");
exit(-1);
@ -478,6 +479,7 @@ void phch_recv::cell_search_inc()
if (cur_earfcn_index >= 0) {
if (cur_earfcn_index >= (int) earfcn.size() - 1) {
cur_earfcn_index = 0;
rrc->earfcn_end();
}
}
Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size());

@ -922,16 +922,16 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui
#ifdef LOG_EXECTIME
gettimeofday(&logtime_start[2], NULL);
get_time_interval(logtime_start);
snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec);
snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec);
#endif
Info("PUSCH: tti_tx=%d, n_prb=%d, rb_start=%d, tbs=%d, mod=%d, mcs=%d, rv_idx=%d, ack=%s, ri=%s, cfo=%.1f Hz%s\n",
TTI_TX(tti),
grant->L_prb, grant->n_prb[0],
grant->mcs.tbs/8, grant->mcs.mod, grant->mcs.idx, rv,
Info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n",
(tti+4)%10240,
grant->n_prb[0], grant->n_prb[0]+grant->L_prb,
grant->mcs.tbs/8, grant->mcs.idx, rv,
uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",
uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no",
cfo*15000, timestr);
cfo*15, timestr);
// Store metrics
ul_metrics.mcs = grant->mcs.idx;
@ -966,22 +966,22 @@ void phch_worker::encode_pucch()
memcpy(&t[2], &logtime_start[2], sizeof(struct timeval));
get_time_interval(logtime_start);
get_time_interval(t);
snprintf(timestr, 64, ", enc_time=%d, total_time=%d us", (int) t[0].tv_usec, (int) logtime_start[0].tv_usec);
snprintf(timestr, 64, ", tot_time=%d us", (int) logtime_start[0].tv_usec);
#endif
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);
Info("PUCCH: tti_tx=%d, n_cce=%3d, n_pucch=%d, n_prb=%d, ack=%s%s, ri=%s, pmi=%s%s, sr=%s, cfo=%.1f Hz%s\n",
TTI_TX(tti),
last_dl_pdcch_ncce, ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb,
Info("PUCCH: tti_tx=%d, n_pucch=%d, n_prb=%d, ack=%s%s, ri=%s, pmi=%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?"1":"0"):"no",
uci_data.uci_pmi_len>0?(uci_data.uci_pmi[1]?"1":"0"):"no",
uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"",
uci_data.scheduling_request?"yes":"no",
cfo*15000, timestr);
cfo*15, timestr);
}
if (uci_data.scheduling_request) {
@ -1002,7 +1002,7 @@ void phch_worker::encode_srs()
#ifdef LOG_EXECTIME
gettimeofday(&logtime_start[2], NULL);
get_time_interval(logtime_start);
snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec);
snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec);
#endif
float tx_power = srslte_ue_ul_srs_power(&ue_ul, phy->pathloss);

@ -181,11 +181,10 @@ 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);
usim.init(&args->usim, &usim_log);
nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
usim.init(&args->usim, &usim_log);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log);
rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str()));

@ -50,8 +50,12 @@ void nas::init(usim_interface_nas *usim_,
nas_log = nas_log_;
state = EMM_STATE_DEREGISTERED;
plmn_selection = PLMN_NOT_SELECTED;
if (usim->get_home_plmn_id(&home_plmn)) {
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n");
home_plmn.mcc = 61441; // This is 001
home_plmn.mnc = 65281; // This is 01
}
cfg = cfg_;
}
@ -64,6 +68,7 @@ emm_state_t nas::get_state() {
/*******************************************************************************
UE interface
*******************************************************************************/
void nas::attach_request() {
nas_log->info("Attach Request\n");
if (state == EMM_STATE_DEREGISTERED) {
@ -72,7 +77,7 @@ void nas::attach_request() {
nas_log->info("Starting PLMN Search...\n");
rrc->plmn_search();
} else if (plmn_selection == PLMN_SELECTED) {
nas_log->info("Selecting PLMN %s\n", plmn_id_to_c_str(current_plmn).c_str());
nas_log->info("Selecting PLMN %s\n", plmn_id_to_string(current_plmn).c_str());
rrc->plmn_select(current_plmn);
selecting_plmn = current_plmn;
}
@ -96,25 +101,49 @@ RRC interface
void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
// Store PLMN if not registered
// Check if already registered
for (uint32_t i=0;i<known_plmns.size();i++) {
if (plmn_id.mcc == known_plmns[i].mcc && plmn_id.mnc == known_plmns[i].mnc) {
nas_log->info("Detected known PLMN %s\n", plmn_id_to_c_str(plmn_id).c_str());
nas_log->info("Found known PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
nas_log->info("Connecting Home PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
rrc->plmn_select(plmn_id);
selecting_plmn = plmn_id;
}
return;
}
}
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_c_str(plmn_id).c_str(),
// Save if new PLMN
known_plmns.push_back(plmn_id);
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
tracking_area_code);
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_c_str(plmn_id).c_str(),
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
tracking_area_code);
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
rrc->plmn_select(plmn_id);
selecting_plmn = plmn_id;
}
}
// RRC indicates that the UE has gone through all EARFCN and finished PLMN selection
void nas::plmn_search_end() {
if (known_plmns.size() > 0) {
nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
plmn_id_to_string(home_plmn).c_str(),
plmn_id_to_string(known_plmns[0]).c_str());
nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
plmn_id_to_string(home_plmn).c_str(),
plmn_id_to_string(known_plmns[0]).c_str());
rrc->plmn_select(known_plmns[0]);
} else {
nas_log->debug("Finished searching PLMN in current EARFCN set but no networks were found.\n");
}
}
bool nas::is_attached() {

@ -177,7 +177,7 @@ void rrc::run_thread() {
case RRC_STATE_PLMN_SELECTION:
plmn_select_timeout++;
if (plmn_select_timeout >= RRC_PLMN_SELECT_TIMEOUT) {
rrc_log->info("RRC PLMN Search: timeout expired. Searching again\n");
rrc_log->info("RRC PLMN Search: timeout expired\n");
phy->cell_search_stop();
sleep(1);
rrc_log->console("\nRRC PLMN Search: timeout expired. Searching again\n");
@ -369,7 +369,7 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
state = RRC_STATE_CELL_SELECTING;
select_cell_timeout = 0;
} else {
rrc_log->info("PLMN %s selected\n", plmn_id_to_c_str(plmn_id).c_str());
rrc_log->info("PLMN Id=%s selected\n", plmn_id_to_string(plmn_id).c_str());
// Sort cells according to RSRP
selected_plmn_id = plmn_id;
@ -427,10 +427,12 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) {
if (!known_cells[i].has_valid_sib1) {
si_acquire_state = SI_ACQUIRE_SIB1;
} else {
} else if (state == RRC_STATE_PLMN_SELECTION) {
for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) {
nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code);
}
usleep(5000);
phy->cell_search_next();
}
return;
}
@ -454,6 +456,15 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) {
cell.earfcn, cell.rsrp);
}
// PHY indicates that has gone through all known EARFCN
void rrc::earfcn_end() {
rrc_log->debug("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]);
// If searching for PLMN, indicate NAS we scanned all frequencies
if (state == RRC_STATE_PLMN_SELECTION) {
nas->plmn_search_end();
}
}

@ -25,13 +25,15 @@
*/
#include <sstream>
#include "upper/usim.h"
#include "srslte/common/bcd_helpers.h"
using namespace srslte;
namespace srsue{
usim::usim()
usim::usim() : initiated(false)
{}
void usim::init(usim_args_t *args, srslte::log *usim_log_)
@ -91,6 +93,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
if("xor" == args->algo) {
auth_algo = auth_algo_xor;
}
initiated = true;
}
void usim::stop()
@ -102,6 +105,11 @@ void usim::stop()
void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
{
if (!initiated)
{
usim_log->error("Getting IMSI: USIM not initiated\n");
return;
}
if(NULL == imsi_ || n < 15)
{
usim_log->error("Invalid parameters to get_imsi_vec");
@ -118,6 +126,11 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
{
if (!initiated)
{
usim_log->error("Getting IMEI: USIM not initiated\n");
return;
}
if(NULL == imei_ || n < 15)
{
usim_log->error("Invalid parameters to get_imei_vec");
@ -132,6 +145,48 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
}
}
int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
{
if (!initiated)
{
usim_log->error("Getting Home PLMN Id: USIM not initiated\n");
return -1;
}
int mcc_len = 3;
int mnc_len = 2;
uint8_t imsi_vec[15];
get_imsi_vec(imsi_vec, 15);
std::ostringstream mcc_str, mnc_str;
for (int i=0;i<mcc_len;i++) {
mcc_str << (int) imsi_vec[i];
}
// US MCC uses 3 MNC digits
if (!mcc_str.str().compare("310") ||
!mcc_str.str().compare("311") ||
!mcc_str.str().compare("312") ||
!mcc_str.str().compare("313") ||
!mcc_str.str().compare("316"))
{
mnc_len = 3;
}
for (int i=mcc_len;i<mcc_len+mnc_len;i++) {
mnc_str << (int) imsi_vec[i];
}
string_to_mcc(mcc_str.str(), &home_plmn_id->mcc);
string_to_mnc(mnc_str.str(), &home_plmn_id->mnc);
usim_log->info("Read Home PLMN Id=%s\n",
plmn_id_to_string(*home_plmn_id).c_str());
return 0;
}
void usim::generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb,
uint16_t mcc,

Loading…
Cancel
Save