Merge branch 'next' into next_novolk

master
Ismael Gomez 7 years ago
commit 1dff82065b

@ -1,6 +1,11 @@
Change Log for Releases 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 ## 002.000.000
* Added fully functional srsENB to srsLTE code * Added fully functional srsENB to srsLTE code
* Merged srsUE code into srsLTE and reestructured PHY 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 Common Features
--------------- ---------------
* LTE Release 8 compliant * LTE Release 8 compliant (with selected features of Release 9)
* FDD configuration * FDD configuration
* Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz * 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 * 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 * MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers
* Detailed log system with per-layer log levels and hex dumps * Detailed log system with per-layer log levels and hex dumps
* MAC layer wireshark packet capture * MAC layer wireshark packet capture
@ -33,6 +34,7 @@ srsUE Features
* Cell search and synchronization procedure for the UE * Cell search and synchronization procedure for the UE
* Soft USIM supporting Milenage and XOR authentication * Soft USIM supporting Milenage and XOR authentication
* Virtual network interface *tun_srsue* created upon network attach * 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. * 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. * 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 5
* LG Nexus 4 * LG Nexus 4
* Motorola Moto G4 plus * Motorola Moto G4 plus
* Huawei P9/P9lite
* Huawei dongles: E3276 and E398
Hardware Hardware
-------- --------
@ -65,7 +69,7 @@ We have tested the following hardware:
* USRP B210 * USRP B210
* USRP X300 * USRP X300
* bladeRF * bladeRF
* limeSDR * limeSDR (currently, only the PHY-layer examples, i.e., pdsch_enodeb/ue are supported)
Build Instructions Build Instructions
------------------ ------------------

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/. # and at http://www.gnu.org/licenses/.
# #
SET(SRSLTE_VERSION_MAJOR 002) SET(SRSLTE_VERSION_MAJOR 17)
SET(SRSLTE_VERSION_MINOR 000) SET(SRSLTE_VERSION_MINOR 9)
SET(SRSLTE_VERSION_PATCH 000) SET(SRSLTE_VERSION_PATCH 0)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}") 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'; *str += (mnc & 0x000F) + '0';
return true; 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; std::string mcc_str, mnc_str;
mnc_to_string(plmn_id.mnc, &mnc_str); mnc_to_string(plmn_id.mnc, &mnc_str);
mcc_to_string(plmn_id.mcc, &mcc_str); mcc_to_string(plmn_id.mcc, &mcc_str);

@ -44,12 +44,12 @@
#define SRSLTE_N_DRB 8 #define SRSLTE_N_DRB 8
#define SRSLTE_N_RADIO_BEARERS 11 #define SRSLTE_N_RADIO_BEARERS 11
#define HARQ_DELAY_MS 6 #define HARQ_DELAY_MS 4
#define MSG3_DELAY_MS 6 #define MSG3_DELAY_MS 6
#define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240) #define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240)
#define TTI_RX_ACK(tti) ((tti+(2*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 TTIMOD(tti) (tti%TTIMOD_SZ)
#define ASYNC_DL_SCHED (HARQ_DELAY_MS <= 4) #define ASYNC_DL_SCHED (HARQ_DELAY_MS <= 4)

