diff --git a/CHANGELOG b/CHANGELOG index 7dfff7d89..2acd0c4a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/README.md b/README.md index a6eada615..ad87ad149 100644 --- a/README.md +++ b/README.md @@ -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 ------------------ diff --git a/cmake/modules/SRSLTEVersion.cmake b/cmake/modules/SRSLTEVersion.cmake index d2ab204f5..b52e47fe5 100644 --- a/cmake/modules/SRSLTEVersion.cmake +++ b/cmake/modules/SRSLTEVersion.cmake @@ -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}") diff --git a/lib/include/srslte/common/bcd_helpers.h b/lib/include/srslte/common/bcd_helpers.h index 55411ae33..b696954c2 100644 --- a/lib/include/srslte/common/bcd_helpers.h +++ b/lib/include/srslte/common/bcd_helpers.h @@ -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); diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 9d3d56569..fd785fbca 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -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) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 2c29bd4d4..8561ba55c 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -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; }; diff --git a/lib/src/common/pdu_queue.cc b/lib/src/common/pdu_queue.cc index a1bf7cd59..6b4c8bfd9 100644 --- a/lib/src/common/pdu_queue.cc +++ b/lib/src/common/pdu_queue.cc @@ -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; diff --git a/lib/src/phy/phch/test/prach_test_usrp.c b/lib/src/phy/phch/test/prach_test_usrp.c index 2defdec4f..c0fae365c 100644 --- a/lib/src/phy/phch/test/prach_test_usrp.c +++ b/lib/src/phy/phch/test/prach_test_usrp.c @@ -231,7 +231,8 @@ 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); diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 00f157b6b..d41adbeed 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -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 }; diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 31649af69..fef533ffc 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -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); } @@ -348,7 +357,15 @@ double rf_soapy_set_rx_freq(void *h, double freq) printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); 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; } + + // 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, @@ -430,49 +464,92 @@ int rf_soapy_recv_with_time(void *h, int rf_soapy_send_timed(void *h, - void *data, - int nsamples, - time_t secs, - double frac_secs, - bool has_time_spec, - bool blocking, - bool is_start_of_burst, - bool is_end_of_burst) + void *data, + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + 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); +} + + +// 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) { - - int flags; - long long timeNs; - int trials = 0; - int ret = 0; - rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + 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; + 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); - int n = 0; + //printf("time_spec: secs=%d, frac_secs=%lf timeNs=%lld\n", secs, frac_secs, timeNs); + } - if(!handler->tx_stream_active){ - rf_soapy_start_tx_stream(h); + do { + 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; } diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 23b59a8b3..19de4536c 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -106,7 +106,7 @@ SRSLTE_API void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs); -SRSLTE_API int rf_soapy_send_timed(void *h, +SRSLTE_API int rf_soapy_send_timed(void *h, void *data, int nsamples, time_t secs, @@ -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); diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index d44df6348..b2697178c 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -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; diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 391eb8af6..d88b63bb7 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -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 diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index ab499efb0..21d60652d 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -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; diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 7f4042849..97b3b44fe 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -29,6 +29,7 @@ #include #include #include +#include #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 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; } diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 68d00ba06..e743165fb 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -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: diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 8dfa7f70d..3643f76c3 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -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 diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index bb4e394bd..fea15ba68 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -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 diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 60327fcd4..b54ea5be6 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -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) { diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 647226384..e10c013fe 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -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()); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index adeb41603..f89696015 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -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,23 +966,23 @@ 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, - 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); - } + 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*15, timestr); + } if (uci_data.scheduling_request) { phy->sr_enabled = false; @@ -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); diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 03e4b6546..92adaf8dd 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -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())); diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 91b35ce01..f0fd8cf54 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -50,8 +50,12 @@ void nas::init(usim_interface_nas *usim_, nas_log = nas_log_; state = EMM_STATE_DEREGISTERED; 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_; } @@ -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;iinfo("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() { diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 3bb3e0017..7b78bd774 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -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(); + } +} diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index 7b1f92896..9be69383e 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -25,13 +25,15 @@ */ +#include #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"); @@ -111,13 +119,18 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) uint64_t temp = imsi; for(int i=14;i>=0;i--) { - imsi_[i] = temp % 10; - temp /= 10; + imsi_[i] = temp % 10; + temp /= 10; } } 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"); @@ -127,11 +140,53 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n) uint64 temp = imei; for(int i=14;i>=0;i--) { - imei_[i] = temp % 10; - temp /= 10; + imei_[i] = 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;imcc); + 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,