@ -54,6 +54,7 @@ class usim_interface_nas
public: public:
virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; 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 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, virtual void generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
@ -104,6 +105,7 @@ public:
virtual uint32_t get_ul_count() = 0; virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 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_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0;
}; };
// NAS interface for UE // NAS interface for UE
@ -140,6 +142,7 @@ class rrc_interface_phy
public: public:
virtual void in_sync() = 0; virtual void in_sync() = 0;
virtual void out_of_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; 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) void pdu_queue::deallocate(uint8_t* pdu)
{ {
if (!pool.deallocate((pdu_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); callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp);
} }
if (!pool.deallocate(pdu)) { 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++; cnt++;
have_data = true; have_data = true;

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

@ -177,7 +177,7 @@ static rf_dev_t dev_soapy = {
rf_soapy_recv_with_time, rf_soapy_recv_with_time,
rf_soapy_recv_with_time_multi, rf_soapy_recv_with_time_multi,
rf_soapy_send_timed, 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_tx_cal,
rf_soapy_set_rx_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) char* rf_soapy_devname(void* h)
{ {
return "soapy"; return "soapy";
} }
bool rf_soapy_rx_wait_lo_locked(void *h) bool rf_soapy_rx_wait_lo_locked(void *h)
{ {
printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n"); 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) if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0)
return SRSLTE_ERROR; return SRSLTE_ERROR;
handler->tx_stream_active = false; handler->tx_stream_active = false;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -175,7 +174,7 @@ void rf_soapy_flush_buffer(void *h)
bool rf_soapy_has_rssi(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; 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++) { 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]);
} }
printf("\n"); 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->tx_stream_active = false;
handler->rx_stream_active = false; handler->rx_stream_active = false;
if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_RX) > 0){ 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) {
@ -251,12 +248,12 @@ int rf_soapy_open(char *args, void **h)
int rf_soapy_close(void *h) int rf_soapy_close(void *h)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) 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); rf_soapy_stop_tx_stream(handler);
SoapySDRDevice_closeStream(handler->device, handler->txStream); SoapySDRDevice_closeStream(handler->device, handler->txStream);
} }
if (handler->rxStream) { if (handler->rx_stream_active) {
rf_soapy_stop_rx_stream(handler); rf_soapy_stop_rx_stream(handler);
SoapySDRDevice_closeStream(handler->device, handler->rxStream); 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; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { 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; 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); 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; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { 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; 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); return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0);
} }
@ -348,7 +357,15 @@ 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;
} }
// 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); 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()); printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; 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);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0); 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 //TODO: add multi-channel support
int rf_soapy_recv_with_time_multi(void *h, int rf_soapy_recv_with_time_multi(void *h,
void **data, void **data,
@ -395,7 +423,7 @@ int rf_soapy_recv_with_time_multi(void *h,
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, 1000000); ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr, rx_samples, &flags, &timeNs, 10000);
if(ret < 0) { if(ret < 0) {
// continue when getting overflows // continue when getting overflows
if (ret == SOAPY_SDR_OVERFLOW) { 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; n += ret;
trials++; trials++;
} while (n < nsamples && trials < 100); } 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; return n;
} }
int rf_soapy_recv_with_time(void *h, int rf_soapy_recv_with_time(void *h,
void *data, void *data,
uint32_t nsamples, uint32_t nsamples,
@ -430,49 +464,92 @@ int rf_soapy_recv_with_time(void *h,
int rf_soapy_send_timed(void *h, int rf_soapy_send_timed(void *h,
void *data, void *data,
int nsamples, int nsamples,
time_t secs, time_t secs,
double frac_secs, double frac_secs,
bool has_time_spec, bool has_time_spec,
bool blocking, bool blocking,
bool is_start_of_burst, bool is_start_of_burst,
bool is_end_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);
}
// 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; int flags = 0;
long long timeNs; const long timeoutUs = 2000; // arbitrarily chosen
int trials = 0; long long timeNs = 0;
int ret = 0; int trials = 0;
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; int ret = 0;
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 = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000); timeNs = timeNs + (frac_secs * 1000000000);
int n = 0; //printf("time_spec: secs=%d, frac_secs=%lf timeNs=%lld\n", secs, frac_secs, timeNs);
}
if(!handler->tx_stream_active){ do {
rf_soapy_start_tx_stream(h); size_t tx_samples = nsamples;
if (tx_samples > nsamples - n) {
tx_samples = nsamples - n;
} }
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)
return SRSLTE_ERROR;
n += ret;
trials++;
}while (n < nsamples && trials < 100);
if(ret != nsamples)
return SRSLTE_ERROR;
return ret;
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 (n != nsamples) {
fprintf(stderr, "Couldn't write all samples.\n");
return SRSLTE_ERROR;
}
return ret;
} }

@ -106,7 +106,7 @@ SRSLTE_API void rf_soapy_get_time(void *h,
time_t *secs, time_t *secs,
double *frac_secs); double *frac_secs);
SRSLTE_API int rf_soapy_send_timed(void *h, SRSLTE_API int rf_soapy_send_timed(void *h,
void *data, void *data,
int nsamples, int nsamples,
time_t secs, time_t secs,
@ -116,3 +116,12 @@ SRSLTE_API int rf_soapy_send_timed(void *h,
bool is_start_of_burst, bool is_start_of_burst,
bool is_end_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
// Handle last segment if (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 < SRSLTE_MAX_BUFFER_SIZE_BYTES || rx_window[vr_ur].buf->N_bytes + rx_sdu->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); 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; 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 # filename: File path to use for log output. Can be set to stdout
# to print logs to standard output # to print logs to standard output
git c##################################################################### #####################################################################
[log] [log]
all_level = info all_level = info
all_hex_limit = 32 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)); tbs, user->get_pending_dl_new_data(current_tti));
} }
} else { } else {
h->reset();
Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); 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), user->get_locations(current_cfi, sf_idx),
aggr_level)) aggr_level))
{ {
h->reset();
log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n", log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n",
rnti, h->get_id(), aggr_level); rnti, h->get_id(), aggr_level);
sched_result->pusch[nof_dci_elems].needs_pdcch = false; sched_result->pusch[nof_dci_elems].needs_pdcch = false;

@ -29,6 +29,7 @@
#include <srslte/interfaces/sched_interface.h> #include <srslte/interfaces/sched_interface.h>
#include <srslte/phy/phch/pucch.h> #include <srslte/phy/phch/pucch.h>
#include <srslte/srslte.h> #include <srslte/srslte.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srslte/common/pdu.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; uint32_t l=0;
float max_coderate = srslte_cqi_to_coderate(dl_cqi); float max_coderate = srslte_cqi_to_coderate(dl_cqi);
float coderate = 99; float coderate = 99;
float factor=1.5;
uint32_t l_max = 3;
if (cell.nof_prb == 6) {
factor = 1.0;
l_max = 2;
}
do { do {
coderate = srslte_pdcch_coderate(nof_bits, l); coderate = srslte_pdcch_coderate(nof_bits, l);
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); 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; return l;
} }

@ -91,10 +91,10 @@ public:
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); 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_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
void plmn_search_end();
// UE interface // UE interface
void attach_request(); void attach_request();
void deattach_request(); void deattach_request();
private: private:

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

@ -61,6 +61,7 @@ public:
// NAS interface // NAS interface
void get_imsi_vec(uint8_t* imsi_, uint32_t n); void get_imsi_vec(uint8_t* imsi_, uint32_t n);
void get_imei_vec(uint8_t* imei_, 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, void generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
@ -119,6 +120,8 @@ private:
uint8_t k_asme[32]; uint8_t k_asme[32];
uint8_t k_enb[32]; uint8_t k_enb[32];
bool initiated;
}; };
} // namespace srsue } // 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) 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); int tbs = ul_harq.get_current_tbs(tti);
ul_harq.new_grant_ul_ack(grant, ack, action); ul_harq.new_grant_ul_ack(grant, ack, action);
if (!ack) { 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 // Need to find a method to effectively reset radio, reloading the driver does not work
//radio_h->reset(); //radio_h->reset();
radio_h->stop();
fprintf(stdout, "Error while receiving samples. Restart srsUE\n"); fprintf(stdout, "Error while receiving samples. Restart srsUE\n");
exit(-1); exit(-1);
@ -478,6 +479,7 @@ void phch_recv::cell_search_inc()
if (cur_earfcn_index >= 0) { if (cur_earfcn_index >= 0) {
if (cur_earfcn_index >= (int) earfcn.size() - 1) { if (cur_earfcn_index >= (int) earfcn.size() - 1) {
cur_earfcn_index = 0; cur_earfcn_index = 0;
rrc->earfcn_end();
} }
} }
Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); 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 #ifdef LOG_EXECTIME
gettimeofday(&logtime_start[2], NULL); gettimeofday(&logtime_start[2], NULL);
get_time_interval(logtime_start); 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 #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", Info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n",
TTI_TX(tti), (tti+4)%10240,
grant->L_prb, grant->n_prb[0], grant->n_prb[0], grant->n_prb[0]+grant->L_prb,
grant->mcs.tbs/8, grant->mcs.mod, grant->mcs.idx, rv, grant->mcs.tbs/8, grant->mcs.idx, rv,
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_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no",
cfo*15000, timestr); cfo*15, timestr);
// Store metrics // Store metrics
ul_metrics.mcs = grant->mcs.idx; ul_metrics.mcs = grant->mcs.idx;
@ -966,23 +966,23 @@ void phch_worker::encode_pucch()
memcpy(&t[2], &logtime_start[2], sizeof(struct timeval)); memcpy(&t[2], &logtime_start[2], sizeof(struct timeval));
get_time_interval(logtime_start); get_time_interval(logtime_start);
get_time_interval(t); 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 #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 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);
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", 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_TX(tti), (tti+4)%10240,
last_dl_pdcch_ncce, 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?"1":"0"):"no", 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[1]?"1":"0"):"no",
uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"", uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"",
uci_data.scheduling_request?"yes":"no", uci_data.scheduling_request?"yes":"no",
cfo*15000, timestr); cfo*15, timestr);
} }
if (uci_data.scheduling_request) { if (uci_data.scheduling_request) {
phy->sr_enabled = false; phy->sr_enabled = false;
@ -1002,7 +1002,7 @@ void phch_worker::encode_srs()
#ifdef LOG_EXECTIME #ifdef LOG_EXECTIME
gettimeofday(&logtime_start[2], NULL); gettimeofday(&logtime_start[2], NULL);
get_time_interval(logtime_start); 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 #endif
float tx_power = srslte_ue_ul_srs_power(&ue_ul, phy->pathloss); 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 */); 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); 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 */); nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); 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.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log);
rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str())); 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_; nas_log = nas_log_;
state = EMM_STATE_DEREGISTERED; state = EMM_STATE_DEREGISTERED;
plmn_selection = PLMN_NOT_SELECTED; plmn_selection = PLMN_NOT_SELECTED;
home_plmn.mcc = 61441; // This is 001
home_plmn.mnc = 65281; // This is 01 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_; cfg = cfg_;
} }
@ -64,6 +68,7 @@ emm_state_t nas::get_state() {
/******************************************************************************* /*******************************************************************************
UE interface UE interface
*******************************************************************************/ *******************************************************************************/
void nas::attach_request() { void nas::attach_request() {
nas_log->info("Attach Request\n"); nas_log->info("Attach Request\n");
if (state == EMM_STATE_DEREGISTERED) { if (state == EMM_STATE_DEREGISTERED) {
@ -72,7 +77,7 @@ void nas::attach_request() {
nas_log->info("Starting PLMN Search...\n"); nas_log->info("Starting PLMN Search...\n");
rrc->plmn_search(); rrc->plmn_search();
} else if (plmn_selection == PLMN_SELECTED) { } 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); rrc->plmn_select(current_plmn);
selecting_plmn = 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) { 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++) { 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) { 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) { 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); rrc->plmn_select(plmn_id);
selecting_plmn = plmn_id; selecting_plmn = plmn_id;
} }
return; 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); 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); tracking_area_code);
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
rrc->plmn_select(plmn_id); rrc->plmn_select(plmn_id);
selecting_plmn = 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() { bool nas::is_attached() {

@ -177,7 +177,7 @@ void rrc::run_thread() {
case RRC_STATE_PLMN_SELECTION: case RRC_STATE_PLMN_SELECTION:
plmn_select_timeout++; plmn_select_timeout++;
if (plmn_select_timeout >= RRC_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(); phy->cell_search_stop();
sleep(1); sleep(1);
rrc_log->console("\nRRC PLMN Search: timeout expired. Searching again\n"); 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; state = RRC_STATE_CELL_SELECTING;
select_cell_timeout = 0; select_cell_timeout = 0;
} else { } 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 // Sort cells according to RSRP
selected_plmn_id = plmn_id; 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) { if (!known_cells[i].has_valid_sib1) {
si_acquire_state = SI_ACQUIRE_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++) { 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); nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code);
} }
usleep(5000);
phy->cell_search_next();
} }
return; return;
} }
@ -454,6 +456,15 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) {
cell.earfcn, cell.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 "upper/usim.h"
#include "srslte/common/bcd_helpers.h"
using namespace srslte; using namespace srslte;
namespace srsue{ namespace srsue{
usim::usim() usim::usim() : initiated(false)
{} {}
void usim::init(usim_args_t *args, srslte::log *usim_log_) 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) { if("xor" == args->algo) {
auth_algo = auth_algo_xor; auth_algo = auth_algo_xor;
} }
initiated = true;
} }
void usim::stop() void usim::stop()
@ -102,6 +105,11 @@ void usim::stop()
void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) 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) if(NULL == imsi_ || n < 15)
{ {
usim_log->error("Invalid parameters to get_imsi_vec"); usim_log->error("Invalid parameters to get_imsi_vec");
@ -111,13 +119,18 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
uint64_t temp = imsi; uint64_t temp = imsi;
for(int i=14;i>=0;i--) for(int i=14;i>=0;i--)
{ {
imsi_[i] = temp % 10; imsi_[i] = temp % 10;
temp /= 10; temp /= 10;
} }
} }
void usim::get_imei_vec(uint8_t* imei_, 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) if(NULL == imei_ || n < 15)
{ {
usim_log->error("Invalid parameters to get_imei_vec"); usim_log->error("Invalid parameters to get_imei_vec");
@ -127,11 +140,53 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
uint64 temp = imei; uint64 temp = imei;
for(int i=14;i>=0;i--) for(int i=14;i>=0;i--)
{ {
imei_[i] = temp % 10; imei_[i] = temp % 10;
temp /= 10; temp /= 10;
} }
} }
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, void usim::generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,

Loading…
Cancel
Save